mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-15 12:58:33 +00:00
Re-sync the entire SigNoz-derived Go tree to a clean fork of latest SigNoz main (upstream 3e6339019), eliminating the version-skew that broke `go build ./...` (mixed-era packages, ~14 imported-but-absent packages, partial signoz->o11y / clickhouse->datastore rebrands, self-import cycle, duplicate package decls). - pkg/ + cmd/ wholesale replaced with latest SigNoz; imports rewritten github.com/SigNoz/signoz/ -> github.com/hanzoai/o11y/. - Adopt SigNoz's CURRENT structure (resourcefilter->telemetryresourcefilter, integrationtypes->cloudintegrationtypes, roletypes/grammar/times folded in upstream); old paths dropped. - Fork deps repathed to hanzoai + bumped: signoz-otel-collector v0.144.6, clickhouse-go-mock v0.14.1, govaluate v0.1.0; expr-lang/expr => hanzoai/expr v1.17.8 (replace). go.mod reconciled from latest SigNoz; go.sum re-tidied. - ee/ + cmd/enterprise stripped — o11y stays MIT-only; community edition imports no ee packages. - Preserved o11y additions: module path github.com/hanzoai/o11y, mount.go (cloud.Register/zip mount adapter, HIP-0106), NOTICE + LICENSE (SigNoz §4c attribution retained; upstream pkg files are headerless per SigNoz convention). - Reverted o11y cosmetic renames (o11y*/datastore*) and experimental originals (authz/iamauthz, billing, zapreceiver, zapmetricreceiver) to SigNoz canonical to kill the skew; snapshots retained in git history for re-layering. go build ./... = exit 0. go vet clean except benign "unreachable code" in generated ANTLR parser files (inherited from upstream).
321 lines
7.8 KiB
Go
321 lines
7.8 KiB
Go
package sqlmigration
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/hanzoai/o11y/pkg/alertmanager/alertmanagerserver"
|
|
"github.com/hanzoai/o11y/pkg/factory"
|
|
"github.com/hanzoai/o11y/pkg/sqlstore"
|
|
"github.com/hanzoai/o11y/pkg/types/alertmanagertypes"
|
|
"github.com/prometheus/alertmanager/config"
|
|
"github.com/tidwall/gjson"
|
|
"github.com/uptrace/bun"
|
|
"github.com/uptrace/bun/migrate"
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
type addAlertmanager struct {
|
|
store sqlstore.SQLStore
|
|
}
|
|
|
|
func NewAddAlertmanagerFactory(store sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
|
return factory.NewProviderFactory(factory.MustNewName("add_alertmanager"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
|
return newAddAlertmanager(ctx, ps, c, store)
|
|
})
|
|
}
|
|
|
|
func newAddAlertmanager(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
|
return &addAlertmanager{
|
|
store: store,
|
|
}, nil
|
|
}
|
|
|
|
func (migration *addAlertmanager) Register(migrations *migrate.Migrations) error {
|
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (migration *addAlertmanager) Up(ctx context.Context, db *bun.DB) error {
|
|
tx, err := db.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() {
|
|
_ = tx.Rollback()
|
|
}()
|
|
|
|
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "notification_channels", "deleted"); err != nil {
|
|
return err
|
|
} else if exists {
|
|
if _, err := tx.
|
|
NewDropColumn().
|
|
Table("notification_channels").
|
|
ColumnExpr("deleted").
|
|
Exec(ctx); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "notification_channels", "org_id"); err != nil {
|
|
return err
|
|
} else if !exists {
|
|
if _, err := tx.
|
|
NewAddColumn().
|
|
Table("notification_channels").
|
|
ColumnExpr("org_id TEXT REFERENCES organizations(id) ON DELETE CASCADE").
|
|
Exec(ctx); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if _, err := tx.
|
|
NewCreateTable().
|
|
Model(&struct {
|
|
bun.BaseModel `bun:"table:alertmanager_config"`
|
|
ID uint64 `bun:"id,pk,autoincrement"`
|
|
Config string `bun:"config,notnull,type:text"`
|
|
Hash string `bun:"hash,notnull,type:text"`
|
|
CreatedAt time.Time `bun:"created_at,notnull"`
|
|
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
|
OrgID string `bun:"org_id,notnull,unique"`
|
|
}{}).
|
|
ForeignKey(`("org_id") REFERENCES "organizations" ("id")`).
|
|
IfNotExists().
|
|
Exec(ctx); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := tx.
|
|
NewCreateTable().
|
|
Model(&struct {
|
|
bun.BaseModel `bun:"table:alertmanager_state"`
|
|
ID uint64 `bun:"id,pk,autoincrement"`
|
|
Silences string `bun:"silences,nullzero,type:text"`
|
|
NFLog string `bun:"nflog,nullzero,type:text"`
|
|
CreatedAt time.Time `bun:"created_at,notnull"`
|
|
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
|
OrgID string `bun:"org_id,notnull,unique"`
|
|
}{}).
|
|
ForeignKey(`("org_id") REFERENCES "organizations" ("id")`).
|
|
IfNotExists().
|
|
Exec(ctx); err != nil {
|
|
return err
|
|
}
|
|
|
|
var orgID string
|
|
err = tx.
|
|
NewSelect().
|
|
ColumnExpr("id").
|
|
Table("organizations").
|
|
Limit(1).
|
|
Scan(ctx, &orgID)
|
|
if err != nil {
|
|
if err != sql.ErrNoRows {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err == nil {
|
|
if err := migration.populateOrgIDInChannels(ctx, tx, orgID); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := migration.populateAlertmanagerConfig(ctx, tx, orgID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (migration *addAlertmanager) populateOrgIDInChannels(ctx context.Context, tx bun.Tx, orgID string) error {
|
|
if _, err := tx.
|
|
NewUpdate().
|
|
Table("notification_channels").
|
|
Set("org_id = ?", orgID).
|
|
Where("org_id IS NULL").
|
|
Exec(ctx); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (migration *addAlertmanager) populateAlertmanagerConfig(ctx context.Context, tx bun.Tx, orgID string) error {
|
|
var channels []*alertmanagertypes.Channel
|
|
|
|
err := tx.
|
|
NewSelect().
|
|
Model(&channels).
|
|
Where("org_id = ?", orgID).
|
|
Scan(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var receiversFromChannels []string
|
|
for _, channel := range channels {
|
|
receiversFromChannels = append(receiversFromChannels, channel.Name)
|
|
}
|
|
|
|
type matcher struct {
|
|
bun.BaseModel `bun:"table:rules"`
|
|
ID int `bun:"id,pk"`
|
|
Data string `bun:"data"`
|
|
}
|
|
|
|
matchers := []matcher{}
|
|
|
|
err = tx.
|
|
NewSelect().
|
|
Column("id", "data").
|
|
Model(&matchers).
|
|
Scan(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
matchersMap := make(map[string][]string)
|
|
for _, matcher := range matchers {
|
|
receivers := gjson.Get(matcher.Data, "preferredChannels").Array()
|
|
for _, receiver := range receivers {
|
|
matchersMap[strconv.Itoa(matcher.ID)] = append(matchersMap[strconv.Itoa(matcher.ID)], receiver.String())
|
|
}
|
|
|
|
if len(receivers) == 0 {
|
|
matchersMap[strconv.Itoa(matcher.ID)] = append(matchersMap[strconv.Itoa(matcher.ID)], receiversFromChannels...)
|
|
}
|
|
}
|
|
|
|
for _, channel := range channels {
|
|
if err := migration.msTeamsChannelToMSTeamsV2Channel(channel); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
config, err := alertmanagertypes.NewConfigFromChannels(alertmanagerserver.NewConfig().Global, alertmanagerserver.NewConfig().Route, channels, orgID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for ruleID, receivers := range matchersMap {
|
|
err = config.CreateRuleIDMatcher(ruleID, receivers)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if _, err := tx.
|
|
NewInsert().
|
|
Model(config.StoreableConfig()).
|
|
On("CONFLICT (org_id) DO UPDATE").
|
|
Set("config = ?", config.StoreableConfig().Config).
|
|
Set("hash = ?", config.StoreableConfig().Hash).
|
|
Set("updated_at = ?", config.StoreableConfig().UpdatedAt).
|
|
Exec(ctx); err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, channel := range channels {
|
|
if channel.Type == "msteamsv2" {
|
|
if _, err := tx.
|
|
NewUpdate().
|
|
Model(channel).
|
|
WherePK().
|
|
Exec(ctx); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (migration *addAlertmanager) Down(ctx context.Context, db *bun.DB) error {
|
|
return nil
|
|
}
|
|
|
|
// copy of alertmanagertypes.NewReceiver as it existed
|
|
// when this migration was written.
|
|
func newReceiver(input string) (config.Receiver, error) {
|
|
receiver := config.Receiver{}
|
|
err := json.Unmarshal([]byte(input), &receiver)
|
|
if err != nil {
|
|
return config.Receiver{}, err
|
|
}
|
|
|
|
bytes, err := yaml.Marshal(receiver)
|
|
if err != nil {
|
|
return config.Receiver{}, err
|
|
}
|
|
|
|
receiverWithDefaults := config.Receiver{}
|
|
if err := yaml.Unmarshal(bytes, &receiverWithDefaults); err != nil {
|
|
return config.Receiver{}, err
|
|
}
|
|
|
|
if err := receiverWithDefaults.UnmarshalYAML(func(i interface{}) error { return nil }); err != nil {
|
|
return config.Receiver{}, err
|
|
}
|
|
|
|
return receiverWithDefaults, nil
|
|
}
|
|
|
|
func (migration *addAlertmanager) msTeamsChannelToMSTeamsV2Channel(c *alertmanagertypes.Channel) error {
|
|
if c.Type != "msteams" {
|
|
return nil
|
|
}
|
|
|
|
receiver, err := newReceiver(c.Data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
receiver = migration.msTeamsReceiverToMSTeamsV2Receiver(receiver)
|
|
data, err := json.Marshal(receiver)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Type = "msteamsv2"
|
|
c.Data = string(data)
|
|
c.UpdatedAt = time.Now()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (migration *addAlertmanager) msTeamsReceiverToMSTeamsV2Receiver(receiver config.Receiver) config.Receiver {
|
|
if receiver.MSTeamsConfigs == nil {
|
|
return receiver
|
|
}
|
|
|
|
var msTeamsV2Configs []*config.MSTeamsV2Config
|
|
for _, cfg := range receiver.MSTeamsConfigs {
|
|
msTeamsV2Configs = append(msTeamsV2Configs, &config.MSTeamsV2Config{
|
|
NotifierConfig: cfg.NotifierConfig,
|
|
HTTPConfig: cfg.HTTPConfig,
|
|
WebhookURL: cfg.WebhookURL,
|
|
WebhookURLFile: cfg.WebhookURLFile,
|
|
Title: cfg.Title,
|
|
Text: cfg.Text,
|
|
})
|
|
}
|
|
|
|
receiver.MSTeamsConfigs = nil
|
|
receiver.MSTeamsV2Configs = msTeamsV2Configs
|
|
|
|
return receiver
|
|
}
|