diff --git a/cmd/pulsectl/commands.go b/cmd/pulsectl/commands.go index 665a486c2..5d6474d22 100644 --- a/cmd/pulsectl/commands.go +++ b/cmd/pulsectl/commands.go @@ -142,6 +142,60 @@ var ( }, }, } + + tribeCommands = []cli.Command{ + { + Name: "member", + Subcommands: []cli.Command{ + { + Name: "list", + Usage: "list", + Action: listMembers, + }, + { + Name: "show", + Usage: "show ", + Action: showMember, + Flags: []cli.Flag{flVerbose}, + }, + }, + }, + { + Name: "agreement", + Subcommands: []cli.Command{ + { + Name: "list", + Usage: "list", + Action: listAgreements, + }, + { + Name: "create", + Usage: "create ", + Action: createAgreement, + }, + { + Name: "delete", + Usage: "delete ", + Action: deleteAgreement, + }, + { + Name: "join", + Usage: "join ", + Action: joinAgreement, + }, + { + Name: "leave", + Usage: "leave ", + Action: leaveAgreement, + }, + { + Name: "members", + Usage: "members ", + Action: agreementMembers, + }, + }, + }, + } ) func printFields(tw *tabwriter.Writer, indent bool, width int, fields ...interface{}) { @@ -157,3 +211,21 @@ func printFields(tw *tabwriter.Writer, indent bool, width int, fields ...interfa } fmt.Fprintln(tw, argArray...) } + +type ByCommand []cli.Command + +func (s ByCommand) Len() int { + return len(s) +} +func (s ByCommand) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} +func (s ByCommand) Less(i, j int) bool { + if s[i].Name == "help" { + return false + } + if s[j].Name == "help" { + return true + } + return s[i].Name < s[j].Name +} diff --git a/cmd/pulsectl/flags.go b/cmd/pulsectl/flags.go index 5c06274d0..828ee61c2 100644 --- a/cmd/pulsectl/flags.go +++ b/cmd/pulsectl/flags.go @@ -118,4 +118,10 @@ var ( Name: "metric-namespace, m", Usage: "A metric namespace", } + + // general + flVerbose = cli.BoolFlag{ + Name: "verbose, v", + Usage: "Verbose output", + } ) diff --git a/cmd/pulsectl/main.go b/cmd/pulsectl/main.go index 591375d3f..1bbfc1d2d 100644 --- a/cmd/pulsectl/main.go +++ b/cmd/pulsectl/main.go @@ -21,6 +21,7 @@ package main import ( "os" + "sort" "time" "github.com/codegangsta/cli" @@ -46,6 +47,11 @@ func main() { if pClient == nil { pClient = client.New(c.GlobalString("url"), c.GlobalString("api-version"), c.GlobalBool("insecure")) } + resp := pClient.ListAgreements() + if resp.Err == nil { + app.Commands = append(app.Commands, tribeCommands...) + } + sort.Sort(ByCommand(app.Commands)) return nil } diff --git a/cmd/pulsectl/tribe.go b/cmd/pulsectl/tribe.go new file mode 100644 index 000000000..fda695ad7 --- /dev/null +++ b/cmd/pulsectl/tribe.go @@ -0,0 +1,218 @@ +/* +http://www.apache.org/licenses/LICENSE-2.0.txt + + +Copyright 2015 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "sort" + "text/tabwriter" + + "github.com/codegangsta/cli" + "github.com/intelsdi-x/pulse/mgmt/tribe/agreement" +) + +func listMembers(ctx *cli.Context) { + resp := pClient.ListMembers() + if resp.Err != nil { + fmt.Printf("Error getting members:\n%v\n", resp.Err) + os.Exit(1) + } + + if len(resp.Members) > 0 { + w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) + defer w.Flush() + printFields(w, false, 0, + "Name", + ) + for _, m := range resp.Members { + printFields(w, false, 0, m) + } + } else { + fmt.Println("None") + } +} + +func showMember(ctx *cli.Context) { + if len(ctx.Args()) != 1 { + fmt.Println("Incorrect usage:") + cli.ShowCommandHelp(ctx, ctx.Command.Name) + os.Exit(1) + } + + resp := pClient.GetMember(ctx.Args().First()) + if resp.Err != nil { + fmt.Printf("Error:\n%v\n", resp.Err) + os.Exit(1) + } + + w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) + defer w.Flush() + fields := []interface{}{"Name", "Plugin Agreement", "Task Agreements"} + if ctx.Bool("verbose") { + fields = append(fields, "tags") + } + printFields(w, false, 0, + fields..., + ) + var tasks bytes.Buffer + for idx, task := range resp.TaskAgreements { + tasks.WriteString(task) + if idx < (len(resp.TaskAgreements) - 1) { + tasks.WriteString(",") + } + } + tags, err := json.Marshal(resp.Tags) + if err != nil { + fmt.Printf("Error:\n%v\n", err) + os.Exit(1) + } + + values := []interface{}{resp.Name, resp.PluginAgreement, tasks.String()} + if ctx.Bool("verbose") { + values = append(values, string(tags)) + } + + printFields(w, false, 0, values...) + +} + +func listAgreements(ctx *cli.Context) { + resp := pClient.ListAgreements() + if resp.Err != nil { + fmt.Printf("Error getting members:\n%v\n", resp.Err) + os.Exit(1) + } + printAgreements(resp.Agreements) +} + +func createAgreement(ctx *cli.Context) { + if len(ctx.Args()) != 1 { + fmt.Println("Incorrect usage:") + cli.ShowCommandHelp(ctx, ctx.Command.Name) + os.Exit(1) + } + + resp := pClient.AddAgreement(ctx.Args().First()) + if resp.Err != nil { + fmt.Printf("Error creating agreement: %v\n", resp.Err) + os.Exit(1) + } + printAgreements(resp.Agreements) +} + +func deleteAgreement(ctx *cli.Context) { + if len(ctx.Args()) != 1 { + fmt.Println("Incorrect usage:") + cli.ShowCommandHelp(ctx, ctx.Command.Name) + os.Exit(1) + } + + resp := pClient.DeleteAgreement(ctx.Args().First()) + if resp.Err != nil { + fmt.Printf("Error: %v\n", resp.Err) + os.Exit(1) + } + printAgreements(resp.Agreements) +} + +func joinAgreement(ctx *cli.Context) { + if len(ctx.Args()) != 2 { + fmt.Println("Incorrect usage:") + cli.ShowCommandHelp(ctx, ctx.Command.Name) + os.Exit(1) + } + + resp := pClient.JoinAgreement(ctx.Args().First(), ctx.Args().Get(1)) + if resp.Err != nil { + fmt.Printf("Error: %v\n", resp.Err) + os.Exit(1) + } + printAgreements(map[string]*agreement.Agreement{resp.Agreement.Name: resp.Agreement}) +} + +func leaveAgreement(ctx *cli.Context) { + if len(ctx.Args()) != 2 { + fmt.Println("Incorrect usage:") + cli.ShowCommandHelp(ctx, ctx.Command.Name) + os.Exit(1) + } + + resp := pClient.LeaveAgreement(ctx.Args().First(), ctx.Args().Get(1)) + if resp.Err != nil { + fmt.Printf("Error: %v\n", resp.Err) + os.Exit(1) + } + printAgreements(map[string]*agreement.Agreement{resp.Agreement.Name: resp.Agreement}) +} + +func agreementMembers(ctx *cli.Context) { + if len(ctx.Args()) != 1 { + fmt.Println("Incorrect usage:") + cli.ShowCommandHelp(ctx, ctx.Command.Name) + os.Exit(1) + } + + resp := pClient.GetAgreement(ctx.Args().First()) + if resp.Err != nil { + fmt.Printf("Error: %v\n", resp.Err) + os.Exit(1) + } + + w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) + defer w.Flush() + printFields(w, false, 0, "Name") + for _, v := range resp.Agreement.Members { + printFields(w, false, 0, v.Name) + } +} + +func printAgreements(agreements map[string]*agreement.Agreement) { + if len(agreements) > 0 { + w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) + defer w.Flush() + printFields(w, false, 0, + "Name", "Number of Members", "plugins", "tasks", + ) + + var keys []string + for k := range agreements { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, k := range keys { + v := agreements[k] + var plugins interface{} + var tasks interface{} + if v.PluginAgreement != nil { + plugins = len(v.PluginAgreement.Plugins) + } + if v.TaskAgreement != nil { + tasks = len(v.TaskAgreement.Tasks) + } + printFields(w, false, 0, v.Name, len(v.Members), plugins, tasks) + } + } else { + fmt.Println("None") + } +} diff --git a/mgmt/rest/client/client_tribe_func_test.go b/mgmt/rest/client/client_tribe_func_test.go new file mode 100644 index 000000000..5d15122c7 --- /dev/null +++ b/mgmt/rest/client/client_tribe_func_test.go @@ -0,0 +1,214 @@ +/* +http://www.apache.org/licenses/LICENSE-2.0.txt + + +Copyright 2015 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client_test + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "sync" + "testing" + "time" + + log "github.com/Sirupsen/logrus" + . "github.com/smartystreets/goconvey/convey" + + "github.com/intelsdi-x/pulse/control" + "github.com/intelsdi-x/pulse/mgmt/rest" + "github.com/intelsdi-x/pulse/mgmt/rest/client" + "github.com/intelsdi-x/pulse/mgmt/rest/rbody" + "github.com/intelsdi-x/pulse/mgmt/tribe" + "github.com/intelsdi-x/pulse/scheduler" +) + +var NextPort = 46000 + +func getPort() int { + defer incrPort() + return NextPort +} + +func incrPort() { + NextPort += 10 +} + +func readBody(r *http.Response) []byte { + b, err := ioutil.ReadAll(r.Body) + if err != nil { + log.Fatal(err) + } + r.Body.Close() + return b +} + +func getAPIResponse(resp *http.Response) *rbody.APIResponse { + r := new(rbody.APIResponse) + rb := readBody(resp) + err := json.Unmarshal(rb, r) + if err != nil { + log.Fatal(err) + } + r.JSONResponse = string(rb) + return r +} + +func getMembers(port int) *rbody.APIResponse { + resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/v1/tribe/members", port)) + if err != nil { + log.Fatal(err) + } + return getAPIResponse(resp) +} + +func TestPulseClientTribe(t *testing.T) { + Convey("REST API functional V1 - TRIBE", t, func() { + numOfTribes := 4 + ports := startTribes(numOfTribes) + c := client.New(fmt.Sprintf("http://localhost:%d", ports[0]), "v1", true) + + Convey("Get global membership", func() { + resp := c.ListMembers() + So(resp.Err, ShouldBeNil) + So(resp.Members, ShouldNotBeNil) + So(resp, ShouldHaveSameTypeAs, &client.ListMembersResult{}) + So(len(resp.Members), ShouldEqual, numOfTribes) + }) + + Convey("An agreement is added", func() { + agreement := "agreement1" + resp := c.AddAgreement(agreement) + So(resp.Err, ShouldBeNil) + So(resp, ShouldHaveSameTypeAs, &client.AddAgreementResult{}) + So(len(resp.Agreements), ShouldEqual, 1) + resp2 := c.ListAgreements() + So(resp2.Err, ShouldBeNil) + So(resp2, ShouldHaveSameTypeAs, &client.ListAgreementResult{}) + So(len(resp2.Agreements), ShouldEqual, 1) + Convey("A node joins the agreement", func() { + resp := c.JoinAgreement(agreement, fmt.Sprintf("member-%d", ports[0])) + So(resp.Err, ShouldBeNil) + So(resp, ShouldHaveSameTypeAs, &client.JoinAgreementResult{}) + So(resp.Agreement, ShouldNotBeNil) + So(len(resp.Agreement.Members), ShouldEqual, 1) + Convey("The rest of the members join the agreement", func() { + for i := 1; i < numOfTribes; i++ { + resp := c.JoinAgreement(agreement, fmt.Sprintf("member-%d", ports[i])) + So(resp.Err, ShouldBeNil) + So(resp, ShouldHaveSameTypeAs, &client.JoinAgreementResult{}) + So(resp.Agreement, ShouldNotBeNil) + So(len(resp.Agreement.Members), ShouldEqual, i+1) + } + Convey("A member is removed from the agreement", func() { + resp := c.LeaveAgreement(agreement, fmt.Sprintf("member-%d", ports[0])) + So(resp.Err, ShouldBeNil) + So(resp, ShouldHaveSameTypeAs, &client.LeaveAgreementResult{}) + So(resp.Agreement, ShouldNotBeNil) + So(len(resp.Agreement.Members), ShouldEqual, numOfTribes-1) + Convey("A member is retrieved", func() { + resp := c.GetMember(fmt.Sprintf("member-%d", ports[1])) + So(resp.Err, ShouldBeNil) + So(resp, ShouldHaveSameTypeAs, &client.GetMemberResult{}) + So(resp.Name, ShouldNotBeNil) + So(resp.Name, ShouldResemble, fmt.Sprintf("member-%d", ports[1])) + Convey("An Agreement is retrieved", func() { + resp := c.GetAgreement(agreement) + So(resp.Err, ShouldBeNil) + So(resp, ShouldHaveSameTypeAs, &client.GetAgreementResult{}) + So(resp.Agreement.Name, ShouldNotBeNil) + So(resp.Agreement.Name, ShouldResemble, agreement) + So(len(resp.Agreement.Members), ShouldEqual, 3) + Convey("An agreement is deleted", func() { + resp := c.DeleteAgreement(agreement) + So(resp.Err, ShouldBeNil) + So(resp, ShouldHaveSameTypeAs, &client.DeleteAgreementResult{}) + So(len(resp.Agreements), ShouldEqual, 0) + }) + }) + }) + }) + }) + }) + }) + }) +} + +func startTribes(count int) []int { + seed := "" + var wg sync.WaitGroup + var mgtPorts []int + for i := 0; i < count; i++ { + mgtPort := getPort() + mgtPorts = append(mgtPorts, mgtPort) + tribePort := getPort() + conf := tribe.DefaultConfig(fmt.Sprintf("member-%v", mgtPort), "127.0.0.1", tribePort, seed, mgtPort) + conf.MemberlistConfig.PushPullInterval = 5 * time.Second + conf.MemberlistConfig.RetransmitMult = conf.MemberlistConfig.RetransmitMult * 2 + if seed == "" { + seed = fmt.Sprintf("%s:%d", "127.0.0.1", tribePort) + } + t, err := tribe.New(conf) + if err != nil { + panic(err) + } + + c := control.New() + c.RegisterEventHandler("tribe", t) + c.Start() + s := scheduler.New() + s.SetMetricManager(c) + s.RegisterEventHandler("tribe", t) + s.Start() + t.SetPluginCatalog(c) + t.SetTaskManager(s) + t.Start() + r, _ := rest.New(false, "", "") + r.BindMetricManager(c) + r.BindTaskManager(s) + r.BindTribeManager(t) + r.Start(":" + strconv.Itoa(mgtPort)) + wg.Add(1) + timer := time.After(10 * time.Second) + go func(port int) { + defer wg.Done() + for { + select { + case <-timer: + panic("timed out") + default: + time.Sleep(100 * time.Millisecond) + + resp := getMembers(port) + if resp.Meta.Code == 200 && len(resp.Body.(*rbody.TribeMemberList).Members) == count { + log.Infof("num of members %v", len(resp.Body.(*rbody.TribeMemberList).Members)) + return + } + } + } + }(mgtPort) + } + wg.Wait() + uris := make([]int, len(mgtPorts)) + for idx, port := range mgtPorts { + uris[idx] = port + } + return uris +} diff --git a/mgmt/rest/client/tribe.go b/mgmt/rest/client/tribe.go new file mode 100644 index 000000000..aa75281d0 --- /dev/null +++ b/mgmt/rest/client/tribe.go @@ -0,0 +1,207 @@ +/* +http://www.apache.org/licenses/LICENSE-2.0.txt + + +Copyright 2015 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "encoding/json" + "fmt" + + "github.com/intelsdi-x/pulse/mgmt/rest/rbody" +) + +func (c *Client) ListMembers() *ListMembersResult { + resp, err := c.do("GET", "/tribe/members", ContentTypeJSON, nil) + if err != nil { + return &ListMembersResult{Err: err} + } + switch resp.Meta.Type { + case rbody.TribeMemberListType: + // Success + return &ListMembersResult{resp.Body.(*rbody.TribeMemberList), nil} + case rbody.ErrorType: + return &ListMembersResult{Err: resp.Body.(*rbody.Error)} + default: + return &ListMembersResult{Err: ErrAPIResponseMetaType} + } +} + +func (c *Client) GetMember(name string) *GetMemberResult { + resp, err := c.do("GET", fmt.Sprintf("/tribe/member/%s", name), ContentTypeJSON, nil) + if err != nil { + return &GetMemberResult{Err: err} + } + switch resp.Meta.Type { + case rbody.TribeMemberShowType: + // Success + return &GetMemberResult{resp.Body.(*rbody.TribeMemberShow), nil} + case rbody.ErrorType: + return &GetMemberResult{Err: resp.Body.(*rbody.Error)} + default: + return &GetMemberResult{Err: ErrAPIResponseMetaType} + } +} + +func (c *Client) ListAgreements() *ListAgreementResult { + resp, err := c.do("GET", "/tribe/agreements", ContentTypeJSON, nil) + if err != nil { + return &ListAgreementResult{Err: err} + } + switch resp.Meta.Type { + case rbody.TribeListAgreementType: + return &ListAgreementResult{resp.Body.(*rbody.TribeListAgreement), nil} + case rbody.ErrorType: + return &ListAgreementResult{Err: resp.Body.(*rbody.Error)} + default: + return &ListAgreementResult{Err: ErrAPIResponseMetaType} + } +} + +func (c *Client) AddAgreement(name string) *AddAgreementResult { + b, err := json.Marshal(struct { + Name string `json:"name"` + }{Name: name}) + if err != nil { + return &AddAgreementResult{Err: err} + } + resp, err := c.do("POST", "/tribe/agreements", ContentTypeJSON, b) + if err != nil { + return &AddAgreementResult{Err: err} + } + switch resp.Meta.Type { + case rbody.TribeAddAgreementType: + return &AddAgreementResult{resp.Body.(*rbody.TribeAddAgreement), nil} + case rbody.ErrorType: + return &AddAgreementResult{Err: resp.Body.(*rbody.Error)} + default: + return &AddAgreementResult{Err: ErrAPIResponseMetaType} + } +} + +func (c *Client) DeleteAgreement(name string) *DeleteAgreementResult { + resp, err := c.do("DELETE", fmt.Sprintf("/tribe/agreements/%s", name), ContentTypeJSON, nil) + if err != nil { + return &DeleteAgreementResult{Err: err} + } + switch resp.Meta.Type { + case rbody.TribeDeleteAgreementType: + return &DeleteAgreementResult{resp.Body.(*rbody.TribeDeleteAgreement), nil} + case rbody.ErrorType: + return &DeleteAgreementResult{Err: resp.Body.(*rbody.Error)} + default: + return &DeleteAgreementResult{Err: ErrAPIResponseMetaType} + } +} + +func (c *Client) GetAgreement(name string) *GetAgreementResult { + resp, err := c.do("GET", fmt.Sprintf("/tribe/agreements/%s", name), ContentTypeJSON, nil) + if err != nil { + return &GetAgreementResult{Err: err} + } + switch resp.Meta.Type { + case rbody.TribeGetAgreementType: + return &GetAgreementResult{resp.Body.(*rbody.TribeGetAgreement), nil} + case rbody.ErrorType: + return &GetAgreementResult{Err: resp.Body.(*rbody.Error)} + default: + return &GetAgreementResult{Err: ErrAPIResponseMetaType} + } +} + +func (c *Client) JoinAgreement(agreementName, memberName string) *JoinAgreementResult { + b, err := json.Marshal(struct { + MemberName string `json:"member_name"` + }{MemberName: memberName}) + if err != nil { + return &JoinAgreementResult{Err: err} + } + resp, err := c.do("PUT", fmt.Sprintf("/tribe/agreements/%s/join", agreementName), ContentTypeJSON, b) + if err != nil { + return &JoinAgreementResult{Err: err} + } + switch resp.Meta.Type { + case rbody.TribeJoinAgreementType: + return &JoinAgreementResult{resp.Body.(*rbody.TribeJoinAgreement), nil} + case rbody.ErrorType: + return &JoinAgreementResult{Err: resp.Body.(*rbody.Error)} + default: + return &JoinAgreementResult{Err: ErrAPIResponseMetaType} + } +} + +func (c *Client) LeaveAgreement(agreementName, memberName string) *LeaveAgreementResult { + b, err := json.Marshal(struct { + MemberName string `json:"member_name"` + }{MemberName: memberName}) + if err != nil { + return &LeaveAgreementResult{Err: err} + } + resp, err := c.do("DELETE", fmt.Sprintf("/tribe/agreements/%s/leave", agreementName), ContentTypeJSON, b) + if err != nil { + return &LeaveAgreementResult{Err: err} + } + switch resp.Meta.Type { + case rbody.TribeLeaveAgreementType: + return &LeaveAgreementResult{resp.Body.(*rbody.TribeLeaveAgreement), nil} + case rbody.ErrorType: + return &LeaveAgreementResult{Err: resp.Body.(*rbody.Error)} + default: + return &LeaveAgreementResult{Err: ErrAPIResponseMetaType} + } +} + +type ListMembersResult struct { + *rbody.TribeMemberList + Err error +} + +type GetMemberResult struct { + *rbody.TribeMemberShow + Err error +} + +type AddAgreementResult struct { + *rbody.TribeAddAgreement + Err error +} + +type ListAgreementResult struct { + *rbody.TribeListAgreement + Err error +} + +type DeleteAgreementResult struct { + *rbody.TribeDeleteAgreement + Err error +} + +type GetAgreementResult struct { + *rbody.TribeGetAgreement + Err error +} + +type JoinAgreementResult struct { + *rbody.TribeJoinAgreement + Err error +} + +type LeaveAgreementResult struct { + *rbody.TribeLeaveAgreement + Err error +} diff --git a/mgmt/rest/rbody/body.go b/mgmt/rest/rbody/body.go index 6be4b5407..05fe35dcd 100644 --- a/mgmt/rest/rbody/body.go +++ b/mgmt/rest/rbody/body.go @@ -103,8 +103,8 @@ func UnmarshalBody(t string, b []byte) (Body, error) { return unmarshalAndHandleError(b, &ScheduledTaskWatchingEnded{}) case TribeMemberListType: return unmarshalAndHandleError(b, &TribeMemberList{}) - case TribeAgreementListType: - return unmarshalAndHandleError(b, &TribeAgreementList{}) + case TribeListAgreementType: + return unmarshalAndHandleError(b, &TribeListAgreement{}) case TribeAddAgreementType: return unmarshalAndHandleError(b, &TribeAddAgreement{}) case TribeDeleteAgreementType: diff --git a/mgmt/rest/rbody/tribe.go b/mgmt/rest/rbody/tribe.go index 8e33c13a0..238b1c480 100644 --- a/mgmt/rest/rbody/tribe.go +++ b/mgmt/rest/rbody/tribe.go @@ -22,7 +22,7 @@ package rbody import "github.com/intelsdi-x/pulse/mgmt/tribe/agreement" const ( - TribeAgreementListType = "tribe_agreement_list_returned" + TribeListAgreementType = "tribe_agreement_list_returned" TribeGetAgreementType = "tribe_agreement_returned" TribeAddAgreementType = "tribe_agreement_created" TribeDeleteAgreementType = "tribe_agreement_deleted" @@ -34,7 +34,7 @@ const ( ) type TribeAddAgreement struct { - Name string + Agreements map[string]*agreement.Agreement `json:"agreements"` } func (t *TribeAddAgreement) ResponseBodyMessage() string { @@ -69,16 +69,16 @@ func (t *TribeDeleteAgreement) ResponseBodyType() string { return TribeDeleteAgreementType } -type TribeAgreementList struct { +type TribeListAgreement struct { Agreements map[string]*agreement.Agreement `json:"agreements"` } -func (t *TribeAgreementList) ResponseBodyMessage() string { +func (t *TribeListAgreement) ResponseBodyMessage() string { return "Tribe agreements retrieved" } -func (t *TribeAgreementList) ResponseBodyType() string { - return TribeAgreementListType +func (t *TribeListAgreement) ResponseBodyType() string { + return TribeListAgreementType } type TribeJoinAgreement struct { diff --git a/mgmt/rest/tribe.go b/mgmt/rest/tribe.go index 73a009de8..273d2a0a5 100644 --- a/mgmt/rest/tribe.go +++ b/mgmt/rest/tribe.go @@ -43,7 +43,7 @@ var ( ) func (s *Server) getAgreements(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - res := &rbody.TribeAgreementList{} + res := &rbody.TribeListAgreement{} res.Agreements = s.tr.GetAgreements() respond(200, res, w) } @@ -81,7 +81,7 @@ func (s *Server) deleteAgreement(w http.ResponseWriter, r *http.Request, p httpr respond(400, rbody.FromPulseError(perror.New(ErrAgreementDoesNotExist, fields)), w) return } - a := &rbody.TribeDeleteAgreement{} + var perr perror.PulseError perr = s.tr.RemoveAgreement(name) if perr != nil { @@ -89,6 +89,8 @@ func (s *Server) deleteAgreement(w http.ResponseWriter, r *http.Request, p httpr respond(400, rbody.FromPulseError(perr), w) return } + + a := &rbody.TribeDeleteAgreement{} a.Agreements = s.tr.GetAgreements() respond(200, a, w) } @@ -206,8 +208,10 @@ func (s *Server) getMember(w http.ResponseWriter, r *http.Request, p httprouter. if member.PluginAgreement != nil { resp.PluginAgreement = member.PluginAgreement.Name } - for k, _ := range member.TaskAgreements { - resp.TaskAgreements = append(resp.TaskAgreements, k) + for k, t := range member.TaskAgreements { + if len(t.Tasks) > 0 { + resp.TaskAgreements = append(resp.TaskAgreements, k) + } } respond(200, resp, w) } @@ -226,7 +230,7 @@ func (s *Server) addAgreement(w http.ResponseWriter, r *http.Request, p httprout if err != nil { fields := map[string]interface{}{ "error": err, - "hint": `The body of the request should be of the form '{"name": "some_value"}'`, + "hint": `The body of the request should be of the form '{"name": "agreement_name"}'`, } pe := perror.New(ErrInvalidJSON, fields) tribeLogger.WithFields(fields).Error(ErrInvalidJSON) @@ -236,7 +240,7 @@ func (s *Server) addAgreement(w http.ResponseWriter, r *http.Request, p httprout if a.Name == "" { fields := map[string]interface{}{ - "hint": `The body of the request should be of the form '{"name": "some_value"}'`, + "hint": `The body of the request should be of the form '{"name": "agreement_name"}'`, } pe := perror.New(ErrInvalidJSON, fields) tribeLogger.WithFields(fields).Error(ErrInvalidJSON) @@ -251,5 +255,8 @@ func (s *Server) addAgreement(w http.ResponseWriter, r *http.Request, p httprout return } - respond(200, &rbody.TribeAddAgreement{Name: a.Name}, w) + res := &rbody.TribeAddAgreement{} + res.Agreements = s.tr.GetAgreements() + + respond(200, res, w) } diff --git a/mgmt/rest/tribe_test.go b/mgmt/rest/tribe_test.go index 85e22e669..aac55f898 100644 --- a/mgmt/rest/tribe_test.go +++ b/mgmt/rest/tribe_test.go @@ -504,8 +504,8 @@ func TestTribePluginAgreements(t *testing.T) { default: resp := getAgreements(port) if resp.Meta.Code == 200 { - c.So(resp.Body.(*rbody.TribeAgreementList), ShouldHaveSameTypeAs, new(rbody.TribeAgreementList)) - if len(resp.Body.(*rbody.TribeAgreementList).Agreements) == 0 { + c.So(resp.Body.(*rbody.TribeListAgreement), ShouldHaveSameTypeAs, new(rbody.TribeListAgreement)) + if len(resp.Body.(*rbody.TribeListAgreement).Agreements) == 0 { return } }