From a3e64f3a67241d59e2af7cd43408f287b0135458 Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Wed, 12 Jul 2017 18:29:20 -0400 Subject: [PATCH 01/16] change name file to be consistent with the command name --- cmd/device-hub-cli/{cmd_pipe.go => cmd_start.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cmd/device-hub-cli/{cmd_pipe.go => cmd_start.go} (100%) diff --git a/cmd/device-hub-cli/cmd_pipe.go b/cmd/device-hub-cli/cmd_start.go similarity index 100% rename from cmd/device-hub-cli/cmd_pipe.go rename to cmd/device-hub-cli/cmd_start.go From 4d89f5e5c408a2325fbd6bde71914f860ee77337 Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Wed, 12 Jul 2017 22:25:32 -0400 Subject: [PATCH 02/16] add config file - add config file - naive approach --- cmd/device-hub-cli/cmd_start.go | 52 +++++++++++++++++++++++++++++--- examples/client_config/test.yaml | 5 +++ 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 examples/client_config/test.yaml diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index 54cefdc..57394bc 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -8,13 +8,29 @@ import ( "fmt" "strings" + "io/ioutil" + "log" + + "os" + "github.com/fiorix/protoc-gen-cobra/iocodec" "github.com/spf13/cobra" "github.com/thingful/device-hub/proto" + "gopkg.in/yaml.v2" ) func startCommand() *cobra.Command { + var configPath string + var configFile bool + type clientConfig struct { + URI string `yaml:"uri"` + Type string `yaml:"type"` + EndpointUIDs string `yaml:"endpoint-uid"` + ListenerUID string `yaml:"listener-uid"` + Tags []string `yaml:"tags"` + } + request := proto.StartRequest{ Endpoints: []string{}, Tags: map[string]string{}, @@ -59,11 +75,37 @@ func startCommand() *cobra.Command { }, } - startCommand.Flags().StringVarP(&request.Listener, "listener", "l", request.Listener, "listener uid to accept messages on") - startCommand.Flags().StringVarP(&request.Uri, "uri", "u", request.Uri, "uri to listen on") - startCommand.Flags().StringSliceVarP(&request.Endpoints, "endpoint", "e", request.Endpoints, "endpoint uid to push messages to, may be specified multiple times") - startCommand.Flags().StringSliceVarP(&tags, "tags", "t", tags, "colon separated (k:v) runtime tags to attach to requests, may be specified multiple times") - + startCommand.Flags().BoolVarP(&configFile, "config-file", "c", configFile, "enable config file feature") + startCommand.Flags().StringVar(&configPath, "config-path", configPath, "config file path with the required resources") + startCommand.ParseFlags(os.Args) + + // fmt.Println("configFile:", configFile) + // TODO check type + if configFile { + + readFields := clientConfig{} + + content, err := ioutil.ReadFile(configPath) + if err != nil { + log.Fatalf("Failed to read config file [%s]: %s\n", configPath, err.Error()) + } + err = yaml.Unmarshal(content, &readFields) + if err != nil { + log.Fatalf("Error parsing config file [%s]: %s\n", configPath, err.Error()) + } + fmt.Println(readFields) + request.Listener = readFields.ListenerUID + request.Uri = readFields.URI + // TODO Parse string slice + //request.Endpoints = readFields.EndpointUIDs + tags = readFields.Tags + + } else { + startCommand.Flags().StringVarP(&request.Listener, "listener", "l", request.Listener, "listener uid to accept messages on") + startCommand.Flags().StringVarP(&request.Uri, "uri", "u", request.Uri, "uri to listen on") + startCommand.Flags().StringSliceVarP(&request.Endpoints, "endpoint", "e", request.Endpoints, "endpoint uid to push messages to, may be specified multiple times") + startCommand.Flags().StringSliceVarP(&tags, "tags", "t", tags, "colon separated (k:v) runtime tags to attach to requests, may be specified multiple times") + } return startCommand } diff --git a/examples/client_config/test.yaml b/examples/client_config/test.yaml new file mode 100644 index 0000000..491acdc --- /dev/null +++ b/examples/client_config/test.yaml @@ -0,0 +1,5 @@ +uri: /a +type: process +endpoint-uids: stdout-endpoint +listener-uid: http-listener-local-port-8085 +tags: \ No newline at end of file From 1f645e40809c5df5f4b3127b3e91b536132bc80a Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Thu, 13 Jul 2017 07:36:58 -0400 Subject: [PATCH 03/16] fix endpoint field --- cmd/device-hub-cli/cmd_start.go | 5 ++--- examples/client_config/test.yaml | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index 57394bc..13884ba 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -26,7 +26,7 @@ func startCommand() *cobra.Command { type clientConfig struct { URI string `yaml:"uri"` Type string `yaml:"type"` - EndpointUIDs string `yaml:"endpoint-uid"` + EndpointUIDs []string `yaml:"endpoint-uids"` ListenerUID string `yaml:"listener-uid"` Tags []string `yaml:"tags"` } @@ -96,8 +96,7 @@ func startCommand() *cobra.Command { fmt.Println(readFields) request.Listener = readFields.ListenerUID request.Uri = readFields.URI - // TODO Parse string slice - //request.Endpoints = readFields.EndpointUIDs + request.Endpoints = readFields.EndpointUIDs tags = readFields.Tags } else { diff --git a/examples/client_config/test.yaml b/examples/client_config/test.yaml index 491acdc..61addeb 100644 --- a/examples/client_config/test.yaml +++ b/examples/client_config/test.yaml @@ -1,5 +1,6 @@ uri: /a type: process -endpoint-uids: stdout-endpoint +endpoint-uids: + - stdout-endpoint listener-uid: http-listener-local-port-8085 tags: \ No newline at end of file From 40e3735c81d9c2234683c19a608cbc61567ae2ac Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Thu, 13 Jul 2017 12:59:11 -0400 Subject: [PATCH 04/16] fix tag field - fix tag field - check type --- cmd/device-hub-cli/cmd_start.go | 13 +++++++------ examples/client_config/test.yaml | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index 13884ba..537745e 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -79,7 +79,6 @@ func startCommand() *cobra.Command { startCommand.Flags().StringVar(&configPath, "config-path", configPath, "config file path with the required resources") startCommand.ParseFlags(os.Args) - // fmt.Println("configFile:", configFile) // TODO check type if configFile { @@ -93,11 +92,13 @@ func startCommand() *cobra.Command { if err != nil { log.Fatalf("Error parsing config file [%s]: %s\n", configPath, err.Error()) } - fmt.Println(readFields) - request.Listener = readFields.ListenerUID - request.Uri = readFields.URI - request.Endpoints = readFields.EndpointUIDs - tags = readFields.Tags + // No sure about the name yet (process, pipe, etc.) + if readFields.Type == "process" { + request.Listener = readFields.ListenerUID + request.Uri = readFields.URI + request.Endpoints = readFields.EndpointUIDs + tags = readFields.Tags + } } else { startCommand.Flags().StringVarP(&request.Listener, "listener", "l", request.Listener, "listener uid to accept messages on") diff --git a/examples/client_config/test.yaml b/examples/client_config/test.yaml index 61addeb..41aa15d 100644 --- a/examples/client_config/test.yaml +++ b/examples/client_config/test.yaml @@ -3,4 +3,5 @@ type: process endpoint-uids: - stdout-endpoint listener-uid: http-listener-local-port-8085 -tags: \ No newline at end of file +tags: + - foo:bar \ No newline at end of file From 4c70933b4ea2a7e91fba1a8e9aafc42d7f4af055 Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Thu, 13 Jul 2017 13:05:09 -0400 Subject: [PATCH 05/16] changed type check on config file --- cmd/device-hub-cli/cmd_start.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index 537745e..f8abe25 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -93,12 +93,13 @@ func startCommand() *cobra.Command { log.Fatalf("Error parsing config file [%s]: %s\n", configPath, err.Error()) } // No sure about the name yet (process, pipe, etc.) - if readFields.Type == "process" { - request.Listener = readFields.ListenerUID - request.Uri = readFields.URI - request.Endpoints = readFields.EndpointUIDs - tags = readFields.Tags + if readFields.Type != "process" { + log.Fatal("Config file doesn't have the needed type") } + request.Listener = readFields.ListenerUID + request.Uri = readFields.URI + request.Endpoints = readFields.EndpointUIDs + tags = readFields.Tags } else { startCommand.Flags().StringVarP(&request.Listener, "listener", "l", request.Listener, "listener uid to accept messages on") From 95c7d68854180ee2996699f0c838e8b4cdc172ef Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Fri, 14 Jul 2017 22:05:09 -0400 Subject: [PATCH 06/16] use -f flag to load config file --- cmd/device-hub-cli/cmd_start.go | 67 ++++++++++++++------------------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index f8abe25..a33d20c 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -6,23 +6,18 @@ import ( "context" "errors" "fmt" - "strings" - "io/ioutil" - "log" + "strings" - "os" + yaml "gopkg.in/yaml.v2" "github.com/fiorix/protoc-gen-cobra/iocodec" "github.com/spf13/cobra" "github.com/thingful/device-hub/proto" - "gopkg.in/yaml.v2" ) func startCommand() *cobra.Command { - var configPath string - var configFile bool type clientConfig struct { URI string `yaml:"uri"` Type string `yaml:"type"` @@ -49,6 +44,27 @@ func startCommand() *cobra.Command { request.Profile = args[0] + if _config.RequestFile != "" { + + readFields := clientConfig{} + + content, err := ioutil.ReadFile(_config.RequestFile) + if err != nil { + return fmt.Errorf("failed to read file [%s]: %s", _config.RequestFile, err.Error()) + } + err = yaml.Unmarshal(content, &readFields) + if err != nil { + return fmt.Errorf("error parsing file [%s]: %s", _config.RequestFile, err.Error()) + } + // No sure about the name yet (process, pipe, etc.) + if readFields.Type != "process" { + return fmt.Errorf("file doesn't have the needed type") + } + request.Listener = readFields.ListenerUID + request.Uri = readFields.URI + request.Endpoints = readFields.EndpointUIDs + tags = readFields.Tags + } for _, m := range tags { bits := strings.Split(m, ":") @@ -75,38 +91,11 @@ func startCommand() *cobra.Command { }, } - startCommand.Flags().BoolVarP(&configFile, "config-file", "c", configFile, "enable config file feature") - startCommand.Flags().StringVar(&configPath, "config-path", configPath, "config file path with the required resources") - startCommand.ParseFlags(os.Args) - - // TODO check type - if configFile { - - readFields := clientConfig{} - - content, err := ioutil.ReadFile(configPath) - if err != nil { - log.Fatalf("Failed to read config file [%s]: %s\n", configPath, err.Error()) - } - err = yaml.Unmarshal(content, &readFields) - if err != nil { - log.Fatalf("Error parsing config file [%s]: %s\n", configPath, err.Error()) - } - // No sure about the name yet (process, pipe, etc.) - if readFields.Type != "process" { - log.Fatal("Config file doesn't have the needed type") - } - request.Listener = readFields.ListenerUID - request.Uri = readFields.URI - request.Endpoints = readFields.EndpointUIDs - tags = readFields.Tags - - } else { - startCommand.Flags().StringVarP(&request.Listener, "listener", "l", request.Listener, "listener uid to accept messages on") - startCommand.Flags().StringVarP(&request.Uri, "uri", "u", request.Uri, "uri to listen on") - startCommand.Flags().StringSliceVarP(&request.Endpoints, "endpoint", "e", request.Endpoints, "endpoint uid to push messages to, may be specified multiple times") - startCommand.Flags().StringSliceVarP(&tags, "tags", "t", tags, "colon separated (k:v) runtime tags to attach to requests, may be specified multiple times") - } + startCommand.Flags().StringVarP(&request.Listener, "listener", "l", request.Listener, "listener uid to accept messages on") + startCommand.Flags().StringVarP(&request.Uri, "uri", "u", request.Uri, "uri to listen on") + startCommand.Flags().StringSliceVarP(&request.Endpoints, "endpoint", "e", request.Endpoints, "endpoint uid to push messages to, may be specified multiple times") + startCommand.Flags().StringSliceVarP(&tags, "tags", "t", tags, "colon separated (k:v) runtime tags to attach to requests, may be specified multiple times") + return startCommand } From 5f92f11109efa97f135fc857b32285292a8da5b5 Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Mon, 17 Jul 2017 22:51:09 -0400 Subject: [PATCH 07/16] partial commit - Added feature start a "process" with a file - Added feature create all resources and start all processess into a folder -Added sample config files --- cmd/device-hub-cli/cmd_create.go | 9 +- cmd/device-hub-cli/cmd_delete.go | 2 +- cmd/device-hub-cli/cmd_show.go | 4 +- cmd/device-hub-cli/cmd_start.go | 129 ++++++++++-------- cmd/device-hub-cli/helpers.go | 109 ++++++++++++--- examples/config/helsinki_process.yaml | 8 ++ .../http_listener_process.yaml} | 3 +- 7 files changed, 180 insertions(+), 84 deletions(-) create mode 100644 examples/config/helsinki_process.yaml rename examples/{client_config/test.yaml => config/http_listener_process.yaml} (61%) diff --git a/cmd/device-hub-cli/cmd_create.go b/cmd/device-hub-cli/cmd_create.go index 5293891..249d299 100644 --- a/cmd/device-hub-cli/cmd_create.go +++ b/cmd/device-hub-cli/cmd_create.go @@ -25,7 +25,7 @@ var createCommand = &cobra.Command{ Configuration: map[string]string{}, } - err := roundTrip(sample, func(cli proto.HubClient, in iocodec.Decoder, out iocodec.Encoder) error { + err := roundTrip(sample, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { v := proto.CreateRequest{} @@ -49,6 +49,13 @@ var createCommand = &cobra.Command{ params, err = register.DescribeListener(v.Kind) case "endpoint": params, err = register.DescribeEndpoint(v.Kind) + case "process": + request := proto.StartRequest{ + Endpoints: []string{}, + Tags: map[string]string{}, + } + tags := []string{} + return startCall(args, request, tags, cli, in, out) } if err != nil { diff --git a/cmd/device-hub-cli/cmd_delete.go b/cmd/device-hub-cli/cmd_delete.go index 40aecbf..ab19b17 100644 --- a/cmd/device-hub-cli/cmd_delete.go +++ b/cmd/device-hub-cli/cmd_delete.go @@ -17,7 +17,7 @@ var deleteCommand = &cobra.Command{ sample := proto.DeleteRequest{} - err := roundTrip(sample, func(cli proto.HubClient, in iocodec.Decoder, out iocodec.Encoder) error { + err := roundTrip(sample, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { v := proto.DeleteRequest{} diff --git a/cmd/device-hub-cli/cmd_show.go b/cmd/device-hub-cli/cmd_show.go index 8f86b9c..4025112 100644 --- a/cmd/device-hub-cli/cmd_show.go +++ b/cmd/device-hub-cli/cmd_show.go @@ -20,10 +20,8 @@ var showCommand = &cobra.Command{ Filter: strings.Join(args, ","), } - err := roundTrip(v, func(cli proto.HubClient, in iocodec.Decoder, out iocodec.Encoder) error { - + err := roundTrip(v, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { resp, err := cli.Show(context.Background(), &v) - if err != nil { return err } diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index a33d20c..b3fb0d6 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -6,25 +6,23 @@ import ( "context" "errors" "fmt" - "io/ioutil" "strings" - yaml "gopkg.in/yaml.v2" - "github.com/fiorix/protoc-gen-cobra/iocodec" "github.com/spf13/cobra" "github.com/thingful/device-hub/proto" ) -func startCommand() *cobra.Command { +type clientConfig struct { + URI string `yaml:"uri"` + Type string `yaml:"type"` + EndpointUIDs []string `yaml:"endpoint-uids"` + ListenerUID string `yaml:"listener-uid"` + ProfileUID string `yaml:"profile-uid"` + Tags []string `yaml:"tags"` +} - type clientConfig struct { - URI string `yaml:"uri"` - Type string `yaml:"type"` - EndpointUIDs []string `yaml:"endpoint-uids"` - ListenerUID string `yaml:"listener-uid"` - Tags []string `yaml:"tags"` - } +func startCommand() *cobra.Command { request := proto.StartRequest{ Endpoints: []string{}, @@ -37,55 +35,18 @@ func startCommand() *cobra.Command { Use: "start", Short: "Start processing messages on a uri", RunE: func(cmd *cobra.Command, args []string) error { - - if len(args) == 0 { - return errors.New("specify a profile") + // if no profile is provided as arg, then the profile field in the yaml file + // will be loaded. + if len(args) > 0 { + request.Profile = args[0] } + err := roundTrip(request, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - request.Profile = args[0] - - if _config.RequestFile != "" { - - readFields := clientConfig{} - - content, err := ioutil.ReadFile(_config.RequestFile) - if err != nil { - return fmt.Errorf("failed to read file [%s]: %s", _config.RequestFile, err.Error()) - } - err = yaml.Unmarshal(content, &readFields) - if err != nil { - return fmt.Errorf("error parsing file [%s]: %s", _config.RequestFile, err.Error()) - } - // No sure about the name yet (process, pipe, etc.) - if readFields.Type != "process" { - return fmt.Errorf("file doesn't have the needed type") - } - request.Listener = readFields.ListenerUID - request.Uri = readFields.URI - request.Endpoints = readFields.EndpointUIDs - tags = readFields.Tags - } - for _, m := range tags { - - bits := strings.Split(m, ":") - - if len(bits) != 2 { - return fmt.Errorf("metadata not colon (:) separated : %s", m) - } - - request.Tags[bits[0]] = bits[1] - } - - err := roundTrip(request, func(cli proto.HubClient, in iocodec.Decoder, out iocodec.Encoder) error { - - resp, err := cli.Start(context.Background(), &request) - + err := startCall(args, request, tags, cli, in, out) if err != nil { return err } - - return out.Encode(resp) - + return nil }) return err }, @@ -99,6 +60,60 @@ func startCommand() *cobra.Command { return startCommand } +func startCall(args []string, request proto.StartRequest, tags []string, cli proto.HubClient, in rawConf, out iocodec.Encoder) error { + + cfg := clientConfig{} + + if _config.RequestFile == "" { + err := in.Decode(&cfg) + if err != nil { + return err + } + } else { + err := yamlDecoder(_config.RequestFile, &cfg) + if err != nil { + return err + } + } + + // No sure about the name yet (process, pipe, etc.) + if cfg.Type != "process" { + return fmt.Errorf("file doesn't have the needed type [%v]", cfg.Type) + } + + if request.Profile == "" { + request.Profile = cfg.ProfileUID + } + + request.Uri = cfg.URI + request.Listener = cfg.ListenerUID + request.Endpoints = cfg.EndpointUIDs + + if request.Profile == "" { + return errors.New("no profile specified") + } + // review tags + tags = cfg.Tags + for _, m := range tags { + + bits := strings.Split(m, ":") + + if len(bits) != 2 { + return fmt.Errorf("metadata not colon (:) separated : %s", m) + } + + request.Tags[bits[0]] = bits[1] + } + + resp, err := cli.Start(context.Background(), &request) + + if err != nil { + return err + } + + return out.Encode(resp) +} + var stopCommand = &cobra.Command{ Use: "stop", Short: "Stop processing messages on a uri", @@ -106,7 +121,7 @@ var stopCommand = &cobra.Command{ v := proto.StopRequest{} - err := roundTrip(v, func(cli proto.HubClient, in iocodec.Decoder, out iocodec.Encoder) error { + err := roundTrip(v, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { if len(args) == 0 { return errors.New("specify a uri to stop") } @@ -133,7 +148,7 @@ var statusCommand = &cobra.Command{ v := proto.StatusRequest{} - err := roundTrip(v, func(cli proto.HubClient, in iocodec.Decoder, out iocodec.Encoder) error { + err := roundTrip(v, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { resp, err := cli.Status(context.Background(), &v) diff --git a/cmd/device-hub-cli/helpers.go b/cmd/device-hub-cli/helpers.go index ceb2d41..3d0268e 100644 --- a/cmd/device-hub-cli/helpers.go +++ b/cmd/device-hub-cli/helpers.go @@ -11,6 +11,9 @@ import ( "os" "path" "path/filepath" + "sort" + + yaml "gopkg.in/yaml.v2" "github.com/fiorix/protoc-gen-cobra/iocodec" "github.com/thingful/device-hub/proto" @@ -108,7 +111,64 @@ func dial() (*grpc.ClientConn, proto.HubClient, error) { return conn, proto.NewHubClient(conn), nil } -type roundTripFunc func(cli proto.HubClient, in iocodec.Decoder, out iocodec.Encoder) error +type rawConf []byte + +func (r rawConf) Decode(target interface{}) error { + err := yaml.Unmarshal(r, target) + if err != nil { + return fmt.Errorf("error decoding data: %s", err.Error()) + } + return nil +} + +// Represent a conf file, Data is basically used to order a cliConf Slice +// Raw contains the file content +type cliConf struct { + Data map[string]interface{} + Raw rawConf +} + +// Load the configuration file to Data +func (c *cliConf) Load(filePath string) (err error) { + + c.Raw, err = ioutil.ReadFile(filePath) + if err != nil { + return fmt.Errorf("failed to read file [%s]: %s", filePath, err.Error()) + } + err = yaml.Unmarshal(c.Raw, &c.Data) + if err != nil { + return fmt.Errorf("error parsing file [%s]: %s", filePath, err.Error()) + } + return nil +} + +type cliConfSlice struct { + C []cliConf +} + +func (c *cliConfSlice) Append(e cliConf) { + + c.C = append(c.C, e) +} +func (c cliConfSlice) Len() int { + return len(c.C) +} +func (c cliConfSlice) Less(i, j int) bool { + if c.C[j].Data["type"] == "process" { + return true + } + return false +} +func (c cliConfSlice) Swap(i, j int) { + c.C[i], c.C[j] = c.C[j], c.C[i] +} +func (c cliConfSlice) Print() { + for k, v := range c.C { + fmt.Println(k, v.Data) + } +} + +type roundTripFunc func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error func roundTrip(sample interface{}, fn roundTripFunc) error { cfg := _config @@ -130,24 +190,23 @@ func roundTrip(sample interface{}, fn roundTripFunc) error { return em.NewEncoder(os.Stdout).Encode(sample) } - decoders := []iocodec.Decoder{} - files := []*os.File{} + var dataSlice cliConfSlice // either no request file is not specified or set to std-in if (cfg.RequestFile == "" && cfg.RequestDir == "") || cfg.RequestFile == "-" { - decoders = append(decoders, iocodec.DefaultDecoders["json"].NewDecoder(os.Stdin)) - + // Add empty item to iterate - TODO refactor + dataSlice.Append(cliConf{}) // or request file is specified } else if cfg.RequestFile != "" { - f, d, err := decoderFromPath(cfg.RequestFile) + var data cliConf + err := data.Load(cfg.RequestFile) if err != nil { return err } - decoders = append(decoders, d) - files = append(files, f) + dataSlice.Append(data) // or request dir is specified } else if cfg.RequestDir != "" { @@ -162,24 +221,16 @@ func roundTrip(sample interface{}, fn roundTripFunc) error { fmt.Println(fi.Name()) folderPath := path.Join(cfg.RequestDir, fi.Name()) - f, d, err := decoderFromPath(folderPath) + var data cliConf + err = data.Load(folderPath) if err != nil { return err } - - decoders = append(decoders, d) - files = append(files, f) - + dataSlice.Append(data) } } - defer func() { - for i, _ := range files { - files[i].Close() - } - }() - conn, client, err := dial() if err != nil { return err @@ -187,8 +238,11 @@ func roundTrip(sample interface{}, fn roundTripFunc) error { defer conn.Close() - for _, d := range decoders { - err := fn(client, d, em.NewEncoder(os.Stdout)) + // sort slice moving the processes to the end + sort.Sort(cliConfSlice(dataSlice)) + + for _, d := range dataSlice.C { + err := fn(client, d.Raw, em.NewEncoder(os.Stdout)) if err != nil { return err @@ -219,3 +273,16 @@ func decoderFromPath(filePath string) (*os.File, iocodec.Decoder, error) { return f, dm.NewDecoder(f), nil } + +func yamlDecoder(filePath string, target interface{}) error { + + data, err := ioutil.ReadFile(filePath) + if err != nil { + return fmt.Errorf("failed to read file [%s]: %s", filePath, err.Error()) + } + err = yaml.Unmarshal(data, target) + if err != nil { + return fmt.Errorf("error parsing file [%s]: %s", filePath, err.Error()) + } + return nil +} diff --git a/examples/config/helsinki_process.yaml b/examples/config/helsinki_process.yaml new file mode 100644 index 0000000..57906d7 --- /dev/null +++ b/examples/config/helsinki_process.yaml @@ -0,0 +1,8 @@ +uri: /b +type: process +endpoint-uids: + - stdout-endpoint +listener-uid: mqtt-helsinki-transport-service-listener +profile-uid: thingful/helsinki-bus +tags: + - foo:bar \ No newline at end of file diff --git a/examples/client_config/test.yaml b/examples/config/http_listener_process.yaml similarity index 61% rename from examples/client_config/test.yaml rename to examples/config/http_listener_process.yaml index 41aa15d..e437d57 100644 --- a/examples/client_config/test.yaml +++ b/examples/config/http_listener_process.yaml @@ -1,7 +1,8 @@ uri: /a type: process endpoint-uids: - - stdout-endpoint + - http-endpoint-example.com listener-uid: http-listener-local-port-8085 +profile-uid: thingful/device-1 tags: - foo:bar \ No newline at end of file From a4e8e7deb0fffb1b9524d7f766f2675135fc211e Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Mon, 17 Jul 2017 23:03:59 -0400 Subject: [PATCH 08/16] fix config integration test --- examples/config_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/config_test.go b/examples/config_test.go index 2bbfb56..5cb9efc 100644 --- a/examples/config_test.go +++ b/examples/config_test.go @@ -49,9 +49,12 @@ func TestConfigurationFilesAreValid(t *testing.T) { err = in.Decode(&entity) assert.Nil(t, err) - assert.NotEmpty(t, entity.Kind) assert.NotEmpty(t, entity.Type) + if strings.ToLower(entity.Type) != "process" { + assert.NotEmpty(t, entity.Kind) + } + var params describe.Parameters switch strings.ToLower(entity.Type) { From 129a1d6fc88f91afaeaf4d8f61b6f8c580e9f06e Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Tue, 18 Jul 2017 00:27:37 -0400 Subject: [PATCH 09/16] added feature "delete" resources files and stop "processes" with -d flag --- cmd/device-hub-cli/cmd_create.go | 2 +- cmd/device-hub-cli/cmd_delete.go | 15 +++++++++++- cmd/device-hub-cli/cmd_show.go | 2 +- cmd/device-hub-cli/cmd_start.go | 39 ++++++++++++++++++++------------ cmd/device-hub-cli/helpers.go | 13 +++++++---- 5 files changed, 48 insertions(+), 23 deletions(-) diff --git a/cmd/device-hub-cli/cmd_create.go b/cmd/device-hub-cli/cmd_create.go index 249d299..7fe4ad3 100644 --- a/cmd/device-hub-cli/cmd_create.go +++ b/cmd/device-hub-cli/cmd_create.go @@ -25,7 +25,7 @@ var createCommand = &cobra.Command{ Configuration: map[string]string{}, } - err := roundTrip(sample, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { + err := roundTrip(sample, "create", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { v := proto.CreateRequest{} diff --git a/cmd/device-hub-cli/cmd_delete.go b/cmd/device-hub-cli/cmd_delete.go index ab19b17..248914f 100644 --- a/cmd/device-hub-cli/cmd_delete.go +++ b/cmd/device-hub-cli/cmd_delete.go @@ -17,7 +17,7 @@ var deleteCommand = &cobra.Command{ sample := proto.DeleteRequest{} - err := roundTrip(sample, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { + err := roundTrip(sample, "delete", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { v := proto.DeleteRequest{} @@ -26,6 +26,19 @@ var deleteCommand = &cobra.Command{ return err } + if v.Type == "process" { + + req := proto.StopRequest{} + + err := in.Decode(&req) + if err != nil { + return err + } + + return stopCall(args, req, cli, in, out) + + } + resp, err := cli.Delete(context.Background(), &v) if err != nil { diff --git a/cmd/device-hub-cli/cmd_show.go b/cmd/device-hub-cli/cmd_show.go index 4025112..2fc480e 100644 --- a/cmd/device-hub-cli/cmd_show.go +++ b/cmd/device-hub-cli/cmd_show.go @@ -20,7 +20,7 @@ var showCommand = &cobra.Command{ Filter: strings.Join(args, ","), } - err := roundTrip(v, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { + err := roundTrip(v, "show", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { resp, err := cli.Show(context.Background(), &v) if err != nil { return err diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index b3fb0d6..139413c 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -40,7 +40,7 @@ func startCommand() *cobra.Command { if len(args) > 0 { request.Profile = args[0] } - err := roundTrip(request, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { + err := roundTrip(request, "start", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { err := startCall(args, request, tags, cli, in, out) if err != nil { @@ -121,24 +121,33 @@ var stopCommand = &cobra.Command{ v := proto.StopRequest{} - err := roundTrip(v, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - if len(args) == 0 { - return errors.New("specify a uri to stop") - } - - v.Uri = strings.TrimSpace(args[0]) + err := roundTrip(v, "stop", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { + return stopCall(args, v, cli, in, out) + }) + return err + }, +} - resp, err := cli.Stop(context.Background(), &v) +func stopCall(args []string, request proto.StopRequest, cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - if err != nil { - return err - } + err := in.Decode(&request) + if err != nil { + return err + } + if len(args) == 0 && request.Uri == "" { + return errors.New("specify a uri to stop") + } + if len(args) > 0 { + request.Uri = strings.TrimSpace(args[0]) + } - return out.Encode(resp) + resp, err := cli.Stop(context.Background(), &request) - }) + if err != nil { return err - }, + } + + return out.Encode(resp) } var statusCommand = &cobra.Command{ @@ -148,7 +157,7 @@ var statusCommand = &cobra.Command{ v := proto.StatusRequest{} - err := roundTrip(v, func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { + err := roundTrip(v, "status", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { resp, err := cli.Status(context.Background(), &v) diff --git a/cmd/device-hub-cli/helpers.go b/cmd/device-hub-cli/helpers.go index 3d0268e..9fd2318 100644 --- a/cmd/device-hub-cli/helpers.go +++ b/cmd/device-hub-cli/helpers.go @@ -170,7 +170,7 @@ func (c cliConfSlice) Print() { type roundTripFunc func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error -func roundTrip(sample interface{}, fn roundTripFunc) error { +func roundTrip(sample interface{}, caller string, fn roundTripFunc) error { cfg := _config var em iocodec.EncoderMaker @@ -235,11 +235,14 @@ func roundTrip(sample interface{}, fn roundTripFunc) error { if err != nil { return err } - defer conn.Close() - - // sort slice moving the processes to the end - sort.Sort(cliConfSlice(dataSlice)) + // sort the config items to create & delete cases + switch caller { + case "create": + sort.Sort(cliConfSlice(dataSlice)) + case "delete": + sort.Sort(sort.Reverse(cliConfSlice(dataSlice))) + } for _, d := range dataSlice.C { err := fn(client, d.Raw, em.NewEncoder(os.Stdout)) From 02947df0f2113961834f8b411dcace308682c4f6 Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Tue, 18 Jul 2017 18:23:37 -0400 Subject: [PATCH 10/16] little fixes --- cmd/device-hub-cli/cmd_start.go | 7 +------ cmd/device-hub-cli/helpers.go | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index 139413c..5d2e4c6 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -41,12 +41,7 @@ func startCommand() *cobra.Command { request.Profile = args[0] } err := roundTrip(request, "start", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - - err := startCall(args, request, tags, cli, in, out) - if err != nil { - return err - } - return nil + return startCall(args, request, tags, cli, in, out) }) return err }, diff --git a/cmd/device-hub-cli/helpers.go b/cmd/device-hub-cli/helpers.go index 9fd2318..fac74a8 100644 --- a/cmd/device-hub-cli/helpers.go +++ b/cmd/device-hub-cli/helpers.go @@ -142,6 +142,8 @@ func (c *cliConf) Load(filePath string) (err error) { return nil } +// cliConfSlice contains configs and implements sort interface using +// "process" type file as the less weight type cliConfSlice struct { C []cliConf } @@ -150,18 +152,32 @@ func (c *cliConfSlice) Append(e cliConf) { c.C = append(c.C, e) } + func (c cliConfSlice) Len() int { return len(c.C) } + func (c cliConfSlice) Less(i, j int) bool { if c.C[j].Data["type"] == "process" { return true } return false } + func (c cliConfSlice) Swap(i, j int) { c.C[i], c.C[j] = c.C[j], c.C[i] } + +// Sort is required to put processes at the end when executing create cmd +func (c cliConfSlice) Sort() { + sort.Sort(cliConfSlice(c)) +} + +// Reverse is required to put processes at first to stop them before delete resources +func (c cliConfSlice) Reverse() { + sort.Sort(sort.Reverse(cliConfSlice(c))) +} + func (c cliConfSlice) Print() { for k, v := range c.C { fmt.Println(k, v.Data) @@ -236,12 +252,12 @@ func roundTrip(sample interface{}, caller string, fn roundTripFunc) error { return err } defer conn.Close() - // sort the config items to create & delete cases + // sort the config items for both create & delete cases switch caller { case "create": - sort.Sort(cliConfSlice(dataSlice)) + dataSlice.Sort() case "delete": - sort.Sort(sort.Reverse(cliConfSlice(dataSlice))) + dataSlice.Reverse() } for _, d := range dataSlice.C { From 8c2b09f8fa96551ea4d2f90c744f3812469f38e9 Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Tue, 18 Jul 2017 22:47:54 -0400 Subject: [PATCH 11/16] add aditional functionality to cliConfSlice --- cmd/device-hub-cli/helpers.go | 44 +++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/cmd/device-hub-cli/helpers.go b/cmd/device-hub-cli/helpers.go index fac74a8..a0c3b96 100644 --- a/cmd/device-hub-cli/helpers.go +++ b/cmd/device-hub-cli/helpers.go @@ -124,8 +124,9 @@ func (r rawConf) Decode(target interface{}) error { // Represent a conf file, Data is basically used to order a cliConf Slice // Raw contains the file content type cliConf struct { - Data map[string]interface{} - Raw rawConf + FileName string + Data map[string]interface{} + Raw rawConf } // Load the configuration file to Data @@ -135,6 +136,10 @@ func (c *cliConf) Load(filePath string) (err error) { if err != nil { return fmt.Errorf("failed to read file [%s]: %s", filePath, err.Error()) } + + _, fileName := filepath.Split(filePath) + c.FileName = fileName + err = yaml.Unmarshal(c.Raw, &c.Data) if err != nil { return fmt.Errorf("error parsing file [%s]: %s", filePath, err.Error()) @@ -179,9 +184,40 @@ func (c cliConfSlice) Reverse() { } func (c cliConfSlice) Print() { - for k, v := range c.C { - fmt.Println(k, v.Data) + for _, v := range c.C { + fmt.Println(v.FileName) + } +} + +// GetCliConfig get config for this CLI app +func (c cliConfSlice) GetCliConfig(cfg *config) error { + var conf cliConf + if cfg.RequestFile != "" { + err := conf.Load(cfg.RequestFile) + if err != nil { + return err + } + c.Append(conf) + return nil + } else if _config.RequestDir != "" { + listing, err := ioutil.ReadDir(_config.RequestDir) + if err != nil { + return err + } + for _, f := range listing { + folderPath := path.Join(cfg.RequestDir, f.Name()) + var _conf cliConf // check if this could be outer scoped! (conf) + err = _conf.Load(folderPath) + if err != nil { + return err + } + c.Append(_conf) + } } + // Sorted with process to the end by default + c.Sort() + c.Print() + return nil } type roundTripFunc func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error From cc54c2ad60bc21df3cac33a8c4a18748b808a62e Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Fri, 21 Jul 2017 00:30:23 -0400 Subject: [PATCH 12/16] candidate changes --- cmd/device-hub-cli/cmd_create.go | 64 +------- cmd/device-hub-cli/cmd_delete.go | 45 ++---- cmd/device-hub-cli/cmd_show.go | 13 +- cmd/device-hub-cli/cmd_start.go | 135 ++++------------- cmd/device-hub-cli/helpers.go | 212 +------------------------- cmd/device-hub-cli/main.go | 14 +- cmd/device-hub-cli/resource.go | 246 +++++++++++++++++++++++++++++++ 7 files changed, 307 insertions(+), 422 deletions(-) create mode 100644 cmd/device-hub-cli/resource.go diff --git a/cmd/device-hub-cli/cmd_create.go b/cmd/device-hub-cli/cmd_create.go index 7fe4ad3..ac2f9ec 100644 --- a/cmd/device-hub-cli/cmd_create.go +++ b/cmd/device-hub-cli/cmd_create.go @@ -3,16 +3,7 @@ package main import ( - "context" - "strings" - - "github.com/fiorix/protoc-gen-cobra/iocodec" "github.com/spf13/cobra" - "github.com/thingful/device-hub/describe" - "github.com/thingful/device-hub/endpoint" - "github.com/thingful/device-hub/listener" - "github.com/thingful/device-hub/proto" - "github.com/thingful/device-hub/registry" ) var createCommand = &cobra.Command{ @@ -20,62 +11,15 @@ var createCommand = &cobra.Command{ Short: "Create listener, endpoint and profile resources", RunE: func(cmd *cobra.Command, args []string) error { - /* TODO : add ability to generate examples */ - sample := proto.CreateRequest{ - Configuration: map[string]string{}, - } - - err := roundTrip(sample, "create", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - - v := proto.CreateRequest{} - - err := in.Decode(&v) + for _, r := range _resources.R { + err := r.SendCreate(args) if err != nil { return err } - // validate the policy file before sending it over the wire - var params describe.Parameters - - register := registry.Default - - endpoint.Register(register) - listener.Register(register) - - switch strings.ToLower(v.Type) { - - case "listener": - params, err = register.DescribeListener(v.Kind) - case "endpoint": - params, err = register.DescribeEndpoint(v.Kind) - case "process": - request := proto.StartRequest{ - Endpoints: []string{}, - Tags: map[string]string{}, - } - tags := []string{} - return startCall(args, request, tags, cli, in, out) - } - - if err != nil { - return err - } - - _, err = describe.NewValues(v.Configuration, params) - - if err != nil { - return err - } - resp, err := cli.Create(context.Background(), &v) - - if err != nil { - return err - } - - return out.Encode(resp) + } - }) - return err + return nil }, } diff --git a/cmd/device-hub-cli/cmd_delete.go b/cmd/device-hub-cli/cmd_delete.go index 248914f..854a2c2 100644 --- a/cmd/device-hub-cli/cmd_delete.go +++ b/cmd/device-hub-cli/cmd_delete.go @@ -3,53 +3,26 @@ package main import ( - "context" - - "github.com/fiorix/protoc-gen-cobra/iocodec" "github.com/spf13/cobra" - "github.com/thingful/device-hub/proto" ) var deleteCommand = &cobra.Command{ Use: "delete", Short: "Delete listener, profile and endpoint resources", RunE: func(cmd *cobra.Command, args []string) error { + var uri string + if len(args) > 0 { + uri = args[0] + } - sample := proto.DeleteRequest{} - - err := roundTrip(sample, "delete", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - - v := proto.DeleteRequest{} - - err := in.Decode(&v) - if err != nil { - return err - } - - if v.Type == "process" { - - req := proto.StopRequest{} - - err := in.Decode(&req) - if err != nil { - return err - } - - return stopCall(args, req, cli, in, out) - - } - - resp, err := cli.Delete(context.Background(), &v) + _resources.Reverse() + for _, r := range _resources.R { + err := r.SendDelete(uri) if err != nil { return err } - - return out.Encode(resp) - - }) - - return err - + } + return nil }, } diff --git a/cmd/device-hub-cli/cmd_show.go b/cmd/device-hub-cli/cmd_show.go index 2fc480e..5b27ef1 100644 --- a/cmd/device-hub-cli/cmd_show.go +++ b/cmd/device-hub-cli/cmd_show.go @@ -16,18 +16,15 @@ var showCommand = &cobra.Command{ Short: "Display one or many resources", RunE: func(cmd *cobra.Command, args []string) error { - v := proto.ShowRequest{ - Filter: strings.Join(args, ","), - } - - err := roundTrip(v, "show", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - resp, err := cli.Show(context.Background(), &v) + err := roundTrip(func(cli proto.HubClient, in rawContent, out iocodec.Encoder) error { + req := proto.ShowRequest{ + Filter: strings.Join(args, ","), + } + resp, err := cli.Show(context.Background(), &req) if err != nil { return err } - return out.Encode(resp) - }) return err diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index 5d2e4c6..991b522 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -5,144 +5,65 @@ package main import ( "context" "errors" - "fmt" - "strings" "github.com/fiorix/protoc-gen-cobra/iocodec" "github.com/spf13/cobra" "github.com/thingful/device-hub/proto" ) -type clientConfig struct { - URI string `yaml:"uri"` - Type string `yaml:"type"` - EndpointUIDs []string `yaml:"endpoint-uids"` - ListenerUID string `yaml:"listener-uid"` - ProfileUID string `yaml:"profile-uid"` - Tags []string `yaml:"tags"` -} - func startCommand() *cobra.Command { - request := proto.StartRequest{ - Endpoints: []string{}, - Tags: map[string]string{}, - } - - tags := []string{} - startCommand := &cobra.Command{ Use: "start", Short: "Start processing messages on a uri", RunE: func(cmd *cobra.Command, args []string) error { - // if no profile is provided as arg, then the profile field in the yaml file - // will be loaded. - if len(args) > 0 { - request.Profile = args[0] + if len(_resources.R) == 0 { + return errors.New("no resource has been set") } - err := roundTrip(request, "start", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - return startCall(args, request, tags, cli, in, out) - }) - return err + err := _resources.R[0].SendCreate(args) + if err != nil { + return err + } + + return nil }, } - startCommand.Flags().StringVarP(&request.Listener, "listener", "l", request.Listener, "listener uid to accept messages on") - startCommand.Flags().StringVarP(&request.Uri, "uri", "u", request.Uri, "uri to listen on") - startCommand.Flags().StringSliceVarP(&request.Endpoints, "endpoint", "e", request.Endpoints, "endpoint uid to push messages to, may be specified multiple times") - startCommand.Flags().StringSliceVarP(&tags, "tags", "t", tags, "colon separated (k:v) runtime tags to attach to requests, may be specified multiple times") + startCommand.Flags().StringVarP(&_config.ProcessConf.ListenerUID, "listener", "l", _config.ProcessConf.ListenerUID, "listener uid to accept messages on") + startCommand.Flags().StringVarP(&_config.ProcessConf.URI, "uri", "u", _config.ProcessConf.URI, "uri to listen on") + startCommand.Flags().StringSliceVarP(&_config.ProcessConf.EndpointUIDs, "endpoint", "e", _config.ProcessConf.EndpointUIDs, "endpoint uid to push messages to, may be specified multiple times") + startCommand.Flags().StringSliceVarP(&_config.ProcessConf.Tags, "tags", "t", _config.ProcessConf.Tags, "colon separated (k:v) runtime tags to attach to requests, may be specified multiple times") return startCommand } -func startCall(args []string, request proto.StartRequest, tags []string, cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - - cfg := clientConfig{} - - if _config.RequestFile == "" { - err := in.Decode(&cfg) - if err != nil { - return err - } - } else { - err := yamlDecoder(_config.RequestFile, &cfg) - if err != nil { - return err - } - } - - // No sure about the name yet (process, pipe, etc.) - if cfg.Type != "process" { - return fmt.Errorf("file doesn't have the needed type [%v]", cfg.Type) - } - - if request.Profile == "" { - request.Profile = cfg.ProfileUID - } - - request.Uri = cfg.URI - request.Listener = cfg.ListenerUID - request.Endpoints = cfg.EndpointUIDs - - if request.Profile == "" { - return errors.New("no profile specified") - } - // review tags - tags = cfg.Tags - for _, m := range tags { - - bits := strings.Split(m, ":") - - if len(bits) != 2 { - return fmt.Errorf("metadata not colon (:) separated : %s", m) - } - - request.Tags[bits[0]] = bits[1] - } - - resp, err := cli.Start(context.Background(), &request) - - if err != nil { - return err - } - - return out.Encode(resp) -} - var stopCommand = &cobra.Command{ Use: "stop", Short: "Stop processing messages on a uri", RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return errors.New("specify a uri to stop") + } - v := proto.StopRequest{} - - err := roundTrip(v, "stop", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - return stopCall(args, v, cli, in, out) + err := roundTrip(func(client proto.HubClient, in rawContent, out iocodec.Encoder) error { + return stopCall(args[0], client, in, out) }) + return err }, } -func stopCall(args []string, request proto.StopRequest, cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - - err := in.Decode(&request) - if err != nil { - return err +func stopCall(uri string, client proto.HubClient, in rawContent, out iocodec.Encoder) error { + req := proto.StopRequest{ + Uri: uri, } - if len(args) == 0 && request.Uri == "" { - return errors.New("specify a uri to stop") - } - if len(args) > 0 { - request.Uri = strings.TrimSpace(args[0]) - } - - resp, err := cli.Stop(context.Background(), &request) + resp, err := client.Stop(context.Background(), &req) if err != nil { return err } - return out.Encode(resp) + } var statusCommand = &cobra.Command{ @@ -150,18 +71,14 @@ var statusCommand = &cobra.Command{ Short: "List running pipes", RunE: func(cmd *cobra.Command, args []string) error { - v := proto.StatusRequest{} - - err := roundTrip(v, "status", func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error { - - resp, err := cli.Status(context.Background(), &v) + err := roundTrip(func(client proto.HubClient, in rawContent, out iocodec.Encoder) error { + req := proto.StatusRequest{} + resp, err := client.Status(context.Background(), &req) if err != nil { return err } - return out.Encode(resp) - }) return err }, diff --git a/cmd/device-hub-cli/helpers.go b/cmd/device-hub-cli/helpers.go index a0c3b96..f397f13 100644 --- a/cmd/device-hub-cli/helpers.go +++ b/cmd/device-hub-cli/helpers.go @@ -9,11 +9,6 @@ import ( "io/ioutil" "net" "os" - "path" - "path/filepath" - "sort" - - yaml "gopkg.in/yaml.v2" "github.com/fiorix/protoc-gen-cobra/iocodec" "github.com/thingful/device-hub/proto" @@ -111,118 +106,9 @@ func dial() (*grpc.ClientConn, proto.HubClient, error) { return conn, proto.NewHubClient(conn), nil } -type rawConf []byte - -func (r rawConf) Decode(target interface{}) error { - err := yaml.Unmarshal(r, target) - if err != nil { - return fmt.Errorf("error decoding data: %s", err.Error()) - } - return nil -} - -// Represent a conf file, Data is basically used to order a cliConf Slice -// Raw contains the file content -type cliConf struct { - FileName string - Data map[string]interface{} - Raw rawConf -} - -// Load the configuration file to Data -func (c *cliConf) Load(filePath string) (err error) { - - c.Raw, err = ioutil.ReadFile(filePath) - if err != nil { - return fmt.Errorf("failed to read file [%s]: %s", filePath, err.Error()) - } - - _, fileName := filepath.Split(filePath) - c.FileName = fileName - - err = yaml.Unmarshal(c.Raw, &c.Data) - if err != nil { - return fmt.Errorf("error parsing file [%s]: %s", filePath, err.Error()) - } - return nil -} - -// cliConfSlice contains configs and implements sort interface using -// "process" type file as the less weight -type cliConfSlice struct { - C []cliConf -} - -func (c *cliConfSlice) Append(e cliConf) { - - c.C = append(c.C, e) -} - -func (c cliConfSlice) Len() int { - return len(c.C) -} - -func (c cliConfSlice) Less(i, j int) bool { - if c.C[j].Data["type"] == "process" { - return true - } - return false -} - -func (c cliConfSlice) Swap(i, j int) { - c.C[i], c.C[j] = c.C[j], c.C[i] -} - -// Sort is required to put processes at the end when executing create cmd -func (c cliConfSlice) Sort() { - sort.Sort(cliConfSlice(c)) -} - -// Reverse is required to put processes at first to stop them before delete resources -func (c cliConfSlice) Reverse() { - sort.Sort(sort.Reverse(cliConfSlice(c))) -} - -func (c cliConfSlice) Print() { - for _, v := range c.C { - fmt.Println(v.FileName) - } -} - -// GetCliConfig get config for this CLI app -func (c cliConfSlice) GetCliConfig(cfg *config) error { - var conf cliConf - if cfg.RequestFile != "" { - err := conf.Load(cfg.RequestFile) - if err != nil { - return err - } - c.Append(conf) - return nil - } else if _config.RequestDir != "" { - listing, err := ioutil.ReadDir(_config.RequestDir) - if err != nil { - return err - } - for _, f := range listing { - folderPath := path.Join(cfg.RequestDir, f.Name()) - var _conf cliConf // check if this could be outer scoped! (conf) - err = _conf.Load(folderPath) - if err != nil { - return err - } - c.Append(_conf) - } - } - // Sorted with process to the end by default - c.Sort() - c.Print() - return nil -} - -type roundTripFunc func(cli proto.HubClient, in rawConf, out iocodec.Encoder) error +type roundTripFunc func(cli proto.HubClient, in rawContent, out iocodec.Encoder) error -func roundTrip(sample interface{}, caller string, fn roundTripFunc) error { +func roundTrip(fn roundTripFunc) error { cfg := _config var em iocodec.EncoderMaker @@ -238,106 +124,16 @@ func roundTrip(sample interface{}, caller string, fn roundTripFunc) error { } } - if cfg.PrintSampleRequest { - return em.NewEncoder(os.Stdout).Encode(sample) - } - - var dataSlice cliConfSlice - - // either no request file is not specified or set to std-in - if (cfg.RequestFile == "" && cfg.RequestDir == "") || cfg.RequestFile == "-" { - // Add empty item to iterate - TODO refactor - dataSlice.Append(cliConf{}) - // or request file is specified - } else if cfg.RequestFile != "" { - - var data cliConf - - err := data.Load(cfg.RequestFile) - if err != nil { - return err - } - - dataSlice.Append(data) - - // or request dir is specified - } else if cfg.RequestDir != "" { - listing, err := ioutil.ReadDir(cfg.RequestDir) - - if err != nil { - return err - } - - for _, fi := range listing { - - fmt.Println(fi.Name()) - - folderPath := path.Join(cfg.RequestDir, fi.Name()) - - var data cliConf - err = data.Load(folderPath) - if err != nil { - return err - } - dataSlice.Append(data) - } - } - conn, client, err := dial() if err != nil { return err } defer conn.Close() - // sort the config items for both create & delete cases - switch caller { - case "create": - dataSlice.Sort() - case "delete": - dataSlice.Reverse() - } - for _, d := range dataSlice.C { - err := fn(client, d.Raw, em.NewEncoder(os.Stdout)) - - if err != nil { - return err - } - } - - return nil -} - -func decoderFromPath(filePath string) (*os.File, iocodec.Decoder, error) { - - f, err := os.Open(filePath) + err = fn(client, nil, em.NewEncoder(os.Stdout)) if err != nil { - return nil, nil, fmt.Errorf("request file: %v", err) - } - - ext := filepath.Ext(filePath) - - if len(ext) > 0 && ext[0] == '.' { - ext = ext[1:] - if ext != "yaml" { - return nil, nil, fmt.Errorf("invalid request file format: %q", ext) - - } + return err } - dm, _ := iocodec.DefaultDecoders["yaml"] - - return f, dm.NewDecoder(f), nil -} - -func yamlDecoder(filePath string, target interface{}) error { - - data, err := ioutil.ReadFile(filePath) - if err != nil { - return fmt.Errorf("failed to read file [%s]: %s", filePath, err.Error()) - } - err = yaml.Unmarshal(data, target) - if err != nil { - return fmt.Errorf("error parsing file [%s]: %s", filePath, err.Error()) - } return nil } diff --git a/cmd/device-hub-cli/main.go b/cmd/device-hub-cli/main.go index ac36c9c..99499f4 100644 --- a/cmd/device-hub-cli/main.go +++ b/cmd/device-hub-cli/main.go @@ -17,13 +17,24 @@ import ( var RootCmd = &cobra.Command{ Use: "device-hub-cli", + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + + err := _resources.SetResources(_config) + if err != nil { + return err + } + return nil + }, } // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -var _config = newConfig() +var ( + _config = newConfig() + _resources = newResources() +) type config struct { ServerAddr string `envconfig:"SERVER_ADDR" default:"127.0.0.1:50051"` @@ -42,6 +53,7 @@ type config struct { AuthTokenType string `envconfig:"AUTH_TOKEN_TYPE" default:"Bearer"` JWTKey string `envconfig:"JWT_KEY"` JWTKeyFile string `envconfig:"JWT_KEY_FILE"` + ProcessConf processConf } func newConfig() *config { diff --git a/cmd/device-hub-cli/resource.go b/cmd/device-hub-cli/resource.go new file mode 100644 index 0000000..2d388ad --- /dev/null +++ b/cmd/device-hub-cli/resource.go @@ -0,0 +1,246 @@ +// Copyright © 2017 thingful + +package main + +import ( + "context" + "fmt" + "io/ioutil" + "path" + "path/filepath" + "sort" + "strings" + + "github.com/fiorix/protoc-gen-cobra/iocodec" + "github.com/thingful/device-hub/proto" + + yaml "gopkg.in/yaml.v2" +) + +type rawContent []byte + +func (r rawContent) Decode(target interface{}) error { + err := yaml.Unmarshal(r, target) + if err != nil { + return fmt.Errorf("error decoding data: %s", err.Error()) + } + return nil +} + +// Represent a resource file, Data is basically used to order a resourceSlice +// Raw contains the file content +type resource struct { + FileName string + Data map[string]interface{} + Raw rawContent +} + +// Load the configuration file to Data +func (r *resource) Load(filePath string) (err error) { + r.Raw, err = ioutil.ReadFile(filePath) + if err != nil { + return fmt.Errorf("failed to read file [%s]: %s", filePath, err.Error()) + } + + _, r.FileName = filepath.Split(filePath) + + r.Raw.Decode(&r.Data) + if err != nil { + return fmt.Errorf("error parsing file [%s]: %s", filePath, err.Error()) + } + return nil +} + +func (r *resource) sendCreateReq() error { + err := roundTrip(func(client proto.HubClient, in rawContent, out iocodec.Encoder) error { + req := proto.CreateRequest{} + err := r.Raw.Decode(&req) + if err != nil { + return err + } + + resp, err := client.Create(context.Background(), &req) + if err != nil { + return err + } + return out.Encode(resp) + }) + return err +} + +func (r *resource) sendStartReq(args []string) error { + err := roundTrip(func(client proto.HubClient, in rawContent, out iocodec.Encoder) error { + req := proto.StartRequest{ + Endpoints: []string{}, + Tags: map[string]string{}, + } + + if _config.RequestFile == "" { + err := r.Raw.Decode(&_config.ProcessConf) + if err != nil { + return err + } + } else { + r.Raw.Decode(&_config.ProcessConf) + } + + if len(args) > 0 { + req.Profile = args[0] + } else { + req.Profile = _config.ProcessConf.ProfileUID + } + + req.Uri = _config.ProcessConf.URI + req.Listener = _config.ProcessConf.ListenerUID + req.Endpoints = _config.ProcessConf.EndpointUIDs + + // review tags + tags := _config.ProcessConf.Tags + + for _, m := range tags { + bits := strings.Split(m, ":") + if len(bits) != 2 { + return fmt.Errorf("metadata not colon (:) separated : %s", m) + } + req.Tags[bits[0]] = bits[1] + } + + resp, err := client.Start(context.Background(), &req) + if err != nil { + return err + } + return out.Encode(resp) + }) + return err +} + +func (r *resource) SendCreate(args []string) error { + if r.Data["type"] == "process" { + return r.sendStartReq(args) + } + return r.sendCreateReq() +} + +func (r *resource) sendStopReq(uri string) error { + err := roundTrip(func(client proto.HubClient, in rawContent, out iocodec.Encoder) error { + if uri == "" { + uri = r.Data["uri"].(string) + } + return stopCall(uri, client, in, out) + }) + return err +} + +func (r *resource) sendDeleteReq() error { + err := roundTrip(func(client proto.HubClient, in rawContent, out iocodec.Encoder) error { + req := proto.DeleteRequest{} + err := r.Raw.Decode(&req) + if err != nil { + return err + } + + resp, err := client.Delete(context.Background(), &req) + if err != nil { + return err + } + return out.Encode(resp) + }) + return err +} + +func (r *resource) SendDelete(uri string) error { + if r.Data["type"] == "process" { + return r.sendStopReq(uri) + } + return r.sendDeleteReq() +} + +// resourceSlice contains configs and implements sort interface using +// "process" type file as the less weight +type resourceSlice struct { + R []resource +} + +func newResources() *resourceSlice { + return &resourceSlice{} +} + +func (r *resourceSlice) Append(e resource) { + + r.R = append(r.R, e) +} + +func (r resourceSlice) Len() int { + return len(r.R) +} + +func (r resourceSlice) Less(i, j int) bool { + if r.R[j].Data["type"] == "process" { + return true + } + return false +} + +func (r resourceSlice) Swap(i, j int) { + r.R[i], r.R[j] = r.R[j], r.R[i] +} + +// Sort is required to put processes at the end when executing create cmd +func (r resourceSlice) Sort() { + sort.Sort(resourceSlice(r)) +} + +// Reverse is required to put processes at first to stop them before delete resources +func (r resourceSlice) Reverse() { + sort.Sort(sort.Reverse(resourceSlice(r))) +} + +func (r resourceSlice) Print() { + for _, f := range r.R { + fmt.Println(f.FileName) + } +} + +// GetCliConfig get config for the CLI app +func (r *resourceSlice) SetResources(cfg *config) error { + var res resource + if cfg.RequestFile != "" { + err := res.Load(cfg.RequestFile) + if err != nil { + return err + } + r.Append(res) + return nil + + } else if cfg.RequestDir != "" { + listing, err := ioutil.ReadDir(cfg.RequestDir) + if err != nil { + return err + } + + for _, f := range listing { + folderPath := path.Join(cfg.RequestDir, f.Name()) + var _res resource // check if this could be outer scoped! (conf) + err = _res.Load(folderPath) + if err != nil { + return err + } + r.Append(_res) + } + } + // Sorted with process to the end by default + r.Sort() + // TODO validate? + r.Print() + return nil +} + +// could be proto.StartRequest? +type processConf struct { + URI string `yaml:"uri"` + Type string `yaml:"type"` + EndpointUIDs []string `yaml:"endpoint-uids"` + ListenerUID string `yaml:"listener-uid"` + ProfileUID string `yaml:"profile-uid"` + Tags []string `yaml:"tags"` +} From 224faf578ee97b55ba95a0efc5399a4e55bacc26 Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Fri, 21 Jul 2017 00:41:13 -0400 Subject: [PATCH 13/16] delete describe --- cmd/device-hub-cli/cmd_describe.go | 58 ------------------------------ cmd/device-hub-cli/main.go | 1 - 2 files changed, 59 deletions(-) delete mode 100644 cmd/device-hub-cli/cmd_describe.go diff --git a/cmd/device-hub-cli/cmd_describe.go b/cmd/device-hub-cli/cmd_describe.go deleted file mode 100644 index 2c37919..0000000 --- a/cmd/device-hub-cli/cmd_describe.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright © 2017 thingful - -package main - -import ( - "errors" - "fmt" - "strings" - - "github.com/spf13/cobra" - "github.com/thingful/device-hub/describe" - "github.com/thingful/device-hub/endpoint" - "github.com/thingful/device-hub/listener" - "github.com/thingful/device-hub/registry" -) - -var describeCommand = &cobra.Command{ - Use: "describe", - Short: "Describe parameters for endpoint and listeners", - RunE: func(cmd *cobra.Command, args []string) error { - - if len(args) != 2 { - return errors.New("describe [listener|endpoint] kind") - } - - typez := strings.ToLower(args[0]) - kind := strings.ToLower(args[1]) - - var params describe.Parameters - var err error - - register := registry.Default - - endpoint.Register(register) - listener.Register(register) - - switch typez { - case "listener": - params, err = register.DescribeListener(kind) - - case "endpoint": - params, err = register.DescribeEndpoint(kind) - - default: - return errors.New("describe [listener|endpoint] kind") - } - - if err != nil { - return err - } - for _, param := range params { - fmt.Println(param.Describe()) - } - - return nil - - }, -} diff --git a/cmd/device-hub-cli/main.go b/cmd/device-hub-cli/main.go index 99499f4..23ede5a 100644 --- a/cmd/device-hub-cli/main.go +++ b/cmd/device-hub-cli/main.go @@ -90,7 +90,6 @@ func init() { RootCmd.AddCommand(startCommand()) RootCmd.AddCommand(stopCommand) RootCmd.AddCommand(statusCommand) - RootCmd.AddCommand(describeCommand) _config.AddFlags(RootCmd.PersistentFlags()) } From da96884769dbce1f78e31dac5f05253d289deead Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Fri, 21 Jul 2017 01:01:15 -0400 Subject: [PATCH 14/16] update docs --- docs/client.md | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/docs/client.md b/docs/client.md index 3ae0a9a..be02990 100644 --- a/docs/client.md +++ b/docs/client.md @@ -20,41 +20,36 @@ Client CLI Commands - Flag: -d Large Format: --request-dir Is required: Yes if -f isn't specified - Description: Directory containing client request file(s) (must be json, yaml, or xml) + Description: Directory containing client request yaml file(s) if there are process files, will be started Parameter: A filesystem path Example: device-hub-cli create -d=./test-configurations/ - Flag: -f Large Format: --request-file Is required: Yes if -d isn't specified - Description: Client request file (must be json, yaml, or xml); use "-" for stdin + json - Parameter: Directory containing client request file(s) (must be json, yaml, or xml) + Description: Client request yaml file + Parameter: Directory containing client request yaml file(s) Example: device-hub-cli create -f=./test-configurations/mqtt_listener.yaml - Command Name: delete [-d|-f]= - Description: Delete listener, profile and endpoint resources + Description: Delete listener, profile, endpoint resources and stop processes if -d is used Flags: - Flag: -d Large Format: --request-dir Is required: Yes if -f isn't specified - Description: Directory containing client request file(s) (must be json, yaml, or xml) + Description: Directory containing client request yaml file(s) if there are process files, will be stopped Parameter: A filesystem path Example: device-hub-cli delete -d=./test-configurations/ - Flag: -f Large Format: --request-file Is required: Yes if -d isn't specified - Description: Client request file (must be json, yaml, or xml); use "-" for stdin + json - Parameter: Directory containing client request file(s) (must be json, yaml, or xml) + Description: Client request yaml file + Parameter: Directory containing client request yaml file(s) Example: device-hub-cli delete -f=./test-configurations/mqtt_listener.yaml -- Command Name: describe [listener|endpoint] [mqtt|stdout] - Description: Describe parameters for endpoints and listeners - Example: device-hub-cli listener mqtt - - - Command Name: show [listener|endpoint|profile|all] Description: Display one or many resources by type or using "all" as * filter, Example: device-hub-cli show all @@ -64,28 +59,35 @@ Client CLI Commands Description: List running pipes -- Command Name: start [-e -l -u ] +- Command Name: start [-f ][-e -l -u ] Description: Start processing messages on an URI Flags: + + - Flag: -f + Description: Start processing messages using a yaml config file + Large Format: --request-file + Is required: No + - Flag: -e Description: Endpoint uid to push messages to, may be specified multiple times Large Format: --endpoint - Is required: Yes + Is required: Yes if -f isn't specified - Flag: -l Description: Listener uid to accept messages on Large Format: --listener - Is required: Yes + Is required: Yes if -f isn't specified - Flag: -u Description: Uri to listen on Large Format: --uri - Is required: Yes + Is required: Yes if -f isn't specified - Flag: -t Description: Colon separated (k:v) runtime tags to attach to requests, may be specified multiple times Large Format: --tags - + Is required: Yes if -f isn't specified + Example: device-hub-cli start -e=stdout-endpoint -l=http-listener-local-port-8085 -u=/a thingful/helsinki-bus @@ -116,10 +118,6 @@ CLI Global Flags Description: response format (json, prettyjson, yaml, or xml) Default: json -- Flag: -p - Large Format: --print-sample-request - Description: Print sample request file and exit - - Flag: --timeout Description: Client connection timeout Default: 10s From adba4284bacd619f9d1fb0a3e432db2c12fdc855 Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Fri, 21 Jul 2017 12:15:32 -0400 Subject: [PATCH 15/16] fixes --- cmd/device-hub-cli/cmd_create.go | 2 +- cmd/device-hub-cli/cmd_start.go | 13 +++++++++---- cmd/device-hub-cli/resource.go | 20 +++++++++++--------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/cmd/device-hub-cli/cmd_create.go b/cmd/device-hub-cli/cmd_create.go index ac2f9ec..0726013 100644 --- a/cmd/device-hub-cli/cmd_create.go +++ b/cmd/device-hub-cli/cmd_create.go @@ -12,7 +12,7 @@ var createCommand = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { for _, r := range _resources.R { - err := r.SendCreate(args) + err := r.SendCreate() if err != nil { return err diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index 991b522..3ba5d6a 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -17,10 +17,15 @@ func startCommand() *cobra.Command { Use: "start", Short: "Start processing messages on a uri", RunE: func(cmd *cobra.Command, args []string) error { + var uri string + if len(_resources.R) == 0 { - return errors.New("no resource has been set") + return errors.New("no resources has been set") + } + if len(args) > 0 { + uri = args[0] } - err := _resources.R[0].SendCreate(args) + err := _resources.R[0].SendCreate(uri) if err != nil { return err } @@ -46,14 +51,14 @@ var stopCommand = &cobra.Command{ } err := roundTrip(func(client proto.HubClient, in rawContent, out iocodec.Encoder) error { - return stopCall(args[0], client, in, out) + return stopCall(args[0], client, out) }) return err }, } -func stopCall(uri string, client proto.HubClient, in rawContent, out iocodec.Encoder) error { +func stopCall(uri string, client proto.HubClient, out iocodec.Encoder) error { req := proto.StopRequest{ Uri: uri, } diff --git a/cmd/device-hub-cli/resource.go b/cmd/device-hub-cli/resource.go index 2d388ad..5444da6 100644 --- a/cmd/device-hub-cli/resource.go +++ b/cmd/device-hub-cli/resource.go @@ -68,7 +68,7 @@ func (r *resource) sendCreateReq() error { return err } -func (r *resource) sendStartReq(args []string) error { +func (r *resource) sendStartReq(uri string) error { err := roundTrip(func(client proto.HubClient, in rawContent, out iocodec.Encoder) error { req := proto.StartRequest{ Endpoints: []string{}, @@ -84,8 +84,8 @@ func (r *resource) sendStartReq(args []string) error { r.Raw.Decode(&_config.ProcessConf) } - if len(args) > 0 { - req.Profile = args[0] + if len(uri) > 0 { + req.Profile = uri } else { req.Profile = _config.ProcessConf.ProfileUID } @@ -95,9 +95,7 @@ func (r *resource) sendStartReq(args []string) error { req.Endpoints = _config.ProcessConf.EndpointUIDs // review tags - tags := _config.ProcessConf.Tags - - for _, m := range tags { + for _, m := range _config.ProcessConf.Tags { bits := strings.Split(m, ":") if len(bits) != 2 { return fmt.Errorf("metadata not colon (:) separated : %s", m) @@ -114,9 +112,13 @@ func (r *resource) sendStartReq(args []string) error { return err } -func (r *resource) SendCreate(args []string) error { +func (r *resource) SendCreate(args ...string) error { + var uri string if r.Data["type"] == "process" { - return r.sendStartReq(args) + if len(args) > 0 { + uri = args[0] + } + return r.sendStartReq(uri) } return r.sendCreateReq() } @@ -126,7 +128,7 @@ func (r *resource) sendStopReq(uri string) error { if uri == "" { uri = r.Data["uri"].(string) } - return stopCall(uri, client, in, out) + return stopCall(uri, client, out) }) return err } From d164960ddd902b49f00d2662339e0e700fd08793 Mon Sep 17 00:00:00 2001 From: ChristianEspinoza Date: Sun, 23 Jul 2017 23:22:52 -0400 Subject: [PATCH 16/16] fix start process using flags --- cmd/device-hub-cli/cmd_start.go | 14 ++++++++------ cmd/device-hub-cli/resource.go | 17 ++++++----------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/cmd/device-hub-cli/cmd_start.go b/cmd/device-hub-cli/cmd_start.go index 3ba5d6a..4c10baf 100644 --- a/cmd/device-hub-cli/cmd_start.go +++ b/cmd/device-hub-cli/cmd_start.go @@ -17,15 +17,17 @@ func startCommand() *cobra.Command { Use: "start", Short: "Start processing messages on a uri", RunE: func(cmd *cobra.Command, args []string) error { - var uri string + var profile string - if len(_resources.R) == 0 { - return errors.New("no resources has been set") - } if len(args) > 0 { - uri = args[0] + profile = args[0] + } + if len(_resources.R) == 0 { + _resources.R = append(_resources.R, + resource{ + Data: map[string]interface{}{"type": "process"}}) } - err := _resources.R[0].SendCreate(uri) + err := _resources.R[0].SendCreate(profile) if err != nil { return err } diff --git a/cmd/device-hub-cli/resource.go b/cmd/device-hub-cli/resource.go index 5444da6..06ccb74 100644 --- a/cmd/device-hub-cli/resource.go +++ b/cmd/device-hub-cli/resource.go @@ -68,24 +68,19 @@ func (r *resource) sendCreateReq() error { return err } -func (r *resource) sendStartReq(uri string) error { +func (r *resource) sendStartReq(profile string) error { err := roundTrip(func(client proto.HubClient, in rawContent, out iocodec.Encoder) error { req := proto.StartRequest{ Endpoints: []string{}, Tags: map[string]string{}, } - - if _config.RequestFile == "" { - err := r.Raw.Decode(&_config.ProcessConf) - if err != nil { - return err - } - } else { - r.Raw.Decode(&_config.ProcessConf) + err := r.Raw.Decode(&_config.ProcessConf) + if err != nil { + return err } - if len(uri) > 0 { - req.Profile = uri + if len(profile) > 0 { + req.Profile = profile } else { req.Profile = _config.ProcessConf.ProfileUID }