diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index 2351203..44bfca4 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -17,7 +17,6 @@ import ( "encoding/json" "flag" "fmt" - "github.com/andygrunwald/go-jira" "net/http" "os" "runtime" @@ -26,6 +25,7 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/jiralert/pkg/alertmanager" + "github.com/prometheus-community/jiralert/pkg/clientset" "github.com/prometheus-community/jiralert/pkg/config" "github.com/prometheus-community/jiralert/pkg/notify" "github.com/prometheus-community/jiralert/pkg/template" @@ -82,6 +82,8 @@ func main() { os.Exit(1) } + var cs clientset.ClientSet + http.HandleFunc("/alert", func(w http.ResponseWriter, req *http.Request) { level.Debug(logger).Log("msg", "handling /alert webhook request") defer func() { _ = req.Body.Close() }() @@ -100,22 +102,7 @@ func main() { } level.Debug(logger).Log("msg", " matched receiver", "receiver", conf.Name) - // TODO: Consider reusing notifiers or just jira clients to reuse connections. - var client *jira.Client - var err error - if conf.User != "" && conf.Password != "" { - tp := jira.BasicAuthTransport{ - Username: conf.User, - Password: string(conf.Password), - } - client, err = jira.NewClient(tp.Client(), conf.APIURL) - } else if conf.PersonalAccessToken != "" { - tp := jira.PATAuthTransport{ - Token: string(conf.PersonalAccessToken), - } - client, err = jira.NewClient(tp.Client(), conf.APIURL) - } - + client, err := cs.GetOrCreateJira(conf) if err != nil { errorHandler(w, http.StatusInternalServerError, err, conf.Name, &data, logger) return diff --git a/pkg/clientset/clientset.go b/pkg/clientset/clientset.go new file mode 100644 index 0000000..fa55892 --- /dev/null +++ b/pkg/clientset/clientset.go @@ -0,0 +1,81 @@ +// Copyright 2017 The Prometheus Authors +// 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 clientset + +import ( + "errors" + "fmt" + "sync" + + "github.com/andygrunwald/go-jira" + "github.com/prometheus-community/jiralert/pkg/config" +) + +type ClientSet struct { + jira map[string]*jira.Client + sync.RWMutex +} + +var ErrorClientExists = errors.New("client already exists") + +func (c *ClientSet) getJira(userName string) (*jira.Client, bool) { + c.RLock() + jc, ok := c.jira[userName] + c.RUnlock() + + return jc, ok +} + +func (c *ClientSet) newJira(conf *config.ReceiverConfig) (*jira.Client, error) { + if conf == nil { + return nil, fmt.Errorf("missing receiver config") + } + + if jc, ok := c.getJira(conf.User); ok { + return jc, fmt.Errorf("jira %w: %s", ErrorClientExists, conf.User) + } + + var ( + client *jira.Client + err error + ) + if conf.User != "" && conf.Password != "" { + tp := jira.BasicAuthTransport{ + Username: conf.User, + Password: string(conf.Password), + } + client, err = jira.NewClient(tp.Client(), conf.APIURL) + } else if conf.PersonalAccessToken != "" { + tp := jira.PATAuthTransport{ + Token: string(conf.PersonalAccessToken), + } + client, err = jira.NewClient(tp.Client(), conf.APIURL) + } + + if err == nil { + c.Lock() + c.jira[conf.User] = client + c.Unlock() + } + + return client, err +} + +func (c *ClientSet) GetOrCreateJira(conf *config.ReceiverConfig) (*jira.Client, error) { + jc, err := c.newJira(conf) + if errors.Is(err, ErrorClientExists) { + err = nil + } + return jc, err +}