diff --git a/cmd/channel/email/main.go b/cmd/channel/email/main.go index 4441180d..5119d535 100644 --- a/cmd/channel/email/main.go +++ b/cmd/channel/email/main.go @@ -8,9 +8,9 @@ import ( "github.com/emersion/go-sasl" "github.com/emersion/go-smtp" "github.com/google/uuid" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal" "github.com/icinga/icinga-notifications/pkg/plugin" - "github.com/icinga/icingadb/pkg/types" "github.com/jhillyerd/enmime" "net" "net/mail" diff --git a/cmd/icinga-notifications-daemon/main.go b/cmd/icinga-notifications-daemon/main.go index c5688933..4fce2240 100644 --- a/cmd/icinga-notifications-daemon/main.go +++ b/cmd/icinga-notifications-daemon/main.go @@ -4,6 +4,9 @@ import ( "context" "flag" "fmt" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/logging" + "github.com/icinga/icinga-go-library/utils" "github.com/icinga/icinga-notifications/internal" "github.com/icinga/icinga-notifications/internal/channel" "github.com/icinga/icinga-notifications/internal/config" @@ -11,9 +14,6 @@ import ( "github.com/icinga/icinga-notifications/internal/icinga2" "github.com/icinga/icinga-notifications/internal/incident" "github.com/icinga/icinga-notifications/internal/listener" - "github.com/icinga/icingadb/pkg/logging" - "github.com/icinga/icingadb/pkg/utils" - "go.uber.org/zap" "os" "os/signal" "runtime" @@ -55,37 +55,31 @@ func main() { conf := daemon.Config() - logs, err := logging.NewLogging( - "icinga-notifications", - conf.Logging.Level, - conf.Logging.Output, - conf.Logging.Options, - conf.Logging.Interval, - ) + logs, err := logging.NewLoggingFromConfig("icinga-notifications", conf.Logging) if err != nil { - _, _ = fmt.Fprintln(os.Stderr, "cannot initialize logging:", err) - os.Exit(1) + utils.PrintErrorThenExit(err, 1) } logger := logs.GetLogger() + defer func() { _ = logger.Sync() }() + logger.Infof("Starting Icinga Notifications daemon (%s)", internal.Version.Version) - db, err := conf.Database.Open(logs.GetChildLogger("database")) + db, err := database.NewDbFromConfig(&conf.Database, logs.GetChildLogger("database"), database.RetryConnectorCallbacks{}) if err != nil { - logger.Fatalw("cannot create database connection from config", zap.Error(err)) + logger.Fatalf("Cannot create database connection from config: %+v", err) } defer db.Close() - { - logger.Infof("Connecting to database at '%s'", utils.JoinHostPort(conf.Database.Host, conf.Database.Port)) - if err := db.Ping(); err != nil { - logger.Fatalw("cannot connect to database", zap.Error(err)) - } - } - - channel.UpsertPlugins(conf.ChannelPluginDir, logs.GetChildLogger("channel"), db) ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer cancel() + logger.Infof("Connecting to database at '%s'", db.GetAddr()) + if err := db.PingContext(ctx); err != nil { + logger.Fatalf("Cannot connect to the database: %+v", err) + } + + channel.UpsertPlugins(ctx, conf.ChannelPluginDir, logs.GetChildLogger("channel"), db) + icinga2Launcher := &icinga2.Launcher{ Ctx: ctx, Logs: logs, @@ -95,7 +89,7 @@ func main() { runtimeConfig := config.NewRuntimeConfig(icinga2Launcher.Launch, logs, db) if err := runtimeConfig.UpdateFromDatabase(ctx); err != nil { - logger.Fatalw("failed to load config from database", zap.Error(err)) + logger.Fatalf("Failed to load config from database %+v", err) } icinga2Launcher.RuntimeConfig = runtimeConfig @@ -104,13 +98,13 @@ func main() { err = incident.LoadOpenIncidents(ctx, db, logs.GetChildLogger("incident"), runtimeConfig) if err != nil { - logger.Fatalw("Can't load incidents from database", zap.Error(err)) + logger.Fatalf("Cannot load incidents from database: %+v", err) } // Wait to load open incidents from the database before either starting Event Stream Clients or starting the Listener. icinga2Launcher.Ready() if err := listener.NewListener(db, runtimeConfig, logs).Run(ctx); err != nil { - logger.Errorw("Listener has finished with an error", zap.Error(err)) + logger.Errorf("Listener has finished with an error: %+v", err) } else { logger.Info("Listener has finished") } diff --git a/go.mod b/go.mod index 1274a58d..1c645f86 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/icinga/icinga-notifications -go 1.21 +go 1.22 require ( github.com/creasty/defaults v1.7.0 @@ -8,7 +8,7 @@ require ( github.com/emersion/go-smtp v0.21.2 github.com/goccy/go-yaml v1.11.3 github.com/google/uuid v1.6.0 - github.com/icinga/icingadb v1.1.1-0.20230418113126-7c4b947aad3a + github.com/icinga/icinga-go-library v0.2.0 github.com/jhillyerd/enmime v1.2.0 github.com/jmoiron/sqlx v1.4.0 github.com/pkg/errors v0.9.1 @@ -22,11 +22,8 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.13.0 // indirect - github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect @@ -41,7 +38,7 @@ require ( github.com/ssgreg/journald v1.0.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d // indirect + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/net v0.23.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect diff --git a/go.sum b/go.sum index 4ab69370..d7f9f054 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,10 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI= github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA= github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ= github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 h1:hH4PQfOndHDlpzYfLAAfl63E8Le6F2+EL/cdhlkyRJY= github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ= @@ -17,16 +13,12 @@ github.com/emersion/go-smtp v0.21.2 h1:OLDgvZKuofk4em9fT5tFG5j4jE1/hXnX75UMvcrL4 github.com/emersion/go-smtp v0.21.2/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= @@ -35,12 +27,12 @@ github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/icinga/icingadb v1.1.1-0.20230418113126-7c4b947aad3a h1:NfVdBKa4dhPk7IU8u0MOF6ywi0LDpMkQMGs1j803+3c= -github.com/icinga/icingadb v1.1.1-0.20230418113126-7c4b947aad3a/go.mod h1:zamCKaKn4JJQinctcUyewTSNNXDfpLc0HSbqb+9lTYs= +github.com/icinga/icinga-go-library v0.2.0 h1:1or5s3KMEJGdhFbMzlN8NPw1NCd/3ntsKLw5et4/9XI= +github.com/icinga/icinga-go-library v0.2.0/go.mod h1:YN7XJN3W0FodD+j4kirO89zk2tgvanXWt1RMV8UgOLo= github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA= github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= @@ -65,14 +57,8 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -96,8 +82,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d h1:vtUKgx8dahOomfFzLREU8nSv25YHnTgLBn4rDnWZdU0= -golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= @@ -115,9 +101,5 @@ golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3j golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/channel/channel.go b/internal/channel/channel.go index c5a5c86d..a318ac69 100644 --- a/internal/channel/channel.go +++ b/internal/channel/channel.go @@ -18,7 +18,7 @@ type Channel struct { Type string `db:"type"` Config string `db:"config" json:"-"` // excluded from JSON config dump as this may contain sensitive information - Logger *zap.SugaredLogger + Logger *zap.SugaredLogger `db:"-"` restartCh chan newConfig pluginCh chan *Plugin diff --git a/internal/channel/plugin.go b/internal/channel/plugin.go index 9b3c04c8..e1d50a91 100644 --- a/internal/channel/plugin.go +++ b/internal/channel/plugin.go @@ -2,13 +2,14 @@ package channel import ( "bufio" + "context" "encoding/json" "fmt" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/logging" "github.com/icinga/icinga-notifications/internal/daemon" "github.com/icinga/icinga-notifications/pkg/plugin" "github.com/icinga/icinga-notifications/pkg/rpc" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/logging" "go.uber.org/zap" "io" "os" @@ -166,7 +167,7 @@ func forwardLogs(errPipe io.Reader, logger *zap.SugaredLogger) { } // UpsertPlugins upsert the available_channel_type table with working plugins -func UpsertPlugins(channelPluginDir string, logger *logging.Logger, db *icingadb.DB) { +func UpsertPlugins(ctx context.Context, channelPluginDir string, logger *logging.Logger, db *database.DB) { logger.Debug("Updating available channel types") files, err := os.ReadDir(channelPluginDir) if err != nil { @@ -209,7 +210,7 @@ func UpsertPlugins(channelPluginDir string, logger *logging.Logger, db *icingadb } stmt, _ := db.BuildUpsertStmt(&plugin.Info{}) - _, err = db.NamedExec(stmt, pluginInfos) + _, err = db.NamedExecContext(ctx, stmt, pluginInfos) if err != nil { logger.Errorw("Failed to update available channel types", zap.Error(err)) } else { diff --git a/internal/config/rule.go b/internal/config/rule.go index 2db0aeae..31f32144 100644 --- a/internal/config/rule.go +++ b/internal/config/rule.go @@ -4,9 +4,9 @@ import ( "context" "github.com/icinga/icinga-notifications/internal/filter" "github.com/icinga/icinga-notifications/internal/rule" - "github.com/icinga/icinga-notifications/internal/utils" "github.com/jmoiron/sqlx" "go.uber.org/zap" + "slices" ) func (r *RuntimeConfig) fetchRules(ctx context.Context, tx *sqlx.Tx) error { @@ -188,7 +188,9 @@ func (r *RuntimeConfig) applyPendingRules() { } } - escalation.Recipients = utils.RemoveNils(escalation.Recipients) + escalation.Recipients = slices.DeleteFunc(escalation.Recipients, func(r *rule.EscalationRecipient) bool { + return r == nil + }) } if currentRule := r.Rules[id]; currentRule != nil { diff --git a/internal/config/runtime.go b/internal/config/runtime.go index acd74403..909fb7f6 100644 --- a/internal/config/runtime.go +++ b/internal/config/runtime.go @@ -4,12 +4,12 @@ import ( "context" "database/sql" "errors" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/logging" "github.com/icinga/icinga-notifications/internal/channel" "github.com/icinga/icinga-notifications/internal/recipient" "github.com/icinga/icinga-notifications/internal/rule" "github.com/icinga/icinga-notifications/internal/timeperiod" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/logging" "github.com/jmoiron/sqlx" "go.uber.org/zap" "golang.org/x/crypto/bcrypt" @@ -34,7 +34,7 @@ type RuntimeConfig struct { logs *logging.Logging logger *logging.Logger - db *icingadb.DB + db *database.DB // mu is used to synchronize access to the live ConfigSet. mu sync.RWMutex @@ -43,7 +43,7 @@ type RuntimeConfig struct { func NewRuntimeConfig( esLaunch func(source *Source), logs *logging.Logging, - db *icingadb.DB, + db *database.DB, ) *RuntimeConfig { return &RuntimeConfig{ EventStreamLaunchFunc: esLaunch, diff --git a/internal/config/source.go b/internal/config/source.go index fc32e34f..df986859 100644 --- a/internal/config/source.go +++ b/internal/config/source.go @@ -2,7 +2,7 @@ package config import ( "context" - "github.com/icinga/icingadb/pkg/types" + "github.com/icinga/icinga-go-library/types" "github.com/jmoiron/sqlx" "go.uber.org/zap" ) diff --git a/internal/config/timeperiod.go b/internal/config/timeperiod.go index 9acb6576..4127ef42 100644 --- a/internal/config/timeperiod.go +++ b/internal/config/timeperiod.go @@ -4,8 +4,8 @@ import ( "context" "database/sql" "fmt" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/timeperiod" - "github.com/icinga/icingadb/pkg/types" "github.com/jmoiron/sqlx" "go.uber.org/zap" "time" diff --git a/internal/daemon/config.go b/internal/daemon/config.go index bd4c4983..19235feb 100644 --- a/internal/daemon/config.go +++ b/internal/daemon/config.go @@ -4,17 +4,18 @@ import ( "errors" "github.com/creasty/defaults" "github.com/goccy/go-yaml" - icingadbConfig "github.com/icinga/icingadb/pkg/config" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/logging" "os" ) type ConfigFile struct { - Listen string `yaml:"listen" default:"localhost:5680"` - DebugPassword string `yaml:"debug-password"` - ChannelPluginDir string `yaml:"channel-plugin-dir" default:"/usr/libexec/icinga-notifications/channel"` - Icingaweb2URL string `yaml:"icingaweb2-url"` - Database icingadbConfig.Database `yaml:"database"` - Logging icingadbConfig.Logging `yaml:"logging"` + Listen string `yaml:"listen" default:"localhost:5680"` + DebugPassword string `yaml:"debug-password"` + ChannelPluginDir string `yaml:"channel-plugin-dir" default:"/usr/libexec/icinga-notifications/channel"` + Icingaweb2URL string `yaml:"icingaweb2-url"` + Database database.Config `yaml:"database"` + Logging logging.Config `yaml:"logging"` } // config holds the configuration state as a singleton. It is used from LoadConfig and Config diff --git a/internal/event/event.go b/internal/event/event.go index 0f0e6883..bb7bacdc 100644 --- a/internal/event/event.go +++ b/internal/event/event.go @@ -5,9 +5,9 @@ import ( "context" "errors" "fmt" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/utils" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/types" "github.com/jmoiron/sqlx" "time" ) @@ -127,7 +127,7 @@ func (e *Event) FullString() string { } // Sync transforms this event to *event.EventRow and synchronises with the database. -func (e *Event) Sync(ctx context.Context, tx *sqlx.Tx, db *icingadb.DB, objectId types.Binary) error { +func (e *Event) Sync(ctx context.Context, tx *sqlx.Tx, db *database.DB, objectId types.Binary) error { if e.ID != 0 { return nil } diff --git a/internal/icinga2/launcher.go b/internal/icinga2/launcher.go index 026c0f72..08a5d0de 100644 --- a/internal/icinga2/launcher.go +++ b/internal/icinga2/launcher.go @@ -7,13 +7,13 @@ import ( "crypto/tls" "crypto/x509" "errors" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/logging" "github.com/icinga/icinga-notifications/internal" "github.com/icinga/icinga-notifications/internal/config" "github.com/icinga/icinga-notifications/internal/daemon" "github.com/icinga/icinga-notifications/internal/event" "github.com/icinga/icinga-notifications/internal/incident" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/logging" "go.uber.org/zap" "net/http" "sync" @@ -25,7 +25,7 @@ import ( type Launcher struct { Ctx context.Context Logs *logging.Logging - Db *icingadb.DB + Db *database.DB RuntimeConfig *config.RuntimeConfig mutex sync.Mutex diff --git a/internal/incident/db_types.go b/internal/incident/db_types.go index 3234cd7c..dfea13af 100644 --- a/internal/incident/db_types.go +++ b/internal/incident/db_types.go @@ -2,11 +2,11 @@ package incident import ( "context" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/event" "github.com/icinga/icinga-notifications/internal/recipient" "github.com/icinga/icinga-notifications/internal/utils" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/types" "github.com/jmoiron/sqlx" ) @@ -40,8 +40,8 @@ func (c *ContactRow) Upsert() interface{} { }{Role: c.Role} } -// Constraint implements the contracts.Constrainter interface. -func (c *ContactRow) Constraint() string { +// PgsqlOnConflictConstraint implements the database.PgsqlOnConflictConstrainter interface. +func (c *ContactRow) PgsqlOnConflictConstraint() string { if c.ContactID.Valid { return "key_incident_contact_contact" } @@ -91,7 +91,7 @@ func (h *HistoryRow) TableName() string { // Sync persists the current state of this history to the database and retrieves the just inserted history ID. // Returns error when failed to execute the query. -func (h *HistoryRow) Sync(ctx context.Context, db *icingadb.DB, tx *sqlx.Tx) error { +func (h *HistoryRow) Sync(ctx context.Context, db *database.DB, tx *sqlx.Tx) error { historyId, err := utils.InsertAndFetchId(ctx, tx, utils.BuildInsertStmtWithout(db, h, "id"), h) if err != nil { return err @@ -109,9 +109,9 @@ func (h *HistoryRow) Sync(ctx context.Context, db *icingadb.DB, tx *sqlx.Tx) err // to them of this type. The cached entries are then used to actually notify the contacts and mark the pending // notification entries as either NotificationStateSent or NotificationStateFailed. type NotificationEntry struct { - HistoryRowID int64 `db:"id"` - ContactID int64 - ChannelID int64 + HistoryRowID int64 `db:"id"` + ContactID int64 `db:"-"` + ChannelID int64 `db:"-"` State NotificationState `db:"notification_state"` SentAt types.UnixMilli `db:"sent_at"` } diff --git a/internal/incident/incident.go b/internal/incident/incident.go index 3439d98b..049431a3 100644 --- a/internal/incident/incident.go +++ b/internal/incident/incident.go @@ -4,6 +4,8 @@ import ( "context" "errors" "fmt" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/config" "github.com/icinga/icinga-notifications/internal/contracts" "github.com/icinga/icinga-notifications/internal/daemon" @@ -12,8 +14,6 @@ import ( "github.com/icinga/icinga-notifications/internal/recipient" "github.com/icinga/icinga-notifications/internal/rule" "github.com/icinga/icinga-notifications/internal/utils" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/types" "github.com/jmoiron/sqlx" "go.uber.org/zap" "sync" @@ -32,9 +32,9 @@ type Incident struct { Object *object.Object `db:"-"` - EscalationState map[escalationID]*EscalationState - Rules map[ruleID]struct{} - Recipients map[recipient.Key]*RecipientState + EscalationState map[escalationID]*EscalationState `db:"-"` + Rules map[ruleID]struct{} `db:"-"` + Recipients map[recipient.Key]*RecipientState `db:"-"` // timer calls RetriggerEscalations the next time any escalation could be reached on the incident. // @@ -44,7 +44,7 @@ type Incident struct { // be reached solely based on the incident aging, so no more timer is necessary and timer stores nil. timer *time.Timer - db *icingadb.DB + db *database.DB logger *zap.SugaredLogger runtimeConfig *config.RuntimeConfig @@ -52,7 +52,7 @@ type Incident struct { } func NewIncident( - db *icingadb.DB, obj *object.Object, runtimeConfig *config.RuntimeConfig, logger *zap.SugaredLogger, + db *database.DB, obj *object.Object, runtimeConfig *config.RuntimeConfig, logger *zap.SugaredLogger, ) *Incident { i := &Incident{ db: db, diff --git a/internal/incident/incidents.go b/internal/incident/incidents.go index 5bcc36c5..0f625651 100644 --- a/internal/incident/incidents.go +++ b/internal/incident/incidents.go @@ -3,14 +3,14 @@ package incident import ( "context" "fmt" + "github.com/icinga/icinga-go-library/com" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/logging" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/config" "github.com/icinga/icinga-notifications/internal/event" "github.com/icinga/icinga-notifications/internal/object" "github.com/icinga/icinga-notifications/internal/utils" - "github.com/icinga/icingadb/pkg/com" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/logging" - "github.com/icinga/icingadb/pkg/types" "github.com/pkg/errors" "go.uber.org/zap" "golang.org/x/sync/errgroup" @@ -25,7 +25,7 @@ var ( // LoadOpenIncidents loads all active (not yet closed) incidents from the database and restores all their states. // Returns error on any database failure. -func LoadOpenIncidents(ctx context.Context, db *icingadb.DB, logger *logging.Logger, runtimeConfig *config.RuntimeConfig) error { +func LoadOpenIncidents(ctx context.Context, db *database.DB, logger *logging.Logger, runtimeConfig *config.RuntimeConfig) error { logger.Info("Loading all active incidents from database") g, ctx := errgroup.WithContext(ctx) @@ -143,7 +143,7 @@ func LoadOpenIncidents(ctx context.Context, db *icingadb.DB, logger *logging.Log } func GetCurrent( - ctx context.Context, db *icingadb.DB, obj *object.Object, logger *logging.Logger, runtimeConfig *config.RuntimeConfig, + ctx context.Context, db *database.DB, obj *object.Object, logger *logging.Logger, runtimeConfig *config.RuntimeConfig, create bool, ) (*Incident, error) { currentIncidentsMu.Lock() @@ -203,7 +203,7 @@ func GetCurrentIncidents() map[int64]*Incident { // The returned error might be wrapped around event.ErrSuperfluousStateChange. func ProcessEvent( ctx context.Context, - db *icingadb.DB, + db *database.DB, logs *logging.Logging, runtimeConfig *config.RuntimeConfig, ev *event.Event, diff --git a/internal/incident/incidents_test.go b/internal/incident/incidents_test.go index 23b24cd7..f429ec77 100644 --- a/internal/incident/incidents_test.go +++ b/internal/incident/incidents_test.go @@ -4,13 +4,13 @@ import ( "context" "crypto/rand" "fmt" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/logging" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/config" "github.com/icinga/icinga-notifications/internal/event" "github.com/icinga/icinga-notifications/internal/object" "github.com/icinga/icinga-notifications/internal/testutils" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/logging" - "github.com/icinga/icingadb/pkg/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" @@ -88,7 +88,7 @@ func TestLoadOpenIncidents(t *testing.T) { // // The incident loading process is limited to a maximum duration of 10 seconds and will be // aborted and causes the entire test suite to fail immediately, if it takes longer. -func assertIncidents(ctx context.Context, db *icingadb.DB, t *testing.T, testData map[string]*Incident) { +func assertIncidents(ctx context.Context, db *database.DB, t *testing.T, testData map[string]*Incident) { logger := logging.NewLogger(zaptest.NewLogger(t).Sugar(), time.Hour) // Since we have been using object.FromEvent() to persist the test objects to the database, @@ -134,7 +134,7 @@ func assertIncidents(ctx context.Context, db *icingadb.DB, t *testing.T, testDat // This will firstly create and synchronise a new object from a freshly generated dummy event with distinct // tags and name, and ensures that no error is returned, otherwise it will cause the entire test suite to fail. // Once the object has been successfully synchronised, an incident is created and synced with the database. -func makeIncident(ctx context.Context, db *icingadb.DB, t *testing.T, recovered bool) *Incident { +func makeIncident(ctx context.Context, db *database.DB, t *testing.T, recovered bool) *Incident { ev := &event.Event{ Time: time.Time{}, SourceId: 1, diff --git a/internal/incident/sync.go b/internal/incident/sync.go index a1532889..f6a64d43 100644 --- a/internal/incident/sync.go +++ b/internal/incident/sync.go @@ -4,11 +4,11 @@ import ( "context" "errors" "fmt" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/event" "github.com/icinga/icinga-notifications/internal/recipient" "github.com/icinga/icinga-notifications/internal/rule" "github.com/icinga/icinga-notifications/internal/utils" - "github.com/icinga/icingadb/pkg/types" "github.com/jmoiron/sqlx" "go.uber.org/zap" "time" diff --git a/internal/listener/listener.go b/internal/listener/listener.go index 73c0955e..4a3bc67b 100644 --- a/internal/listener/listener.go +++ b/internal/listener/listener.go @@ -5,20 +5,20 @@ import ( "crypto/subtle" "encoding/json" "fmt" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/logging" "github.com/icinga/icinga-notifications/internal" "github.com/icinga/icinga-notifications/internal/config" "github.com/icinga/icinga-notifications/internal/daemon" "github.com/icinga/icinga-notifications/internal/event" "github.com/icinga/icinga-notifications/internal/incident" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/logging" "go.uber.org/zap" "net/http" "time" ) type Listener struct { - db *icingadb.DB + db *database.DB logger *logging.Logger runtimeConfig *config.RuntimeConfig @@ -26,7 +26,7 @@ type Listener struct { mux http.ServeMux } -func NewListener(db *icingadb.DB, runtimeConfig *config.RuntimeConfig, logs *logging.Logging) *Listener { +func NewListener(db *database.DB, runtimeConfig *config.RuntimeConfig, logs *logging.Logging) *Listener { l := &Listener{ db: db, logger: logs.GetChildLogger("listener"), diff --git a/internal/object/db_types.go b/internal/object/db_types.go index 979aa519..324f8af5 100644 --- a/internal/object/db_types.go +++ b/internal/object/db_types.go @@ -1,8 +1,6 @@ package object -import ( - "github.com/icinga/icingadb/pkg/types" -) +import "github.com/icinga/icinga-go-library/types" // TagRow is a base type for IdTagRow and ExtraTagRow type TagRow struct { diff --git a/internal/object/object.go b/internal/object/object.go index f258c670..be52c1c3 100644 --- a/internal/object/object.go +++ b/internal/object/object.go @@ -8,10 +8,10 @@ import ( "encoding/hex" "encoding/json" "fmt" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/event" "github.com/icinga/icinga-notifications/internal/utils" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/types" "github.com/pkg/errors" "regexp" "sort" @@ -30,14 +30,14 @@ type Object struct { Name string `db:"name"` URL types.String `db:"url"` - Tags map[string]string - ExtraTags map[string]string + Tags map[string]string `db:"-"` + ExtraTags map[string]string `db:"-"` - db *icingadb.DB + db *database.DB } // New creates a new object from the given event. -func New(db *icingadb.DB, ev *event.Event) *Object { +func New(db *database.DB, ev *event.Event) *Object { return &Object{ SourceID: ev.SourceId, Name: ev.Name, @@ -68,7 +68,7 @@ func ClearCache() { // RestoreObjects restores all objects and their (extra)tags matching the given IDs from the database. // Returns error on any database failures and panics when trying to cache an object that's already in the cache store. -func RestoreObjects(ctx context.Context, db *icingadb.DB, ids []types.Binary) error { +func RestoreObjects(ctx context.Context, db *database.DB, ids []types.Binary) error { objects := map[string]*Object{} err := utils.ForEachRow[Object](ctx, db, "id", ids, func(o *Object) { o.db = db @@ -114,7 +114,7 @@ func RestoreObjects(ctx context.Context, db *icingadb.DB, ids []types.Binary) er // FromEvent creates an object from the provided event tags if it's not in the cache // and syncs all object related types with the database. // Returns error on any database failure -func FromEvent(ctx context.Context, db *icingadb.DB, ev *event.Event) (*Object, error) { +func FromEvent(ctx context.Context, db *database.DB, ev *event.Event) (*Object, error) { id := ID(ev.SourceId, ev.Tags) cacheMu.Lock() diff --git a/internal/recipient/contact.go b/internal/recipient/contact.go index bf0eeb96..e3503536 100644 --- a/internal/recipient/contact.go +++ b/internal/recipient/contact.go @@ -10,7 +10,7 @@ type Contact struct { FullName string `db:"full_name"` Username sql.NullString `db:"username"` DefaultChannelID int64 `db:"default_channel_id"` - Addresses []*Address + Addresses []*Address `db:"-"` } func (c *Contact) String() string { diff --git a/internal/recipient/group.go b/internal/recipient/group.go index 1325667a..f960bf3e 100644 --- a/internal/recipient/group.go +++ b/internal/recipient/group.go @@ -3,10 +3,10 @@ package recipient import "time" type Group struct { - ID int64 `db:"id"` - Name string `db:"name"` - Members []*Contact - MemberIDs []int64 + ID int64 `db:"id"` + Name string `db:"name"` + Members []*Contact `db:"-"` + MemberIDs []int64 `db:"-"` } func (g *Group) GetContactsAt(t time.Time) []*Contact { diff --git a/internal/recipient/recipient.go b/internal/recipient/recipient.go index c426842e..a09f45e4 100644 --- a/internal/recipient/recipient.go +++ b/internal/recipient/recipient.go @@ -2,8 +2,8 @@ package recipient import ( "fmt" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/utils" - "github.com/icinga/icingadb/pkg/types" "go.uber.org/zap/zapcore" "time" ) diff --git a/internal/recipient/schedule.go b/internal/recipient/schedule.go index 3be25bd4..24c30c2a 100644 --- a/internal/recipient/schedule.go +++ b/internal/recipient/schedule.go @@ -7,10 +7,10 @@ import ( ) type Schedule struct { - ID int64 `db:"id"` - Name string `db:"name"` - Members []*Member - MemberRows []*ScheduleMemberRow + ID int64 `db:"id"` + Name string `db:"name"` + Members []*Member `db:"-"` + MemberRows []*ScheduleMemberRow `db:"-"` } type Member struct { diff --git a/internal/rule/escalation.go b/internal/rule/escalation.go index d07a25c5..22731b73 100644 --- a/internal/rule/escalation.go +++ b/internal/rule/escalation.go @@ -16,9 +16,9 @@ type Escalation struct { Condition filter.Filter `db:"-"` ConditionExpr sql.NullString `db:"condition"` FallbackForID sql.NullInt64 `db:"fallback_for"` - Fallbacks []*Escalation + Fallbacks []*Escalation `db:"-"` - Recipients []*EscalationRecipient + Recipients []*EscalationRecipient `db:"-"` } // MarshalLogObject implements the zapcore.ObjectMarshaler interface. @@ -87,7 +87,7 @@ type EscalationRecipient struct { EscalationID int64 `db:"rule_escalation_id"` ChannelID sql.NullInt64 `db:"channel_id"` recipient.Key `db:",inline"` - Recipient recipient.Recipient + Recipient recipient.Recipient `db:"-"` } func (r *EscalationRecipient) TableName() string { diff --git a/internal/rule/rule.go b/internal/rule/rule.go index 370185b9..0350d9f9 100644 --- a/internal/rule/rule.go +++ b/internal/rule/rule.go @@ -1,22 +1,22 @@ package rule import ( + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/filter" "github.com/icinga/icinga-notifications/internal/recipient" "github.com/icinga/icinga-notifications/internal/timeperiod" - "github.com/icinga/icingadb/pkg/types" "time" ) type Rule struct { - ID int64 `db:"id"` - IsActive types.Bool `db:"is_active"` - Name string `db:"name"` - TimePeriod *timeperiod.TimePeriod - TimePeriodID types.Int `db:"timeperiod_id"` - ObjectFilter filter.Filter `db:"-"` - ObjectFilterExpr types.String `db:"object_filter"` - Escalations map[int64]*Escalation + ID int64 `db:"id"` + IsActive types.Bool `db:"is_active"` + Name string `db:"name"` + TimePeriod *timeperiod.TimePeriod `db:"-"` + TimePeriodID types.Int `db:"timeperiod_id"` + ObjectFilter filter.Filter `db:"-"` + ObjectFilterExpr types.String `db:"object_filter"` + Escalations map[int64]*Escalation `db:"-"` } // ContactChannels stores a set of channel IDs for each set of individual contacts. diff --git a/internal/testutils/testutils.go b/internal/testutils/testutils.go index 6f68698f..19aef451 100644 --- a/internal/testutils/testutils.go +++ b/internal/testutils/testutils.go @@ -3,9 +3,8 @@ package testutils import ( "context" "github.com/creasty/defaults" - "github.com/icinga/icingadb/pkg/config" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/logging" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/logging" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" "os" @@ -19,8 +18,8 @@ import ( // // The test suite will be skipped if no environment variable is set, otherwise fails fatally when // invalid configurations are specified. -func GetTestDB(ctx context.Context, t *testing.T) *icingadb.DB { - c := &config.Database{} +func GetTestDB(ctx context.Context, t *testing.T) *database.DB { + c := &database.Config{} require.NoError(t, defaults.Set(c), "applying config default should not fail") if v, ok := os.LookupEnv("NOTIFICATIONS_TESTS_DB_TYPE"); ok { @@ -50,7 +49,7 @@ func GetTestDB(ctx context.Context, t *testing.T) *icingadb.DB { require.NoError(t, c.Validate(), "database config validation should not fail") - db, err := c.Open(logging.NewLogger(zaptest.NewLogger(t).Sugar(), time.Hour)) + db, err := database.NewDbFromConfig(c, logging.NewLogger(zaptest.NewLogger(t).Sugar(), time.Hour), database.RetryConnectorCallbacks{}) require.NoError(t, err, "connecting to database should not fail") require.NoError(t, db.PingContext(ctx), "pinging the database should not fail") diff --git a/internal/timeperiod/timeperiod.go b/internal/timeperiod/timeperiod.go index fb2ad6e6..cff97a1a 100644 --- a/internal/timeperiod/timeperiod.go +++ b/internal/timeperiod/timeperiod.go @@ -7,9 +7,9 @@ import ( ) type TimePeriod struct { - ID int64 `db:"id"` - Name string - Entries []*Entry + ID int64 `db:"id"` + Name string `db:"-"` + Entries []*Entry `db:"-"` } func (p *TimePeriod) TableName() string { diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 40c27578..7d05c736 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -5,10 +5,8 @@ import ( "context" "database/sql" "fmt" - "github.com/icinga/icingadb/pkg/driver" - "github.com/icinga/icingadb/pkg/icingadb" - "github.com/icinga/icingadb/pkg/types" - "github.com/icinga/icingadb/pkg/utils" + "github.com/icinga/icinga-go-library/database" + "github.com/icinga/icinga-go-library/types" "github.com/jmoiron/sqlx" "github.com/pkg/errors" "slices" @@ -16,7 +14,7 @@ import ( ) // BuildInsertStmtWithout builds an insert stmt without the provided column. -func BuildInsertStmtWithout(db *icingadb.DB, into interface{}, withoutColumn string) string { +func BuildInsertStmtWithout(db *database.DB, into interface{}, withoutColumn string) string { columns := db.BuildColumns(into) for i, column := range columns { if column == withoutColumn { @@ -28,7 +26,7 @@ func BuildInsertStmtWithout(db *icingadb.DB, into interface{}, withoutColumn str return fmt.Sprintf( `INSERT INTO "%s" ("%s") VALUES (%s)`, - utils.TableName(into), strings.Join(columns, `", "`), + database.TableName(into), strings.Join(columns, `", "`), fmt.Sprintf(":%s", strings.Join(columns, ", :")), ) } @@ -38,7 +36,7 @@ func BuildInsertStmtWithout(db *icingadb.DB, into interface{}, withoutColumn str // A new transaction is started on db which is then passed to fn. After fn returns, the transaction is // committed unless an error was returned. If fn returns an error, that error is returned, otherwise an // error is returned if a database operation fails. -func RunInTx(ctx context.Context, db *icingadb.DB, fn func(tx *sqlx.Tx) error) error { +func RunInTx(ctx context.Context, db *database.DB, fn func(tx *sqlx.Tx) error) error { tx, err := db.BeginTxx(ctx, nil) if err != nil { return err @@ -56,7 +54,7 @@ func RunInTx(ctx context.Context, db *icingadb.DB, fn func(tx *sqlx.Tx) error) e // InsertAndFetchId executes the given query and fetches the last inserted ID. func InsertAndFetchId(ctx context.Context, tx *sqlx.Tx, stmt string, args any) (int64, error) { var lastInsertId int64 - if tx.DriverName() == driver.PostgreSQL { + if tx.DriverName() == database.PostgreSQL { preparedStmt, err := tx.PrepareNamedContext(ctx, stmt+" RETURNING id") if err != nil { return 0, err @@ -85,9 +83,9 @@ func InsertAndFetchId(ctx context.Context, tx *sqlx.Tx, stmt string, args any) ( // ForEachRow applies the provided restoreFunc callback for each successfully retrieved row of the specified type. // It will bulk SELECT the data from the database scoped to the specified ids and scans into the provided Row type. // Returns error on any database failure or fails to acquire the table semaphore. -func ForEachRow[Row, Id any](ctx context.Context, db *icingadb.DB, idColumn string, ids []Id, restoreFunc func(*Row)) error { +func ForEachRow[Row, Id any](ctx context.Context, db *database.DB, idColumn string, ids []Id, restoreFunc func(*Row)) error { subject := new(Row) - table := utils.TableName(subject) + table := database.TableName(subject) sem := db.GetSemaphoreForTable(table) if err := sem.Acquire(ctx, 1); err != nil { return errors.Wrapf(err, "cannot acquire semaphore for table %q", table) @@ -141,25 +139,6 @@ func ToDBInt(value int64) types.Int { return val } -func RemoveIf[T any](slice []T, pred func(T) bool) []T { - n := len(slice) - - for i := 0; i < n; i++ { - for i < n && pred(slice[i]) { - n-- - slice[i], slice[n] = slice[n], slice[i] - } - } - - return slice[:n] -} - -func RemoveNils[T any](slice []*T) []*T { - return RemoveIf(slice, func(ptr *T) bool { - return ptr == nil - }) -} - // IterateOrderedMap implements iter.Seq2 to iterate over a map in the key's order. // // This function returns a func yielding key-value-pairs from a given map in the order of their keys, if their type diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index a668d8d2..d3b474a5 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -5,28 +5,6 @@ import ( "testing" ) -func TestRemoveNils(t *testing.T) { - var a, b, c, d int - - tests := []struct { - name string - in []*int - want []*int - }{ - {"Empty", []*int{}, []*int{}}, - {"SingleKeep", []*int{&a}, []*int{&a}}, - {"SingleRemove", []*int{nil}, []*int{}}, - {"KeepOrder", []*int{&a, &b, &c, &d}, []*int{&a, &b, &c, &d}}, - {"Duplicates", []*int{&a, &b, &b}, []*int{&a, &b, &b}}, - {"Mixed", []*int{&a, nil, &b, nil, nil, &b, nil, &d}, []*int{&a, &b, &b, &d}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.want, RemoveNils(tt.in)) - }) - } -} - func TestIterateOrderedMap(t *testing.T) { tests := []struct { name string diff --git a/internal/version.go b/internal/version.go index ad8b3be1..45eeb114 100644 --- a/internal/version.go +++ b/internal/version.go @@ -1,6 +1,6 @@ package internal -import "github.com/icinga/icingadb/pkg/version" +import "github.com/icinga/icinga-go-library/version" // Version contains version and Git commit information. // diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 9d3d1923..0db44155 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -4,10 +4,10 @@ import ( "encoding/json" "errors" "fmt" + "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-notifications/internal/event" "github.com/icinga/icinga-notifications/internal/utils" "github.com/icinga/icinga-notifications/pkg/rpc" - "github.com/icinga/icingadb/pkg/types" "io" "log" "os"