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).
129 lines
3.9 KiB
Go
129 lines
3.9 KiB
Go
package sqlmigration
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"log/slog"
|
|
|
|
"github.com/hanzoai/o11y/pkg/errors"
|
|
"github.com/hanzoai/o11y/pkg/factory"
|
|
"github.com/hanzoai/o11y/pkg/sqlstore"
|
|
"github.com/uptrace/bun"
|
|
"github.com/uptrace/bun/migrate"
|
|
)
|
|
|
|
type migrateRecurrenceBounds struct {
|
|
sqlstore sqlstore.SQLStore
|
|
logger *slog.Logger
|
|
}
|
|
|
|
type plannedMaintenanceScheduleRow struct {
|
|
bun.BaseModel `bun:"table:planned_maintenance"`
|
|
|
|
ID string `bun:"id"`
|
|
Schedule string `bun:"schedule"`
|
|
}
|
|
|
|
func NewMigrateRecurrenceBoundsFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
|
return factory.NewProviderFactory(
|
|
factory.MustNewName("migrate_recurrence_bounds"),
|
|
func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
|
return &migrateRecurrenceBounds{sqlstore: sqlstore, logger: ps.Logger}, nil
|
|
},
|
|
)
|
|
}
|
|
|
|
func (migration *migrateRecurrenceBounds) Register(migrations *migrate.Migrations) error {
|
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Up moves the start/end bounds of a recurring planned maintenance from the
|
|
// nested recurrence object up to the schedule level. Until now both the
|
|
// schedule and its recurrence carried their own startTime/endTime, with the
|
|
// recurrence values taking precedence when a recurrence was present. The
|
|
// recurrence fields are being dropped, so the recurrence bounds (the source of
|
|
// truth for recurring maintenances) are promoted to the schedule before the
|
|
// struct loses those fields.
|
|
//
|
|
// We deliberately operate on the raw JSON instead of the Recurrence struct:
|
|
// that struct loses its StartTime/EndTime fields in the same change set, so it
|
|
// can no longer read the values this migration needs to move.
|
|
func (migration *migrateRecurrenceBounds) Up(ctx context.Context, db *bun.DB) error {
|
|
tx, err := db.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() {
|
|
_ = tx.Rollback()
|
|
}()
|
|
|
|
rows := make([]*plannedMaintenanceScheduleRow, 0)
|
|
if err := tx.NewSelect().Model(&rows).Scan(ctx); err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, row := range rows {
|
|
schedule := make(map[string]json.RawMessage)
|
|
if err := json.Unmarshal([]byte(row.Schedule), &schedule); err != nil {
|
|
// A single corrupt row must not abort the whole migration (which would block startup).
|
|
migration.logger.WarnContext(ctx, "skipping planned maintenance with unreadable schedule", slog.String("maintenance_id", row.ID), errors.Attr(err))
|
|
continue
|
|
}
|
|
|
|
recurrenceRaw, ok := schedule["recurrence"]
|
|
if !ok || string(recurrenceRaw) == "null" {
|
|
continue
|
|
}
|
|
|
|
recurrence := make(map[string]json.RawMessage)
|
|
if err := json.Unmarshal(recurrenceRaw, &recurrence); err != nil {
|
|
migration.logger.WarnContext(ctx, "skipping planned maintenance with unreadable recurrence", slog.String("maintenance_id", row.ID), errors.Attr(err))
|
|
continue
|
|
}
|
|
|
|
// Promote the recurrence bounds (source of truth) to the schedule
|
|
// level, then drop them from the recurrence.
|
|
if startTime, ok := recurrence["startTime"]; ok {
|
|
schedule["startTime"] = startTime
|
|
delete(recurrence, "startTime")
|
|
}
|
|
if endTime, ok := recurrence["endTime"]; ok && string(endTime) != "null" {
|
|
schedule["endTime"] = endTime
|
|
} else {
|
|
// The recurrence had no end time, so the schedule must not carry
|
|
// a stale one duplicated by the UI.
|
|
delete(schedule, "endTime")
|
|
}
|
|
delete(recurrence, "endTime")
|
|
|
|
newRecurrence, err := json.Marshal(recurrence)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
schedule["recurrence"] = newRecurrence
|
|
|
|
newSchedule, err := json.Marshal(schedule)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := tx.NewUpdate().
|
|
Model((*plannedMaintenanceScheduleRow)(nil)).
|
|
Set("schedule = ?", string(newSchedule)).
|
|
Where("id = ?", row.ID).
|
|
Exec(ctx); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
func (migration *migrateRecurrenceBounds) Down(context.Context, *bun.DB) error {
|
|
return nil
|
|
}
|