// Handle targets message func (plugin *targets) Handle(req *comm.Request) error { t := comm.Mention(req.User) if len(plugin.config.Targets) < 1 { t += "no known targets" } else { t += "known targets - " for k, v := range plugin.config.Targets { if k > 0 { t += ", " } t += comm.BuildwebTargetURL(v) } } iop := &comm.Interop{ Request: req, Response: &comm.Response{ Channel: req.Channel, Text: t, Parameters: comm.DefaultMessageParameters()}} comm.SB.ChanResponse <- iop.Response comm.SB.ChanPersist <- iop return nil }
// Handle branches message func (plugin *branches) Handle(req *comm.Request) (err error) { t := comm.Mention(req.User) if len(plugin.config.Branches) == 0 { t += "no known branches" } else { t += "known branches - " for k, v := range plugin.config.Branches { if k > 0 { t += ", " } t += comm.BuildwebBranchURL(v) } } iop := &comm.Interop{ Request: req, Response: &comm.Response{ Channel: req.Channel, Text: t, Parameters: comm.DefaultMessageParameters()}} comm.SB.ChanResponse <- iop.Response comm.SB.ChanPersist <- iop return }
// Handle testrun message // CAT URL: // http://cat.eng.vmware.com/api/v2.0/testrun/?format=json&limit=1&order_by=-endtime&deliverables__build__branch=main&area__name=SingleVA_PostCheckin&result=PASS func (plugin *testrun) Handle(req *comm.Request) error { url := plugin.config.URLs.BaseCatURL + plugin.config.URLs.BaseTestrunURL params := DefaultCatParams() params["deliverables__build__branch"] = defaultBranch if len(req.Arguments) > 2 { params["deliverables__build__branch"] = req.Arguments[2] } params["area__name"] = defaultArea if len(req.Arguments) > 3 { params["area__name"] = req.Arguments[3] } if len(req.Arguments) > 4 { params["result"] = req.Arguments[4] } p := params.AsUrlValues() s := napping.Session{} j := TestrunJSON{} r, err := s.Get(url, &p, &j, nil) if err != nil { return err } if r.Status() != 200 { return fmt.Errorf("expect response status code 200. Actual %d %s", r.Status(), params) } if len(j.Objects) == 0 { return fmt.Errorf("testrun %s/%s not found", params["deliverables__build__branch"], params["area__name"]) } if len(j.Objects) != 1 { return fmt.Errorf("expected one object. Actual %d %s", len(j.Objects), params) } t := comm.Mention(req.User) t += fmt.Sprintf("testrun for %s ", comm.CatTestrunURL(j.Objects[0].ID, fmt.Sprintf("%s/%s", params["deliverables__build__branch"], params["area__name"]))) t += fmt.Sprintf("is *%s* ", j.Objects[0].Result) t += fmt.Sprintf("(%s)", comm.CatTestrunResultsURL(j.Objects[0].ResultsDir)) iop := &comm.Interop{ Request: req, Response: &comm.Response{ Channel: req.Channel, Text: t, Parameters: comm.DefaultMessageParameters()}} comm.SB.ChanResponse <- iop.Response comm.SB.ChanPersist <- iop return nil }
// HandleUnknown handles unknown directives func (pm *PluginManager) HandleUnknown(req *comm.Request) error { text := comm.Mention(req.User) text += fmt.Sprintf("unknown request - *%s*", strings.Join(req.Arguments, " ")) comm.SB.ChanResponse <- &comm.Response{ Channel: req.Channel, Text: text, Parameters: comm.DefaultMessageParameters()} return nil }
// HandleError handles plugin handle error func (pm *PluginManager) HandleError(req *comm.Request, err error) error { text := comm.Mention(req.User) text += fmt.Sprintf("error occurred - *%s*", err) comm.SB.ChanResponse <- &comm.Response{ Channel: req.Channel, Text: text, Parameters: comm.DefaultMessageParameters()} return nil }
// Handle build message // CAT URL: // http://cat.eng.vmware.com/api/v2.0/deliverable/?format=json&limit=1&order_by=-endtime&build__branch=<1>&targets=<2>&result=<3> func (plugin *build) Handle(req *comm.Request) error { url := plugin.config.URLs.BaseCatURL + plugin.config.URLs.BaseBuildURL params := DefaultCatParams() params["build__branch"] = defaultBranch if len(req.Arguments) > 2 { params["build__branch"] = req.Arguments[2] } params["targets"] = defaultTarget if len(req.Arguments) > 3 { params["targets"] = req.Arguments[3] } if len(req.Arguments) > 4 { params["result"] = req.Arguments[4] } p := params.AsUrlValues() s := napping.Session{} j := BuildJSON{} r, err := s.Get(url, &p, &j, nil) if err != nil { return err } if r.Status() != 200 { return fmt.Errorf("expect response status code 200. Actual %d %s", r.Status(), params) } if len(j.Objects) == 0 { return fmt.Errorf("build %s/%s not found", params["build__branch"], params["targets"]) } if len(j.Objects) > 1 { return fmt.Errorf("expected one object. Actual %d %s", len(j.Objects), params) } t := comm.Mention(req.User) t += fmt.Sprintf("latest *%s/%s* ", j.Objects[0].Build.Branch, j.Objects[0].Targets) t += fmt.Sprintf("status is *%s* ", j.Objects[0].Result) t += fmt.Sprintf("(%s)", comm.BuildwebSbURL(j.Objects[0].SbBuildID, strconv.Itoa(j.Objects[0].SbBuildID))) iop := &comm.Interop{ Request: req, Response: &comm.Response{ Channel: req.Channel, Text: t, Parameters: comm.DefaultMessageParameters()}} comm.SB.ChanResponse <- iop.Response comm.SB.ChanPersist <- iop return nil }
// Handle welcome message func (plugin *welcome) Handle(req *comm.Request) error { t := comm.Mention(req.User) m := strings.ToLower(req.Arguments[0]) m = replacer.Replace(m) r, _ := responseMap[m] t += fmt.Sprintf("%s", r) comm.SB.ChanResponse <- &comm.Response{ Channel: req.Channel, Text: t, Parameters: comm.DefaultMessageParameters()} return nil }
// Handle uptime message func (plugin *uptime) Handle(req *comm.Request) error { now := time.Now() t := comm.Mention(req.User) t += fmt.Sprintf( "start time: *%s* current time: *%s* uptime: *%s*", plugin.start.Format(time.RFC822), now.Format(time.RFC822), now.Sub(plugin.start)) comm.SB.ChanResponse <- &comm.Response{ Channel: req.Channel, Text: t, Parameters: comm.DefaultMessageParameters()} return nil }
// HandleHelp checks if help is requested func (pm *PluginManager) HandleHelp(req *comm.Request) error { text := comm.Mention(req.User) text += "*vR Ops Bot Usage*\n" for _, v := range pm.pullPlugin { u := v.Usage() if len(u) > 0 { text += fmt.Sprintf("\t%s\n", v.Usage()) } } comm.SB.ChanResponse <- &comm.Response{ Channel: req.Channel, Text: text, Parameters: comm.DefaultMessageParameters()} return nil }
// Handle slas message func (plugin *slas) Handle(req *comm.Request) error { t := comm.Mention(req.User) if len(plugin.config.SLAs) < 1 { t += "no known slas" } else { t += fmt.Sprintf("known slas - *%s*", strings.Join(plugin.config.SLAs, ", ")) } iop := &comm.Interop{ Request: req, Response: &comm.Response{ Channel: req.Channel, Text: t, Parameters: comm.DefaultMessageParameters()}} comm.SB.ChanResponse <- iop.Response comm.SB.ChanPersist <- iop return nil }
// Handle manages the posting of a new vro workflow // GET https://10.25.37.28:8281/vco/api/workflows/ // POST https://10.25.37.28:8281/vco/api/workflows/<id>/executions func (plugin *wf) Handle(req *comm.Request) error { vroURL := plugin.config.Vro.BaseURL + plugin.config.Vro.WfURL vroUser := plugin.config.Vro.Username vroPass := plugin.config.Vro.Password vroInsecure := plugin.config.Vro.Insecure debug := plugin.config.Debug build := req.Arguments[2] buildType := "sb" if len(req.Arguments) > 3 { buildType = req.Arguments[3] } wfName := "dev_checkin_tests" if len(req.Arguments) > 4 { wfName = req.Arguments[4] } tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: vroInsecure}, } s := napping.Session{ Client: &http.Client{Transport: tr}, Log: debug, Userinfo: url.UserPassword(vroUser, vroPass)} var href string { np := napping.Params{ "conditions": fmt.Sprintf("name=%s", wfName)} p := np.AsUrlValues() j := WorkflowsJSON{} r, err := s.Get(vroURL, &p, &j, nil) if err != nil { return err } if r.Status() != 200 { return fmt.Errorf("error querying vRO for '%s' [%d]", wfName, r.Status()) } if len(j.Link) == 0 { return fmt.Errorf("vRO workflow '%s' not found", wfName) } if len(j.Link) != 1 { return fmt.Errorf("expect one vRO %s workflow. Actual %d", wfName, len(j.Link)) } if len(j.Link[0].Href) == 0 { return fmt.Errorf("href is empty for '%s' vRO workflow", wfName) } href = j.Link[0].Href } { slackUser, _ := comm.GetUser(req.User) slackEmail := fmt.Sprintf("*****@*****.**", slackUser) j := WorkflowExecutionJSON{ Parameters: []Parameter{ Parameter{ Name: "vcopssuitepakBuildNumber", Type: "string", Value: Value{ String: String{ Value: build}}}, Parameter{ Name: "vcopssuitepakBuildType", Type: "string", Value: Value{ String: String{ Value: buildType}}}, Parameter{ Name: "email_to_address", Type: "string", Value: Value{ String: String{ Value: slackEmail}}}, Parameter{ Name: "vappPrefix", Type: "string", Value: Value{ String: String{ Value: slackUser}}}, Parameter{ Name: "vAppOwner", Type: "string", Value: Value{ String: String{ Value: slackUser}}}}} r, err := s.Post(href+"executions", &j, nil, nil) if err != nil { return err } if r.Status() != 202 { return fmt.Errorf("expect response status code 202. Actual %d", r.Status()) } } text := comm.Mention(req.User) text += fmt.Sprintf("started vro workflow *%s* using *%s/%s*", wfName, build, buildType) iop := &comm.Interop{ Request: req, Response: &comm.Response{ Channel: req.Channel, Text: text, Parameters: comm.DefaultMessageParameters()}} comm.SB.ChanResponse <- iop.Response comm.SB.ChanPersist <- iop return nil }
// Run starts the message pump for build push func (plugin *buildPush) Run() (err error) { pollInterval := common.DefaultPollInterval var channels []string var groups []string pollInterval, err = time.ParseDuration(plugin.config.PushPluginConfig.PollInterval) if err != nil { return err } channels = plugin.config.PushPluginConfig.Channels groups = plugin.config.PushPluginConfig.Groups if len(channels) == 0 && len(groups) == 0 { return fmt.Errorf("no channels or groups specified") } log.Printf("%s poll interval %d", plugin.Name(), pollInterval) log.Printf("%s channels %v", plugin.Name(), channels) log.Printf("%s groups %v", plugin.Name(), groups) for _, b := range plugin.config.Branches { for _, t := range plugin.config.Targets { common.RandomDelay() go func(branch, target string) { pumpName := fmt.Sprintf("%s/%s/%s", plugin.Name(), branch, target) log.Printf("Starting pump for %s", pumpName) buildResult := unknownStatus for { select { case <-time.After(pollInterval): comm.SB.ChanHeartbeat <- pumpName pa := &common.PushActions{ PluginName: plugin.Name()} url := plugin.config.URLs.BaseCatURL + plugin.config.URLs.BaseBuildURL params := DefaultCatParams() params["build__branch"] = branch params["targets"] = target p := params.AsUrlValues() s := napping.Session{} j := BuildJSON{} r, err := s.Get(url, &p, &j, nil) if err != nil { pa.Response = fmt.Sprintf("Error getting %s %s [%s]", url, params, err) pa.IsError = 1 comm.SB.ChanPersist <- pa continue } if r.Status() != 200 { pa.Response = fmt.Sprintf("Expect response status code 200. Actual %d %s", r.Status(), url) pa.IsError = 1 comm.SB.ChanPersist <- pa continue } if len(j.Objects) == 0 { // build not found continue } if len(j.Objects) > 1 { pa.Response = fmt.Sprintf("Expected one object. Actual %d %s", len(j.Objects), params) pa.IsError = 1 comm.SB.ChanPersist <- pa continue } // if build status has changed // and build status is not unknown // and build is not the default status // post the result if (buildResult != unknownStatus && buildResult != j.Objects[0].Result) || (buildResult == unknownStatus && j.Objects[0].Result != defaultResult) { text := fmt.Sprintf("build *%s/%s* ", branch, target) text += fmt.Sprintf("changed *%s* to *%s* ", buildResult, j.Objects[0].Result) text += fmt.Sprintf("(%s)", comm.BuildwebSbURL(j.Objects[0].SbBuildID, strconv.Itoa(j.Objects[0].SbBuildID))) pa.Response = text pa.Before = buildResult pa.After = j.Objects[0].Result for _, c := range channels { cname, err := comm.GetChannelByName(c) if err != nil { log.Print(err) continue } comm.SB.ChanResponse <- &comm.Response{ Channel: cname, Text: text, Parameters: comm.DefaultMessageParameters()} pa.Channel = cname comm.SB.ChanPersist <- pa } for _, g := range groups { gname, err := comm.GetGroupByName(g) if err != nil { log.Print(err) continue } comm.SB.ChanResponse <- &comm.Response{ Channel: gname, Text: text, Parameters: comm.DefaultMessageParameters()} pa.Channel = gname comm.SB.ChanPersist <- pa } } buildResult = j.Objects[0].Result } } }(b, t) } } return }
// Handle recommended message // CAT URL: // http://cat.eng.vmware.com/api/v2.0/recommendation/?format=json&limit=1&order_by=-updated&branch__name=main&sla__name=VA_Bats&site=mbu func (plugin *recommended) Handle(req *comm.Request) error { branch := defaultBranch if len(req.Arguments) > 2 { branch = req.Arguments[2] } jRecommended := RecommendedJSON{} { url := plugin.config.URLs.BaseCatURL + plugin.config.URLs.BaseRecommendedURL params := DefaultRecommendedParams() params["branch__name"] = branch p := params.AsUrlValues() s := napping.Session{} r, err := s.Get(url, &p, &jRecommended, nil) if err != nil { return err } if r.Status() != 200 { return fmt.Errorf("expect response status code 200. Actual %d %s", r.Status(), params) } if len(jRecommended.Objects) == 0 { return fmt.Errorf("recommended change list for %s not found", params["branch__name"]) } if len(jRecommended.Objects) > 1 { return fmt.Errorf("expected one object. Actual %d %s", len(jRecommended.Objects), params) } } // CAT URL: // http://cat.eng.vmware.com/api/v2.0/build/<id>/?format=json jCurrBuild := CurrBuildJSON{} { url := plugin.config.URLs.BaseCatURL + jRecommended.Objects[0].CurrBuild params := DefaultCurrBuildParams() p := params.AsUrlValues() s := napping.Session{} r, err := s.Get(url, &p, &jCurrBuild, nil) if err != nil { return err } if r.Status() != 200 { return fmt.Errorf("expect response status code 200. Actual %d\n", r.Status()) } } t := comm.Mention(req.User) t += fmt.Sprintf("recommended changeset for *%s* ", branch) t += fmt.Sprintf("is *%s*", comm.P4WebBranchURL(branch, jCurrBuild.Changeset)) iop := &comm.Interop{ Request: req, Response: &comm.Response{ Channel: req.Channel, Text: t, Parameters: comm.DefaultMessageParameters()}} comm.SB.ChanResponse <- iop.Response comm.SB.ChanPersist <- iop return nil }
// Run recommendedPush func (plugin *recommendedPush) Run() (err error) { pollInterval := common.DefaultPollInterval var channels []string var groups []string pollInterval, err = time.ParseDuration(plugin.config.PushPluginConfig.PollInterval) if err != nil { return err } channels = plugin.config.PushPluginConfig.Channels groups = plugin.config.PushPluginConfig.Groups if len(channels) == 0 && len(groups) == 0 { return fmt.Errorf("no channels or groups specified") } log.Printf("%s poll interval %d", plugin.Name(), pollInterval) log.Printf("%s channels %v", plugin.Name(), channels) log.Printf("%s groups %v", plugin.Name(), groups) for _, b := range plugin.config.Branches { common.RandomDelay() go func(branch string) { pumpName := fmt.Sprintf("%s/%s", plugin.Name(), branch) log.Printf("Starting pump for %s", pumpName) currentChangeset := unknownStatus for { select { case <-time.After(pollInterval): comm.SB.ChanHeartbeat <- pumpName pa := &common.PushActions{ PluginName: plugin.Name()} jRecommended := RecommendedJSON{} { url := plugin.config.URLs.BaseCatURL + plugin.config.URLs.BaseRecommendedURL params := DefaultRecommendedParams() params["branch__name"] = branch p := params.AsUrlValues() s := napping.Session{} r, err := s.Get(url, &p, &jRecommended, nil) if err != nil { pa.Response = fmt.Sprintf("Error getting %s %s [%s]", url, params, err) pa.IsError = 1 comm.SB.ChanPersist <- pa continue } if r.Status() != 200 { pa.Response = fmt.Sprintf("Expect response status code 200. Actual %d. %s", r.Status(), params) pa.IsError = 1 comm.SB.ChanPersist <- pa continue } if len(jRecommended.Objects) == 0 { // build not found continue } if len(jRecommended.Objects) > 1 { pa.Response = fmt.Sprintf("Expected one object. Actual %d %s\n", len(jRecommended.Objects), params) pa.IsError = 1 comm.SB.ChanPersist <- pa continue } } jCurrBuild := CurrBuildJSON{} { url := plugin.config.URLs.BaseCatURL + jRecommended.Objects[0].CurrBuild params := DefaultCurrBuildParams() p := params.AsUrlValues() s := napping.Session{} r, err := s.Get(url, &p, &jCurrBuild, nil) if err != nil { pa.Response = fmt.Sprintf("Error getting %s [%s]", url, err) pa.IsError = 1 comm.SB.ChanPersist <- pa continue } if r.Status() != 200 { pa.Response = fmt.Sprintf("Expect response status code 200. Actual %d. %s", r.Status(), params) pa.IsError = 1 comm.SB.ChanPersist <- pa continue } } if currentChangeset != unknownStatus && currentChangeset != jCurrBuild.Changeset { text := fmt.Sprintf("recommendation for *%s* ", branch) text += fmt.Sprintf( "changed from %s to %s", comm.P4WebBranchURL(branch, currentChangeset), comm.P4WebBranchURL(branch, jCurrBuild.Changeset)) pa.Response = text pa.Before = currentChangeset pa.After = jCurrBuild.Changeset for _, c := range channels { cname, err := comm.GetChannelByName(c) if err != nil { log.Print(err) continue } comm.SB.ChanResponse <- &comm.Response{ Channel: cname, Text: text, Parameters: comm.DefaultMessageParameters()} pa.Channel = cname comm.SB.ChanPersist <- pa } for _, g := range groups { gname, err := comm.GetGroupByName(g) if err != nil { log.Print(err) continue } comm.SB.ChanResponse <- &comm.Response{ Channel: gname, Text: text, Parameters: comm.DefaultMessageParameters()} pa.Channel = gname comm.SB.ChanPersist <- pa } } currentChangeset = jCurrBuild.Changeset } } }(b) } return }