diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index 4b643a3..e875abf 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -22,11 +22,10 @@ import ( "runtime" "strconv" - "github.com/andygrunwald/go-jira" - "github.com/go-kit/kit/log" "github.com/go-kit/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" @@ -83,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() }() @@ -101,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/go.mod b/go.mod index 680ffdb..6a13c88 100644 --- a/go.mod +++ b/go.mod @@ -11,5 +11,6 @@ require ( github.com/prometheus/common v0.10.0 // indirect github.com/stretchr/testify v1.5.1 github.com/trivago/tgo v1.0.7 + golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect gopkg.in/yaml.v2 v2.3.0 ) diff --git a/go.sum b/go.sum index f721b67..00c3d25 100644 --- a/go.sum +++ b/go.sum @@ -341,6 +341,8 @@ golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslY golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 h1:AzgQNqF+FKwyQ5LbVrVqOcuuFB67N47F9+htZYH0wFM= +golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/pkg/clientset/clientset.go b/pkg/clientset/clientset.go new file mode 100644 index 0000000..ba44e2f --- /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 +}