Spanner support enhancements (#101634)
* Adds ability to run integration tests against spanner (by using GRAFANA_TEST_DB=spanner env variable. SPANNER_DB variable then specifies database to use: spannertest, emulator or string like /projects/<project>/instances/<instance>/databases/<db>) * Adds feature to migration dialects to create database from a snapshot, instead of running individual migrations. * Adds first version of Spanner snapshot, prepared from "OSS" migrations. * Uses generated bit-reversed-positive values instead of auto_increment. (As an experiment)
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
//go:build enterprise || pro
|
||||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/ini.v1"
|
||||
"xorm.io/core"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/sqlutil"
|
||||
)
|
||||
|
||||
func setupTestDB(t *testing.T) (*migrator.Migrator, *xorm.Engine) {
|
||||
t.Helper()
|
||||
dbType := sqlutil.GetTestDBType()
|
||||
testDB, err := sqlutil.GetTestDB(dbType)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(testDB.Cleanup)
|
||||
|
||||
x, err := xorm.NewEngine(testDB.DriverName, testDB.ConnStr)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
if err := x.Close(); err != nil {
|
||||
fmt.Printf("failed to close xorm engine: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
err = migrator.NewDialect(x.DriverName()).CleanDB(x)
|
||||
require.NoError(t, err)
|
||||
|
||||
mg := migrator.NewMigrator(x, &setting.Cfg{
|
||||
Logger: log.New("users.test"),
|
||||
Raw: ini.Empty(),
|
||||
})
|
||||
migrations := &OSSMigrations{}
|
||||
migrations.AddMigration(mg)
|
||||
|
||||
err = mg.Start(false, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
return mg, x
|
||||
}
|
||||
|
||||
// This "test" migrates database from scratch, and then generates Spanner DDL statements for re-creating the same database.
|
||||
func TestMigrateToSpannerDialect(t *testing.T) {
|
||||
mg, eng := setupTestDB(t)
|
||||
tables, err := eng.DBMetas()
|
||||
require.NoError(t, err)
|
||||
|
||||
var statements []string
|
||||
|
||||
spannerDialect := migrator.NewSpannerDialect()
|
||||
for _, table := range tables {
|
||||
t := &migrator.Table{
|
||||
Name: table.Name,
|
||||
Columns: nil,
|
||||
PrimaryKeys: table.PrimaryKeys,
|
||||
Indices: nil,
|
||||
}
|
||||
|
||||
for _, c := range table.Columns() {
|
||||
col := &migrator.Column{
|
||||
Name: c.Name,
|
||||
Type: c.SQLType.Name,
|
||||
Length: c.Length,
|
||||
Length2: c.Length2,
|
||||
Nullable: c.Nullable,
|
||||
IsPrimaryKey: c.IsPrimaryKey,
|
||||
IsAutoIncrement: c.IsAutoIncrement,
|
||||
IsLatin: false,
|
||||
Default: c.Default,
|
||||
}
|
||||
if (col.Type == core.Bool || col.Type == core.TinyInt) && c.Default != "" {
|
||||
b, err := strconv.ParseBool(c.Default)
|
||||
if err == nil {
|
||||
// Format bool values as true/false.
|
||||
col.Default = strconv.FormatBool(b)
|
||||
}
|
||||
}
|
||||
t.Columns = append(t.Columns, col)
|
||||
}
|
||||
|
||||
for _, ix := range table.Indexes {
|
||||
nix := &migrator.Index{
|
||||
Name: ix.Name,
|
||||
Type: ix.Type,
|
||||
Cols: ix.Cols,
|
||||
}
|
||||
t.Indices = append(t.Indices, nix)
|
||||
}
|
||||
|
||||
statements = append(statements, spannerDialect.CreateTableSQL(t))
|
||||
|
||||
for _, nix := range t.Indices {
|
||||
if nix.Name != "PRIMARY_KEY" {
|
||||
statements = append(statements, spannerDialect.CreateIndexSQL(table.Name, nix))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
|
||||
require.NoError(t, enc.Encode(statements))
|
||||
fmt.Println()
|
||||
require.NoError(t, enc.Encode(mg.GetMigrationIDs(true)))
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
. "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
@@ -76,7 +77,8 @@ func TestIntegrationMigrationLock(t *testing.T) {
|
||||
}
|
||||
|
||||
dbType := sqlutil.GetTestDBType()
|
||||
if dbType == SQLite {
|
||||
// skip for SQLite and Spanner since there is no database locking (only migrator locking)
|
||||
if dbType == SQLite || dbType == Spanner {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
@@ -233,8 +235,8 @@ func TestMigratorLocking(t *testing.T) {
|
||||
func TestDatabaseLocking(t *testing.T) {
|
||||
dbType := sqlutil.GetTestDBType()
|
||||
|
||||
// skip for SQLite since there is no database locking (only migrator locking)
|
||||
if dbType == SQLite {
|
||||
// skip for SQLite and Spanner since there is no database locking (only migrator locking)
|
||||
if dbType == SQLite || dbType == Spanner {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
|
||||
+11
-11
@@ -38,12 +38,12 @@ func (p *ServiceAccountsSameLoginCrossOrgs) Exec(sess *xorm.Session, mg *migrato
|
||||
case migrator.Postgres:
|
||||
_, err = p.sess.Exec(`
|
||||
UPDATE "user"
|
||||
SET login = 'sa-' || org_id::text || '-' ||
|
||||
CASE
|
||||
WHEN login LIKE 'sa-%' THEN SUBSTRING(login FROM 4)
|
||||
ELSE login
|
||||
END
|
||||
WHERE login IS NOT NULL
|
||||
SET login = 'sa-' || org_id::text || '-' ||
|
||||
CASE
|
||||
WHEN login LIKE 'sa-%' THEN SUBSTRING(login FROM 4)
|
||||
ELSE login
|
||||
END
|
||||
WHERE login IS NOT NULL
|
||||
AND is_service_account = true
|
||||
AND login NOT LIKE 'sa-' || org_id::text || '-%';
|
||||
`)
|
||||
@@ -56,7 +56,7 @@ func (p *ServiceAccountsSameLoginCrossOrgs) Exec(sess *xorm.Session, mg *migrato
|
||||
ELSE login
|
||||
END
|
||||
)
|
||||
WHERE login IS NOT NULL
|
||||
WHERE login IS NOT NULL
|
||||
AND is_service_account = 1
|
||||
AND login NOT LIKE CONCAT('sa-', org_id, '-%');
|
||||
`)
|
||||
@@ -68,7 +68,7 @@ func (p *ServiceAccountsSameLoginCrossOrgs) Exec(sess *xorm.Session, mg *migrato
|
||||
WHEN SUBSTR(login, 1, 3) = 'sa-' THEN SUBSTR(login, 4)
|
||||
ELSE login
|
||||
END
|
||||
WHERE login IS NOT NULL
|
||||
WHERE login IS NOT NULL
|
||||
AND is_service_account = 1
|
||||
AND login NOT LIKE 'sa-' || CAST(org_id AS TEXT) || '-%';
|
||||
`)
|
||||
@@ -96,7 +96,7 @@ func (p *ServiceAccountsDeduplicateOrgInLogin) Exec(sess *xorm.Session, mg *migr
|
||||
_, err = sess.Exec(`
|
||||
UPDATE "user" AS u
|
||||
SET login = 'sa-' || org_id::text || SUBSTRING(login FROM LENGTH('sa-' || org_id::text || '-' || org_id::text)+1)
|
||||
WHERE login IS NOT NULL
|
||||
WHERE login IS NOT NULL
|
||||
AND is_service_account = true
|
||||
AND login LIKE 'sa-' || org_id::text || '-' || org_id::text || '-%'
|
||||
AND NOT EXISTS (
|
||||
@@ -123,8 +123,8 @@ func (p *ServiceAccountsDeduplicateOrgInLogin) Exec(sess *xorm.Session, mg *migr
|
||||
AND u.is_service_account = 1
|
||||
AND u.login LIKE 'sa-'||CAST(u.org_id AS TEXT)||'-'||CAST(u.org_id AS TEXT)||'-%'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM ` + dialect.Quote("user") + `AS u2
|
||||
SELECT 1
|
||||
FROM ` + dialect.Quote("user") + `AS u2
|
||||
WHERE u2.login = 'sa-' || CAST(u.org_id AS TEXT) || SUBSTRING(u.login, LENGTH('sa-'||CAST(u.org_id AS TEXT)||'-'||CAST(u.org_id AS TEXT))+1)
|
||||
);;
|
||||
`)
|
||||
|
||||
@@ -6,8 +6,9 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/session"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/session"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
@@ -68,6 +69,10 @@ type Dialect interface {
|
||||
CleanDB(engine *xorm.Engine) error
|
||||
TruncateDBTables(engine *xorm.Engine) error
|
||||
NoOpSQL() string
|
||||
// CreateDatabaseFromSnapshot is called when migration log table is not found.
|
||||
// Dialect can recreate all tables from existing snapshot. After successful (nil error) return,
|
||||
// migrator will list migrations from the log, and apply all missing migrations.
|
||||
CreateDatabaseFromSnapshot(ctx context.Context, engine *xorm.Engine, migrationLogTableName string) error
|
||||
|
||||
IsUniqueConstraintViolation(err error) bool
|
||||
ErrorMessage(err error) string
|
||||
@@ -338,6 +343,10 @@ func (b *BaseDialect) CleanDB(engine *xorm.Engine) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BaseDialect) CreateDatabaseFromSnapshot(ctx context.Context, engine *xorm.Engine, tableName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BaseDialect) NoOpSQL() string {
|
||||
return "SELECT 0;"
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
@@ -161,16 +162,7 @@ func (mg *Migrator) GetMigrationIDs(excludeNotLogged bool) []string {
|
||||
func (mg *Migrator) GetMigrationLog() (map[string]MigrationLog, error) {
|
||||
logMap := make(map[string]MigrationLog)
|
||||
logItems := make([]MigrationLog, 0)
|
||||
|
||||
exists, err := mg.DBEngine.IsTableExist(mg.tableName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%v: %w", "failed to check table existence", err)
|
||||
}
|
||||
if !exists {
|
||||
return logMap, nil
|
||||
}
|
||||
|
||||
if err = mg.DBEngine.Table(mg.tableName).Find(&logItems); err != nil {
|
||||
if err := mg.DBEngine.Table(mg.tableName).Find(&logItems); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -246,9 +238,29 @@ func (mg *Migrator) run(ctx context.Context) (err error) {
|
||||
|
||||
logger.Info("Starting DB migrations")
|
||||
|
||||
_, err = mg.GetMigrationLog()
|
||||
migrationLogExists, err := mg.DBEngine.IsTableExist(mg.tableName)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("%v: %w", "failed to check table existence", err)
|
||||
}
|
||||
|
||||
if !migrationLogExists {
|
||||
// Check if dialect can initialize database from a snapshot.
|
||||
err := mg.Dialect.CreateDatabaseFromSnapshot(ctx, mg.DBEngine, mg.tableName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v: %w", "failed to create database from snapshot", err)
|
||||
}
|
||||
|
||||
migrationLogExists, err = mg.DBEngine.IsTableExist(mg.tableName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v: %w", "failed to check table existence after applying snapshot", err)
|
||||
}
|
||||
}
|
||||
|
||||
if migrationLogExists {
|
||||
_, err = mg.GetMigrationLog()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
successLabel := prometheus.Labels{"success": "true"}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
[
|
||||
"CREATE TABLE `alert` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `version` INT64 NOT NULL, `dashboard_id` INT64 NOT NULL, `panel_id` INT64 NOT NULL, `org_id` INT64 NOT NULL, `name` STRING(255) NOT NULL, `message` STRING(MAX) NOT NULL, `state` STRING(190) NOT NULL, `settings` STRING(MAX), `frequency` INT64 NOT NULL, `handler` INT64 NOT NULL, `severity` STRING(MAX) NOT NULL, `silenced` BOOL NOT NULL, `execution_error` STRING(MAX) NOT NULL, `eval_data` STRING(MAX), `eval_date` TIMESTAMP, `new_state_date` TIMESTAMP NOT NULL, `state_changes` INT64 NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `for` INT64) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_alert_dashboard_id` ON `alert` (dashboard_id)",
|
||||
"CREATE INDEX `IDX_alert_org_id_id` ON `alert` (org_id, id)",
|
||||
"CREATE INDEX `IDX_alert_state` ON `alert` (state)",
|
||||
"CREATE TABLE `alert_configuration` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `alertmanager_configuration` STRING(MAX), `configuration_version` STRING(3) NOT NULL, `created_at` INT64 NOT NULL, `default` BOOL NOT NULL DEFAULT (false), `org_id` INT64 NOT NULL DEFAULT (0), `configuration_hash` STRING(32) NOT NULL DEFAULT ('not-yet-calculated')) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_configuration_org_id` ON `alert_configuration` (org_id)",
|
||||
"CREATE TABLE `alert_configuration_history` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL DEFAULT (0), `alertmanager_configuration` STRING(MAX) NOT NULL, `configuration_hash` STRING(32) NOT NULL DEFAULT ('not-yet-calculated'), `configuration_version` STRING(3) NOT NULL, `created_at` INT64 NOT NULL, `default` BOOL NOT NULL DEFAULT (false), `last_applied` INT64 NOT NULL DEFAULT (0)) PRIMARY KEY (id)",
|
||||
"CREATE TABLE `alert_image` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `token` STRING(190) NOT NULL, `path` STRING(190) NOT NULL, `url` STRING(2048) NOT NULL, `created_at` TIMESTAMP NOT NULL, `expires_at` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_image_token` ON `alert_image` (token)",
|
||||
"CREATE TABLE `alert_instance` (`rule_org_id` INT64 NOT NULL, `rule_uid` STRING(40) NOT NULL, `labels` STRING(MAX) NOT NULL, `labels_hash` STRING(190) NOT NULL, `current_state` STRING(190) NOT NULL, `current_state_since` INT64 NOT NULL, `last_eval_time` INT64 NOT NULL, `current_state_end` INT64 NOT NULL DEFAULT (0), `current_reason` STRING(190), `result_fingerprint` STRING(16), `resolved_at` INT64, `last_sent_at` INT64) PRIMARY KEY (rule_org_id,rule_uid,labels_hash)",
|
||||
"CREATE INDEX `IDX_alert_instance_rule_org_id_rule_uid_current_state` ON `alert_instance` (rule_org_id, rule_uid, current_state)",
|
||||
"CREATE INDEX `IDX_alert_instance_rule_org_id_current_state` ON `alert_instance` (rule_org_id, current_state)",
|
||||
"CREATE TABLE `alert_notification` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `name` STRING(190) NOT NULL, `type` STRING(255) NOT NULL, `settings` STRING(MAX) NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `is_default` BOOL NOT NULL DEFAULT (false), `frequency` INT64, `send_reminder` BOOL DEFAULT (false), `disable_resolve_message` BOOL NOT NULL DEFAULT (false), `uid` STRING(40), `secure_settings` STRING(MAX)) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_notification_org_id_uid` ON `alert_notification` (org_id, uid)",
|
||||
"CREATE TABLE `alert_notification_state` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `alert_id` INT64 NOT NULL, `notifier_id` INT64 NOT NULL, `state` STRING(50) NOT NULL, `version` INT64 NOT NULL, `updated_at` INT64 NOT NULL, `alert_rule_state_updated_version` INT64 NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_alert_notification_state_alert_id` ON `alert_notification_state` (alert_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_notification_state_org_id_alert_id_notifier_id` ON `alert_notification_state` (org_id, alert_id, notifier_id)",
|
||||
"CREATE TABLE `alert_rule` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `title` STRING(190) NOT NULL, `condition` STRING(190) NOT NULL, `data` STRING(MAX), `updated` TIMESTAMP NOT NULL, `interval_seconds` INT64 NOT NULL DEFAULT (60), `version` INT64 NOT NULL DEFAULT (0), `uid` STRING(40) NOT NULL DEFAULT ('0'), `namespace_uid` STRING(40) NOT NULL, `rule_group` STRING(190) NOT NULL, `no_data_state` STRING(15) NOT NULL DEFAULT ('NoData'), `exec_err_state` STRING(15) NOT NULL DEFAULT ('Alerting'), `for` INT64 NOT NULL DEFAULT (0), `annotations` STRING(MAX), `labels` STRING(MAX), `dashboard_uid` STRING(40), `panel_id` INT64, `rule_group_idx` INT64 NOT NULL DEFAULT (1), `is_paused` BOOL NOT NULL DEFAULT (false), `notification_settings` STRING(MAX), `record` STRING(MAX), `metadata` STRING(MAX), `updated_by` STRING(40), `guid` STRING(36) NOT NULL DEFAULT ('')) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_alert_rule_org_id_dashboard_uid_panel_id` ON `alert_rule` (org_id, dashboard_uid, panel_id)",
|
||||
"CREATE INDEX `IDX_alert_rule_org_id_namespace_uid_rule_group` ON `alert_rule` (org_id, namespace_uid, rule_group)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_rule_guid` ON `alert_rule` (guid)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_rule_org_id_namespace_uid_title` ON `alert_rule` (org_id, namespace_uid, title)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_rule_org_id_uid` ON `alert_rule` (org_id, uid)",
|
||||
"CREATE TABLE `alert_rule_state` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `rule_uid` STRING(40) NOT NULL, `data` BYTES(MAX) NOT NULL, `updated_at` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_rule_state_org_id_rule_uid` ON `alert_rule_state` (org_id, rule_uid)",
|
||||
"CREATE TABLE `alert_rule_tag` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `alert_id` INT64 NOT NULL, `tag_id` INT64 NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_alert_rule_tag_alert_id` ON `alert_rule_tag` (alert_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_rule_tag_alert_id_tag_id` ON `alert_rule_tag` (alert_id, tag_id)",
|
||||
"CREATE TABLE `alert_rule_version` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `rule_org_id` INT64 NOT NULL, `rule_uid` STRING(40) NOT NULL DEFAULT ('0'), `rule_namespace_uid` STRING(40) NOT NULL, `rule_group` STRING(190) NOT NULL, `parent_version` INT64 NOT NULL, `restored_from` INT64 NOT NULL, `version` INT64 NOT NULL, `created` TIMESTAMP NOT NULL, `title` STRING(190) NOT NULL, `condition` STRING(190) NOT NULL, `data` STRING(MAX), `interval_seconds` INT64 NOT NULL, `no_data_state` STRING(15) NOT NULL DEFAULT ('NoData'), `exec_err_state` STRING(15) NOT NULL DEFAULT ('Alerting'), `for` INT64 NOT NULL DEFAULT (0), `annotations` STRING(MAX), `labels` STRING(MAX), `rule_group_idx` INT64 NOT NULL DEFAULT (1), `is_paused` BOOL NOT NULL DEFAULT (false), `notification_settings` STRING(MAX), `record` STRING(MAX), `metadata` STRING(MAX), `created_by` STRING(40), `rule_guid` STRING(36) NOT NULL DEFAULT ('')) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_alert_rule_version_rule_org_id_rule_namespace_uid_rule_group` ON `alert_rule_version` (rule_org_id, rule_namespace_uid, rule_group)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_rule_version_rule_guid_version` ON `alert_rule_version` (rule_guid, version)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_alert_rule_version_rule_org_id_rule_uid_rule_guid_version` ON `alert_rule_version` (rule_org_id, rule_uid, rule_guid, version)",
|
||||
"CREATE TABLE `annotation` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `alert_id` INT64, `user_id` INT64, `dashboard_id` INT64, `panel_id` INT64, `category_id` INT64, `type` STRING(25) NOT NULL, `title` STRING(MAX) NOT NULL, `text` STRING(MAX) NOT NULL, `metric` STRING(255), `prev_state` STRING(40) NOT NULL, `new_state` STRING(40) NOT NULL, `data` STRING(MAX) NOT NULL, `epoch` INT64 NOT NULL, `region_id` INT64 DEFAULT (0), `tags` STRING(4096), `created` INT64 DEFAULT (0), `updated` INT64 DEFAULT (0), `epoch_end` INT64 NOT NULL DEFAULT (0)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_annotation_alert_id` ON `annotation` (alert_id)",
|
||||
"CREATE INDEX `IDX_annotation_org_id_alert_id` ON `annotation` (org_id, alert_id)",
|
||||
"CREATE INDEX `IDX_annotation_org_id_created` ON `annotation` (org_id, created)",
|
||||
"CREATE INDEX `IDX_annotation_org_id_dashboard_id_epoch_end_epoch` ON `annotation` (org_id, dashboard_id, epoch_end, epoch)",
|
||||
"CREATE INDEX `IDX_annotation_org_id_epoch_end_epoch` ON `annotation` (org_id, epoch_end, epoch)",
|
||||
"CREATE INDEX `IDX_annotation_org_id_type` ON `annotation` (org_id, type)",
|
||||
"CREATE INDEX `IDX_annotation_org_id_updated` ON `annotation` (org_id, updated)",
|
||||
"CREATE TABLE `annotation_tag` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `annotation_id` INT64 NOT NULL, `tag_id` INT64 NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_annotation_tag_annotation_id_tag_id` ON `annotation_tag` (annotation_id, tag_id)",
|
||||
"CREATE TABLE `anon_device` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `client_ip` STRING(255) NOT NULL, `created_at` TIMESTAMP NOT NULL, `device_id` STRING(127) NOT NULL, `updated_at` TIMESTAMP NOT NULL, `user_agent` STRING(255) NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_anon_device_updated_at` ON `anon_device` (updated_at)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_anon_device_device_id` ON `anon_device` (device_id)",
|
||||
"CREATE TABLE `api_key` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `name` STRING(190) NOT NULL, `key` STRING(190) NOT NULL, `role` STRING(255) NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `expires` INT64, `service_account_id` INT64, `last_used_at` TIMESTAMP, `is_revoked` BOOL DEFAULT (false)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_api_key_org_id` ON `api_key` (org_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_api_key_key` ON `api_key` (key)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_api_key_org_id_name` ON `api_key` (org_id, name)",
|
||||
"CREATE TABLE `builtin_role` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `role` STRING(190) NOT NULL, `role_id` INT64 NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `org_id` INT64 NOT NULL DEFAULT (0)) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_builtin_role_org_id_role_id_role` ON `builtin_role` (org_id, role_id, role)",
|
||||
"CREATE INDEX `IDX_builtin_role_org_id` ON `builtin_role` (org_id)",
|
||||
"CREATE INDEX `IDX_builtin_role_role` ON `builtin_role` (role)",
|
||||
"CREATE INDEX `IDX_builtin_role_role_id` ON `builtin_role` (role_id)",
|
||||
"CREATE TABLE `cache_data` (`cache_key` STRING(168) NOT NULL, `data` BYTES(MAX) NOT NULL, `expires` INT64 NOT NULL, `created_at` INT64 NOT NULL) PRIMARY KEY (cache_key)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_cache_data_cache_key` ON `cache_data` (cache_key)",
|
||||
"CREATE TABLE `cloud_migration_resource` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `uid` STRING(40) NOT NULL, `resource_type` STRING(40) NOT NULL, `resource_uid` STRING(255), `status` STRING(20) NOT NULL, `error_string` STRING(MAX), `snapshot_uid` STRING(40) NOT NULL, `name` STRING(MAX), `parent_name` STRING(MAX), `error_code` STRING(MAX)) PRIMARY KEY (id)",
|
||||
"CREATE TABLE `cloud_migration_session` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `uid` STRING(40), `auth_token` STRING(MAX), `slug` STRING(MAX) NOT NULL, `stack_id` INT64 NOT NULL, `region_slug` STRING(MAX) NOT NULL, `cluster_slug` STRING(MAX) NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `org_id` INT64 NOT NULL DEFAULT (1)) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_cloud_migration_session_uid` ON `cloud_migration_session` (uid)",
|
||||
"CREATE TABLE `cloud_migration_snapshot` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `uid` STRING(40), `session_uid` STRING(40), `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `finished` TIMESTAMP, `upload_url` STRING(MAX), `status` STRING(MAX) NOT NULL, `local_directory` STRING(MAX), `gms_snapshot_uid` STRING(MAX), `encryption_key` STRING(MAX), `error_string` STRING(MAX)) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_cloud_migration_snapshot_uid` ON `cloud_migration_snapshot` (uid)",
|
||||
"CREATE TABLE `correlation` (`uid` STRING(40) NOT NULL, `org_id` INT64 NOT NULL DEFAULT (0), `source_uid` STRING(40) NOT NULL, `target_uid` STRING(40), `label` STRING(MAX) NOT NULL, `description` STRING(MAX) NOT NULL, `config` STRING(MAX), `provisioned` BOOL NOT NULL DEFAULT (false), `type` STRING(40) NOT NULL DEFAULT ('query')) PRIMARY KEY (uid,org_id,source_uid)",
|
||||
"CREATE INDEX `IDX_correlation_source_uid` ON `correlation` (source_uid)",
|
||||
"CREATE INDEX `IDX_correlation_uid` ON `correlation` (uid)",
|
||||
"CREATE INDEX `IDX_correlation_org_id` ON `correlation` (org_id)",
|
||||
"CREATE TABLE `dashboard` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `version` INT64 NOT NULL, `slug` STRING(189) NOT NULL, `title` STRING(189) NOT NULL, `data` STRING(MAX) NOT NULL, `org_id` INT64 NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `updated_by` INT64, `created_by` INT64, `gnet_id` INT64, `plugin_id` STRING(189), `folder_id` INT64 NOT NULL DEFAULT (0), `is_folder` BOOL NOT NULL DEFAULT (false), `has_acl` BOOL NOT NULL DEFAULT (false), `uid` STRING(40), `is_public` BOOL NOT NULL DEFAULT (false), `deleted` TIMESTAMP, `api_version` STRING(16), `folder_uid` STRING(40)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_dashboard_deleted` ON `dashboard` (deleted)",
|
||||
"CREATE INDEX `IDX_dashboard_is_folder` ON `dashboard` (is_folder)",
|
||||
"CREATE INDEX `IDX_dashboard_org_id` ON `dashboard` (org_id)",
|
||||
"CREATE INDEX `IDX_dashboard_org_id_folder_id_title` ON `dashboard` (org_id, folder_id, title)",
|
||||
"CREATE INDEX `IDX_dashboard_org_id_plugin_id` ON `dashboard` (org_id, plugin_id)",
|
||||
"CREATE INDEX `IDX_dashboard_gnet_id` ON `dashboard` (gnet_id)",
|
||||
"CREATE INDEX `IDX_dashboard_title` ON `dashboard` (title)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_dashboard_org_id_uid` ON `dashboard` (org_id, uid)",
|
||||
"CREATE TABLE `dashboard_acl` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `dashboard_id` INT64 NOT NULL, `user_id` INT64, `team_id` INT64, `permission` INT64 NOT NULL DEFAULT (4), `role` STRING(20), `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_dashboard_acl_team_id` ON `dashboard_acl` (team_id)",
|
||||
"CREATE INDEX `IDX_dashboard_acl_user_id` ON `dashboard_acl` (user_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_dashboard_acl_dashboard_id_team_id` ON `dashboard_acl` (dashboard_id, team_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_dashboard_acl_dashboard_id_user_id` ON `dashboard_acl` (dashboard_id, user_id)",
|
||||
"CREATE INDEX `IDX_dashboard_acl_dashboard_id` ON `dashboard_acl` (dashboard_id)",
|
||||
"CREATE INDEX `IDX_dashboard_acl_org_id_role` ON `dashboard_acl` (org_id, role)",
|
||||
"CREATE INDEX `IDX_dashboard_acl_permission` ON `dashboard_acl` (permission)",
|
||||
"CREATE TABLE `dashboard_provisioning` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `dashboard_id` INT64, `name` STRING(150) NOT NULL, `external_id` STRING(MAX) NOT NULL, `updated` INT64 NOT NULL DEFAULT (0), `check_sum` STRING(32)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_dashboard_provisioning_dashboard_id` ON `dashboard_provisioning` (dashboard_id)",
|
||||
"CREATE INDEX `IDX_dashboard_provisioning_dashboard_id_name` ON `dashboard_provisioning` (dashboard_id, name)",
|
||||
"CREATE TABLE `dashboard_public` (`uid` STRING(40) NOT NULL, `dashboard_uid` STRING(40) NOT NULL, `org_id` INT64 NOT NULL, `time_settings` STRING(MAX), `template_variables` STRING(MAX), `access_token` STRING(32) NOT NULL, `created_by` INT64 NOT NULL, `updated_by` INT64, `created_at` TIMESTAMP NOT NULL, `updated_at` TIMESTAMP, `is_enabled` BOOL NOT NULL DEFAULT (false), `annotations_enabled` BOOL NOT NULL DEFAULT (false), `time_selection_enabled` BOOL NOT NULL DEFAULT (false), `share` STRING(64) NOT NULL DEFAULT ('public')) PRIMARY KEY (uid)",
|
||||
"CREATE INDEX `IDX_dashboard_public_config_org_id_dashboard_uid` ON `dashboard_public` (org_id, dashboard_uid)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_dashboard_public_config_access_token` ON `dashboard_public` (access_token)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_dashboard_public_config_uid` ON `dashboard_public` (uid)",
|
||||
"CREATE TABLE `dashboard_snapshot` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `name` STRING(255) NOT NULL, `key` STRING(190) NOT NULL, `delete_key` STRING(190) NOT NULL, `org_id` INT64 NOT NULL, `user_id` INT64 NOT NULL, `external` BOOL NOT NULL, `external_url` STRING(255) NOT NULL, `dashboard` STRING(MAX) NOT NULL, `expires` TIMESTAMP NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `external_delete_url` STRING(255), `dashboard_encrypted` BYTES(MAX)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_dashboard_snapshot_user_id` ON `dashboard_snapshot` (user_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_dashboard_snapshot_delete_key` ON `dashboard_snapshot` (delete_key)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_dashboard_snapshot_key` ON `dashboard_snapshot` (key)",
|
||||
"CREATE TABLE `dashboard_tag` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `dashboard_id` INT64 NOT NULL, `term` STRING(50) NOT NULL, `dashboard_uid` STRING(40), `org_id` INT64 DEFAULT (1)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_dashboard_tag_dashboard_id` ON `dashboard_tag` (dashboard_id)",
|
||||
"CREATE TABLE `dashboard_version` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `dashboard_id` INT64 NOT NULL, `parent_version` INT64 NOT NULL, `restored_from` INT64 NOT NULL, `version` INT64 NOT NULL, `created` TIMESTAMP NOT NULL, `created_by` INT64 NOT NULL, `message` STRING(MAX) NOT NULL, `data` STRING(MAX), `api_version` STRING(16)) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_dashboard_version_dashboard_id_version` ON `dashboard_version` (dashboard_id, version)",
|
||||
"CREATE INDEX `IDX_dashboard_version_dashboard_id` ON `dashboard_version` (dashboard_id)",
|
||||
"CREATE TABLE `data_keys` (`name` STRING(100) NOT NULL, `active` BOOL NOT NULL, `scope` STRING(30) NOT NULL, `provider` STRING(50) NOT NULL, `encrypted_data` BYTES(MAX) NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `label` STRING(100)) PRIMARY KEY (name)",
|
||||
"CREATE TABLE `data_source` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `version` INT64 NOT NULL, `type` STRING(255) NOT NULL, `name` STRING(190) NOT NULL, `access` STRING(255) NOT NULL, `url` STRING(255) NOT NULL, `password` STRING(255), `user` STRING(255), `database` STRING(255), `basic_auth` BOOL NOT NULL, `basic_auth_user` STRING(255), `basic_auth_password` STRING(255), `is_default` BOOL NOT NULL, `json_data` STRING(MAX), `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `with_credentials` BOOL NOT NULL DEFAULT (false), `secure_json_data` STRING(MAX), `read_only` BOOL, `uid` STRING(40) NOT NULL DEFAULT ('0'), `is_prunable` BOOL DEFAULT (false), `api_version` STRING(20)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_data_source_org_id` ON `data_source` (org_id)",
|
||||
"CREATE INDEX `IDX_data_source_org_id_is_default` ON `data_source` (org_id, is_default)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_data_source_org_id_name` ON `data_source` (org_id, name)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_data_source_org_id_uid` ON `data_source` (org_id, uid)",
|
||||
"CREATE TABLE `entity_event` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `entity_id` STRING(1024) NOT NULL, `event_type` STRING(8) NOT NULL, `created` INT64 NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE TABLE `file` (`path` STRING(1024) NOT NULL, `path_hash` STRING(64) NOT NULL, `parent_folder_path_hash` STRING(64) NOT NULL, `contents` BYTES(MAX), `etag` STRING(32) NOT NULL, `cache_control` STRING(128) NOT NULL, `content_disposition` STRING(128) NOT NULL, `updated` TIMESTAMP NOT NULL, `created` TIMESTAMP NOT NULL, `size` INT64 NOT NULL, `mime_type` STRING(255) NOT NULL) PRIMARY KEY (path_hash)",
|
||||
"CREATE INDEX `IDX_file_parent_folder_path_hash` ON `file` (parent_folder_path_hash)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_file_path_hash` ON `file` (path_hash)",
|
||||
"CREATE TABLE `file_meta` (`path_hash` STRING(64) NOT NULL, `key` STRING(191) NOT NULL, `value` STRING(1024) NOT NULL) PRIMARY KEY (path_hash,key)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_file_meta_path_hash_key` ON `file_meta` (path_hash, key)",
|
||||
"CREATE TABLE `folder` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `uid` STRING(40) NOT NULL, `org_id` INT64 NOT NULL, `title` STRING(189) NOT NULL, `description` STRING(255), `parent_uid` STRING(40), `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_folder_org_id_uid` ON `folder` (org_id, uid)",
|
||||
"CREATE TABLE `kv_store` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `namespace` STRING(190) NOT NULL, `key` STRING(190) NOT NULL, `value` STRING(MAX) NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_kv_store_org_id_namespace_key` ON `kv_store` (org_id, namespace, key)",
|
||||
"CREATE TABLE `library_element` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `folder_id` INT64 NOT NULL, `uid` STRING(40) NOT NULL, `name` STRING(150) NOT NULL, `kind` INT64 NOT NULL, `type` STRING(40) NOT NULL, `description` STRING(2048) NOT NULL, `model` STRING(MAX) NOT NULL, `created` TIMESTAMP NOT NULL, `created_by` INT64 NOT NULL, `updated` TIMESTAMP NOT NULL, `updated_by` INT64 NOT NULL, `version` INT64 NOT NULL, `folder_uid` STRING(40)) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_library_element_org_id_folder_id_name_kind` ON `library_element` (org_id, folder_id, name, kind)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_library_element_org_id_folder_uid_name_kind` ON `library_element` (org_id, folder_uid, name, kind)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_library_element_org_id_uid` ON `library_element` (org_id, uid)",
|
||||
"CREATE TABLE `library_element_connection` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `element_id` INT64 NOT NULL, `kind` INT64 NOT NULL, `connection_id` INT64 NOT NULL, `created` TIMESTAMP NOT NULL, `created_by` INT64 NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_library_element_connection_element_id_kind_connection_id` ON `library_element_connection` (element_id, kind, connection_id)",
|
||||
"CREATE TABLE `login_attempt` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `username` STRING(190) NOT NULL, `ip_address` STRING(30) NOT NULL, `created` INT64 NOT NULL DEFAULT (0)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_login_attempt_username` ON `login_attempt` (username)",
|
||||
"CREATE TABLE `migration_log` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `migration_id` STRING(255) NOT NULL, `sql` STRING(MAX) NOT NULL, `success` BOOL NOT NULL, `error` STRING(MAX) NOT NULL, `timestamp` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE TABLE `ngalert_configuration` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `alertmanagers` STRING(MAX), `created_at` INT64 NOT NULL, `updated_at` INT64 NOT NULL, `send_alerts_to` INT64 NOT NULL DEFAULT (0)) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_ngalert_configuration_org_id` ON `ngalert_configuration` (org_id)",
|
||||
"CREATE TABLE `org` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `version` INT64 NOT NULL, `name` STRING(190) NOT NULL, `address1` STRING(255), `address2` STRING(255), `city` STRING(255), `state` STRING(255), `zip_code` STRING(50), `country` STRING(255), `billing_email` STRING(255), `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_org_name` ON `org` (name)",
|
||||
"CREATE TABLE `org_user` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `user_id` INT64 NOT NULL, `role` STRING(20) NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_org_user_org_id_user_id` ON `org_user` (org_id, user_id)",
|
||||
"CREATE INDEX `IDX_org_user_org_id` ON `org_user` (org_id)",
|
||||
"CREATE INDEX `IDX_org_user_user_id` ON `org_user` (user_id)",
|
||||
"CREATE TABLE `permission` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `role_id` INT64 NOT NULL, `action` STRING(190) NOT NULL, `scope` STRING(190) NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `kind` STRING(40) NOT NULL DEFAULT (''), `attribute` STRING(40) NOT NULL DEFAULT (''), `identifier` STRING(40) NOT NULL DEFAULT ('')) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_permission_action_scope_role_id` ON `permission` (action, scope, role_id)",
|
||||
"CREATE INDEX `IDX_permission_identifier` ON `permission` (identifier)",
|
||||
"CREATE INDEX `IDX_permission_role_id` ON `permission` (role_id)",
|
||||
"CREATE TABLE `playlist` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `name` STRING(255) NOT NULL, `interval` STRING(255) NOT NULL, `org_id` INT64 NOT NULL, `created_at` INT64 NOT NULL DEFAULT (0), `updated_at` INT64 NOT NULL DEFAULT (0), `uid` STRING(80) NOT NULL DEFAULT ('0')) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_playlist_org_id_uid` ON `playlist` (org_id, uid)",
|
||||
"CREATE TABLE `playlist_item` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `playlist_id` INT64 NOT NULL, `type` STRING(255) NOT NULL, `value` STRING(MAX) NOT NULL, `title` STRING(MAX) NOT NULL, `order` INT64 NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE TABLE `plugin_setting` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL DEFAULT (1), `plugin_id` STRING(190) NOT NULL, `enabled` BOOL NOT NULL, `pinned` BOOL NOT NULL, `json_data` STRING(MAX), `secure_json_data` STRING(MAX), `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `plugin_version` STRING(50)) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_plugin_setting_org_id_plugin_id` ON `plugin_setting` (org_id, plugin_id)",
|
||||
"CREATE TABLE `preferences` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `user_id` INT64 NOT NULL, `version` INT64 NOT NULL, `home_dashboard_id` INT64 NOT NULL, `timezone` STRING(50) NOT NULL, `theme` STRING(20) NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `team_id` INT64, `week_start` STRING(10), `json_data` STRING(MAX)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_preferences_org_id` ON `preferences` (org_id)",
|
||||
"CREATE INDEX `IDX_preferences_user_id` ON `preferences` (user_id)",
|
||||
"CREATE TABLE `provenance_type` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `record_key` STRING(190) NOT NULL, `record_type` STRING(190) NOT NULL, `provenance` STRING(190) NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_provenance_type_record_type_record_key_org_id` ON `provenance_type` (record_type, record_key, org_id)",
|
||||
"CREATE TABLE `query_history` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `uid` STRING(40) NOT NULL, `org_id` INT64 NOT NULL, `datasource_uid` STRING(40) NOT NULL, `created_by` INT64, `created_at` INT64 NOT NULL, `comment` STRING(MAX) NOT NULL, `queries` STRING(MAX) NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_query_history_org_id_created_by_datasource_uid` ON `query_history` (org_id, created_by, datasource_uid)",
|
||||
"CREATE TABLE `query_history_details` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `query_history_item_uid` STRING(40) NOT NULL, `datasource_uid` STRING(40) NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE TABLE `query_history_star` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `query_uid` STRING(40) NOT NULL, `user_id` INT64, `org_id` INT64 NOT NULL DEFAULT (1)) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_query_history_star_user_id_query_uid` ON `query_history_star` (user_id, query_uid)",
|
||||
"CREATE TABLE `quota` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64, `user_id` INT64, `target` STRING(190) NOT NULL, `limit` INT64 NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_quota_org_id_user_id_target` ON `quota` (org_id, user_id, target)",
|
||||
"CREATE TABLE `role` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `name` STRING(190) NOT NULL, `description` STRING(MAX), `version` INT64 NOT NULL, `org_id` INT64 NOT NULL, `uid` STRING(40) NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `display_name` STRING(190), `group_name` STRING(190), `hidden` BOOL NOT NULL DEFAULT (false)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_role_org_id` ON `role` (org_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_role_org_id_name` ON `role` (org_id, name)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_role_uid` ON `role` (uid)",
|
||||
"CREATE TABLE `secrets` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `namespace` STRING(255) NOT NULL, `type` STRING(255) NOT NULL, `value` STRING(MAX), `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE TABLE `seed_assignment` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `builtin_role` STRING(190) NOT NULL, `role_name` STRING(190), `action` STRING(190), `scope` STRING(190), `origin` STRING(190)) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_seed_assignment_builtin_role_action_scope` ON `seed_assignment` (builtin_role, action, scope)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_seed_assignment_builtin_role_role_name` ON `seed_assignment` (builtin_role, role_name)",
|
||||
"CREATE TABLE `server_lock` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `operation_uid` STRING(100) NOT NULL, `version` INT64 NOT NULL, `last_execution` INT64 NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_server_lock_operation_uid` ON `server_lock` (operation_uid)",
|
||||
"CREATE TABLE `session` (`key` STRING(16) NOT NULL, `data` BYTES(MAX) NOT NULL, `expiry` INT64 NOT NULL) PRIMARY KEY (key)",
|
||||
"CREATE TABLE `short_url` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `uid` STRING(40) NOT NULL, `path` STRING(MAX) NOT NULL, `created_by` INT64, `created_at` INT64 NOT NULL, `last_seen_at` INT64) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_short_url_org_id_uid` ON `short_url` (org_id, uid)",
|
||||
"CREATE TABLE `signing_key` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `key_id` STRING(255) NOT NULL, `private_key` STRING(MAX) NOT NULL, `added_at` TIMESTAMP NOT NULL, `expires_at` TIMESTAMP, `alg` STRING(255) NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_signing_key_key_id` ON `signing_key` (key_id)",
|
||||
"CREATE TABLE `sso_setting` (`id` STRING(40) NOT NULL, `provider` STRING(255) NOT NULL, `settings` STRING(MAX) NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `is_deleted` BOOL NOT NULL DEFAULT (false)) PRIMARY KEY (id)",
|
||||
"CREATE TABLE `star` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `user_id` INT64 NOT NULL, `dashboard_id` INT64 NOT NULL, `dashboard_uid` STRING(40), `org_id` INT64 DEFAULT (1), `updated` TIMESTAMP) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_star_user_id_dashboard_id` ON `star` (user_id, dashboard_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_star_user_id_dashboard_uid_org_id` ON `star` (user_id, dashboard_uid, org_id)",
|
||||
"CREATE TABLE `tag` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `key` STRING(100) NOT NULL, `value` STRING(100) NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_tag_key_value` ON `tag` (key, value)",
|
||||
"CREATE TABLE `team` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `name` STRING(190) NOT NULL, `org_id` INT64 NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `uid` STRING(40), `email` STRING(190)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_team_org_id` ON `team` (org_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_team_org_id_name` ON `team` (org_id, name)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_team_org_id_uid` ON `team` (org_id, uid)",
|
||||
"CREATE TABLE `team_member` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `team_id` INT64 NOT NULL, `user_id` INT64 NOT NULL, `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `external` BOOL, `permission` INT64) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_team_member_org_id_team_id_user_id` ON `team_member` (org_id, team_id, user_id)",
|
||||
"CREATE INDEX `IDX_team_member_org_id` ON `team_member` (org_id)",
|
||||
"CREATE INDEX `IDX_team_member_team_id` ON `team_member` (team_id)",
|
||||
"CREATE INDEX `IDX_team_member_user_id_org_id` ON `team_member` (user_id, org_id)",
|
||||
"CREATE TABLE `team_role` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `team_id` INT64 NOT NULL, `role_id` INT64 NOT NULL, `created` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_team_role_org_id` ON `team_role` (org_id)",
|
||||
"CREATE INDEX `IDX_team_role_team_id` ON `team_role` (team_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_team_role_org_id_team_id_role_id` ON `team_role` (org_id, team_id, role_id)",
|
||||
"CREATE TABLE `temp_user` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `version` INT64 NOT NULL, `email` STRING(190) NOT NULL, `name` STRING(255), `role` STRING(20), `code` STRING(190) NOT NULL, `status` STRING(20) NOT NULL, `invited_by_user_id` INT64, `email_sent` BOOL NOT NULL, `email_sent_on` TIMESTAMP, `remote_addr` STRING(255), `created` INT64 NOT NULL DEFAULT (0), `updated` INT64 NOT NULL DEFAULT (0)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_temp_user_org_id` ON `temp_user` (org_id)",
|
||||
"CREATE INDEX `IDX_temp_user_status` ON `temp_user` (status)",
|
||||
"CREATE INDEX `IDX_temp_user_code` ON `temp_user` (code)",
|
||||
"CREATE INDEX `IDX_temp_user_email` ON `temp_user` (email)",
|
||||
"CREATE TABLE `test_data` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `metric1` STRING(20), `metric2` STRING(150), `value_big_int` INT64, `value_double` FLOAT64, `value_float` FLOAT64, `value_int` INT64, `time_epoch` INT64 NOT NULL, `time_date_time` TIMESTAMP NOT NULL, `time_time_stamp` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE TABLE `user` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `version` INT64 NOT NULL, `login` STRING(190) NOT NULL, `email` STRING(190) NOT NULL, `name` STRING(255), `password` STRING(255), `salt` STRING(50), `rands` STRING(50), `company` STRING(255), `org_id` INT64 NOT NULL, `is_admin` BOOL NOT NULL, `email_verified` BOOL, `theme` STRING(255), `created` TIMESTAMP NOT NULL, `updated` TIMESTAMP NOT NULL, `help_flags1` INT64 NOT NULL DEFAULT (0), `last_seen_at` TIMESTAMP, `is_disabled` BOOL NOT NULL DEFAULT (false), `is_service_account` BOOL DEFAULT (false), `uid` STRING(40), `is_provisioned` BOOL NOT NULL DEFAULT (false)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_user_login_email` ON `user` (login, email)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_user_email` ON `user` (email)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_user_login` ON `user` (login)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_user_uid` ON `user` (uid)",
|
||||
"CREATE TABLE `user_auth` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `user_id` INT64 NOT NULL, `auth_module` STRING(190) NOT NULL, `auth_id` STRING(190), `created` TIMESTAMP NOT NULL, `o_auth_access_token` STRING(MAX), `o_auth_refresh_token` STRING(MAX), `o_auth_token_type` STRING(MAX), `o_auth_expiry` TIMESTAMP, `o_auth_id_token` STRING(MAX)) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_user_auth_auth_module_auth_id` ON `user_auth` (auth_module, auth_id)",
|
||||
"CREATE INDEX `IDX_user_auth_user_id` ON `user_auth` (user_id)",
|
||||
"CREATE TABLE `user_auth_token` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `user_id` INT64 NOT NULL, `auth_token` STRING(100) NOT NULL, `prev_auth_token` STRING(100) NOT NULL, `user_agent` STRING(255) NOT NULL, `client_ip` STRING(255) NOT NULL, `auth_token_seen` BOOL NOT NULL, `seen_at` INT64, `rotated_at` INT64 NOT NULL, `created_at` INT64 NOT NULL, `updated_at` INT64 NOT NULL, `revoked_at` INT64, `external_session_id` INT64) PRIMARY KEY (id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_user_auth_token_auth_token` ON `user_auth_token` (auth_token)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_user_auth_token_prev_auth_token` ON `user_auth_token` (prev_auth_token)",
|
||||
"CREATE INDEX `IDX_user_auth_token_revoked_at` ON `user_auth_token` (revoked_at)",
|
||||
"CREATE INDEX `IDX_user_auth_token_user_id` ON `user_auth_token` (user_id)",
|
||||
"CREATE TABLE `user_external_session` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `user_auth_id` INT64 NOT NULL, `user_id` INT64 NOT NULL, `auth_module` STRING(190) NOT NULL, `access_token` STRING(MAX), `id_token` STRING(MAX), `refresh_token` STRING(MAX), `session_id` STRING(1024), `session_id_hash` STRING(44), `name_id` STRING(1024), `name_id_hash` STRING(44), `expires_at` TIMESTAMP, `created_at` TIMESTAMP NOT NULL) PRIMARY KEY (id)",
|
||||
"CREATE TABLE `user_role` (`id` INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), `org_id` INT64 NOT NULL, `user_id` INT64 NOT NULL, `role_id` INT64 NOT NULL, `created` TIMESTAMP NOT NULL, `group_mapping_uid` STRING(40) DEFAULT ('')) PRIMARY KEY (id)",
|
||||
"CREATE INDEX `IDX_user_role_org_id` ON `user_role` (org_id)",
|
||||
"CREATE INDEX `IDX_user_role_user_id` ON `user_role` (user_id)",
|
||||
"CREATE UNIQUE NULL_FILTERED INDEX `UQE_user_role_org_id_user_id_role_id_group_mapping_uid` ON `user_role` (org_id, user_id, role_id, group_mapping_uid)"
|
||||
]
|
||||
@@ -0,0 +1,644 @@
|
||||
[
|
||||
"create migration_log table",
|
||||
"create user table",
|
||||
"add unique index user.login",
|
||||
"add unique index user.email",
|
||||
"drop index UQE_user_login - v1",
|
||||
"drop index UQE_user_email - v1",
|
||||
"Rename table user to user_v1 - v1",
|
||||
"create user table v2",
|
||||
"create index UQE_user_login - v2",
|
||||
"create index UQE_user_email - v2",
|
||||
"copy data_source v1 to v2",
|
||||
"Drop old table user_v1",
|
||||
"Add column help_flags1 to user table",
|
||||
"Update user table charset",
|
||||
"Add last_seen_at column to user",
|
||||
"Add missing user data",
|
||||
"Add is_disabled column to user",
|
||||
"Add index user.login/user.email",
|
||||
"Add is_service_account column to user",
|
||||
"Update is_service_account column to nullable",
|
||||
"Add uid column to user",
|
||||
"Update uid column values for users",
|
||||
"Add unique index user_uid",
|
||||
"Add is_provisioned column to user",
|
||||
"update login field with orgid to allow for multiple service accounts with same name across orgs",
|
||||
"update service accounts login field orgid to appear only once",
|
||||
"update login and email fields to lowercase",
|
||||
"update login and email fields to lowercase2",
|
||||
"create temp user table v1-7",
|
||||
"create index IDX_temp_user_email - v1-7",
|
||||
"create index IDX_temp_user_org_id - v1-7",
|
||||
"create index IDX_temp_user_code - v1-7",
|
||||
"create index IDX_temp_user_status - v1-7",
|
||||
"Update temp_user table charset",
|
||||
"drop index IDX_temp_user_email - v1",
|
||||
"drop index IDX_temp_user_org_id - v1",
|
||||
"drop index IDX_temp_user_code - v1",
|
||||
"drop index IDX_temp_user_status - v1",
|
||||
"Rename table temp_user to temp_user_tmp_qwerty - v1",
|
||||
"create temp_user v2",
|
||||
"create index IDX_temp_user_email - v2",
|
||||
"create index IDX_temp_user_org_id - v2",
|
||||
"create index IDX_temp_user_code - v2",
|
||||
"create index IDX_temp_user_status - v2",
|
||||
"copy temp_user v1 to v2",
|
||||
"drop temp_user_tmp_qwerty",
|
||||
"Set created for temp users that will otherwise prematurely expire",
|
||||
"create star table",
|
||||
"add unique index star.user_id_dashboard_id",
|
||||
"Add column dashboard_uid in star",
|
||||
"Add column org_id in star",
|
||||
"Add column updated in star",
|
||||
"add index in star table on dashboard_uid, org_id and user_id columns",
|
||||
"create org table v1",
|
||||
"create index UQE_org_name - v1",
|
||||
"create org_user table v1",
|
||||
"create index IDX_org_user_org_id - v1",
|
||||
"create index UQE_org_user_org_id_user_id - v1",
|
||||
"create index IDX_org_user_user_id - v1",
|
||||
"Update org table charset",
|
||||
"Update org_user table charset",
|
||||
"Migrate all Read Only Viewers to Viewers",
|
||||
"create dashboard table",
|
||||
"add index dashboard.account_id",
|
||||
"add unique index dashboard_account_id_slug",
|
||||
"create dashboard_tag table",
|
||||
"add unique index dashboard_tag.dasboard_id_term",
|
||||
"drop index UQE_dashboard_tag_dashboard_id_term - v1",
|
||||
"Rename table dashboard to dashboard_v1 - v1",
|
||||
"create dashboard v2",
|
||||
"create index IDX_dashboard_org_id - v2",
|
||||
"create index UQE_dashboard_org_id_slug - v2",
|
||||
"copy dashboard v1 to v2",
|
||||
"drop table dashboard_v1",
|
||||
"alter dashboard.data to mediumtext v1",
|
||||
"Add column updated_by in dashboard - v2",
|
||||
"Add column created_by in dashboard - v2",
|
||||
"Add column gnetId in dashboard",
|
||||
"Add index for gnetId in dashboard",
|
||||
"Add column plugin_id in dashboard",
|
||||
"Add index for plugin_id in dashboard",
|
||||
"Add index for dashboard_id in dashboard_tag",
|
||||
"Update dashboard table charset",
|
||||
"Update dashboard_tag table charset",
|
||||
"Add column folder_id in dashboard",
|
||||
"Add column isFolder in dashboard",
|
||||
"Add column has_acl in dashboard",
|
||||
"Add column uid in dashboard",
|
||||
"Update uid column values in dashboard",
|
||||
"Add unique index dashboard_org_id_uid",
|
||||
"Remove unique index org_id_slug",
|
||||
"Update dashboard title length",
|
||||
"Add unique index for dashboard_org_id_title_folder_id",
|
||||
"create dashboard_provisioning",
|
||||
"Rename table dashboard_provisioning to dashboard_provisioning_tmp_qwerty - v1",
|
||||
"create dashboard_provisioning v2",
|
||||
"create index IDX_dashboard_provisioning_dashboard_id - v2",
|
||||
"create index IDX_dashboard_provisioning_dashboard_id_name - v2",
|
||||
"copy dashboard_provisioning v1 to v2",
|
||||
"drop dashboard_provisioning_tmp_qwerty",
|
||||
"Add check_sum column",
|
||||
"Add index for dashboard_title",
|
||||
"delete tags for deleted dashboards",
|
||||
"delete stars for deleted dashboards",
|
||||
"Add index for dashboard_is_folder",
|
||||
"Add isPublic for dashboard",
|
||||
"Add deleted for dashboard",
|
||||
"Add index for deleted",
|
||||
"Add column dashboard_uid in dashboard_tag",
|
||||
"Add column org_id in dashboard_tag",
|
||||
"Add missing dashboard_uid and org_id to dashboard_tag",
|
||||
"Add apiVersion for dashboard",
|
||||
"Add missing dashboard_uid and org_id to star",
|
||||
"create data_source table",
|
||||
"add index data_source.account_id",
|
||||
"add unique index data_source.account_id_name",
|
||||
"drop index IDX_data_source_account_id - v1",
|
||||
"drop index UQE_data_source_account_id_name - v1",
|
||||
"Rename table data_source to data_source_v1 - v1",
|
||||
"create data_source table v2",
|
||||
"create index IDX_data_source_org_id - v2",
|
||||
"create index UQE_data_source_org_id_name - v2",
|
||||
"Drop old table data_source_v1 #2",
|
||||
"Add column with_credentials",
|
||||
"Add secure json data column",
|
||||
"Update data_source table charset",
|
||||
"Update initial version to 1",
|
||||
"Add read_only data column",
|
||||
"Migrate logging ds to loki ds",
|
||||
"Update json_data with nulls",
|
||||
"Add uid column",
|
||||
"Update uid value",
|
||||
"Add unique index datasource_org_id_uid",
|
||||
"add unique index datasource_org_id_is_default",
|
||||
"Add is_prunable column",
|
||||
"Add api_version column",
|
||||
"create api_key table",
|
||||
"add index api_key.account_id",
|
||||
"add index api_key.key",
|
||||
"add index api_key.account_id_name",
|
||||
"drop index IDX_api_key_account_id - v1",
|
||||
"drop index UQE_api_key_key - v1",
|
||||
"drop index UQE_api_key_account_id_name - v1",
|
||||
"Rename table api_key to api_key_v1 - v1",
|
||||
"create api_key table v2",
|
||||
"create index IDX_api_key_org_id - v2",
|
||||
"create index UQE_api_key_key - v2",
|
||||
"create index UQE_api_key_org_id_name - v2",
|
||||
"copy api_key v1 to v2",
|
||||
"Drop old table api_key_v1",
|
||||
"Update api_key table charset",
|
||||
"Add expires to api_key table",
|
||||
"Add service account foreign key",
|
||||
"set service account foreign key to nil if 0",
|
||||
"Add last_used_at to api_key table",
|
||||
"Add is_revoked column to api_key table",
|
||||
"create dashboard_snapshot table v4",
|
||||
"drop table dashboard_snapshot_v4 #1",
|
||||
"create dashboard_snapshot table v5 #2",
|
||||
"create index UQE_dashboard_snapshot_key - v5",
|
||||
"create index UQE_dashboard_snapshot_delete_key - v5",
|
||||
"create index IDX_dashboard_snapshot_user_id - v5",
|
||||
"alter dashboard_snapshot to mediumtext v2",
|
||||
"Update dashboard_snapshot table charset",
|
||||
"Add column external_delete_url to dashboard_snapshots table",
|
||||
"Add encrypted dashboard json column",
|
||||
"Change dashboard_encrypted column to MEDIUMBLOB",
|
||||
"create quota table v1",
|
||||
"create index UQE_quota_org_id_user_id_target - v1",
|
||||
"Update quota table charset",
|
||||
"create plugin_setting table",
|
||||
"create index UQE_plugin_setting_org_id_plugin_id - v1",
|
||||
"Add column plugin_version to plugin_settings",
|
||||
"Update plugin_setting table charset",
|
||||
"update NULL org_id to 1",
|
||||
"make org_id NOT NULL and DEFAULT VALUE 1",
|
||||
"create session table",
|
||||
"Drop old table playlist table",
|
||||
"Drop old table playlist_item table",
|
||||
"create playlist table v2",
|
||||
"create playlist item table v2",
|
||||
"Update playlist table charset",
|
||||
"Update playlist_item table charset",
|
||||
"Add playlist column created_at",
|
||||
"Add playlist column updated_at",
|
||||
"drop preferences table v2",
|
||||
"drop preferences table v3",
|
||||
"create preferences table v3",
|
||||
"Update preferences table charset",
|
||||
"Add column team_id in preferences",
|
||||
"Update team_id column values in preferences",
|
||||
"Add column week_start in preferences",
|
||||
"Add column preferences.json_data",
|
||||
"alter preferences.json_data to mediumtext v1",
|
||||
"Add preferences index org_id",
|
||||
"Add preferences index user_id",
|
||||
"create alert table v1",
|
||||
"add index alert org_id \u0026 id ",
|
||||
"add index alert state",
|
||||
"add index alert dashboard_id",
|
||||
"Create alert_rule_tag table v1",
|
||||
"Add unique index alert_rule_tag.alert_id_tag_id",
|
||||
"drop index UQE_alert_rule_tag_alert_id_tag_id - v1",
|
||||
"Rename table alert_rule_tag to alert_rule_tag_v1 - v1",
|
||||
"Create alert_rule_tag table v2",
|
||||
"create index UQE_alert_rule_tag_alert_id_tag_id - Add unique index alert_rule_tag.alert_id_tag_id V2",
|
||||
"copy alert_rule_tag v1 to v2",
|
||||
"drop table alert_rule_tag_v1",
|
||||
"create alert_notification table v1",
|
||||
"Add column is_default",
|
||||
"Add column frequency",
|
||||
"Add column send_reminder",
|
||||
"Add column disable_resolve_message",
|
||||
"add index alert_notification org_id \u0026 name",
|
||||
"Update alert table charset",
|
||||
"Update alert_notification table charset",
|
||||
"create notification_journal table v1",
|
||||
"add index notification_journal org_id \u0026 alert_id \u0026 notifier_id",
|
||||
"drop alert_notification_journal",
|
||||
"create alert_notification_state table v1",
|
||||
"add index alert_notification_state org_id \u0026 alert_id \u0026 notifier_id",
|
||||
"Add for to alert table",
|
||||
"Add column uid in alert_notification",
|
||||
"Update uid column values in alert_notification",
|
||||
"Add unique index alert_notification_org_id_uid",
|
||||
"Remove unique index org_id_name",
|
||||
"Add column secure_settings in alert_notification",
|
||||
"alter alert.settings to mediumtext",
|
||||
"Add non-unique index alert_notification_state_alert_id",
|
||||
"Add non-unique index alert_rule_tag_alert_id",
|
||||
"Drop old annotation table v4",
|
||||
"create annotation table v5",
|
||||
"add index annotation 0 v3",
|
||||
"add index annotation 1 v3",
|
||||
"add index annotation 2 v3",
|
||||
"add index annotation 3 v3",
|
||||
"add index annotation 4 v3",
|
||||
"Update annotation table charset",
|
||||
"Add column region_id to annotation table",
|
||||
"Drop category_id index",
|
||||
"Add column tags to annotation table",
|
||||
"Create annotation_tag table v2",
|
||||
"Add unique index annotation_tag.annotation_id_tag_id",
|
||||
"drop index UQE_annotation_tag_annotation_id_tag_id - v2",
|
||||
"Rename table annotation_tag to annotation_tag_v2 - v2",
|
||||
"Create annotation_tag table v3",
|
||||
"create index UQE_annotation_tag_annotation_id_tag_id - Add unique index annotation_tag.annotation_id_tag_id V3",
|
||||
"copy annotation_tag v2 to v3",
|
||||
"drop table annotation_tag_v2",
|
||||
"Update alert annotations and set TEXT to empty",
|
||||
"Add created time to annotation table",
|
||||
"Add updated time to annotation table",
|
||||
"Add index for created in annotation table",
|
||||
"Add index for updated in annotation table",
|
||||
"Convert existing annotations from seconds to milliseconds",
|
||||
"Add epoch_end column",
|
||||
"Add index for epoch_end",
|
||||
"Make epoch_end the same as epoch",
|
||||
"Move region to single row",
|
||||
"Remove index org_id_epoch from annotation table",
|
||||
"Remove index org_id_dashboard_id_panel_id_epoch from annotation table",
|
||||
"Add index for org_id_dashboard_id_epoch_end_epoch on annotation table",
|
||||
"Add index for org_id_epoch_end_epoch on annotation table",
|
||||
"Remove index org_id_epoch_epoch_end from annotation table",
|
||||
"Add index for alert_id on annotation table",
|
||||
"Increase tags column to length 4096",
|
||||
"Increase prev_state column to length 40 not null",
|
||||
"Increase new_state column to length 40 not null",
|
||||
"create test_data table",
|
||||
"create dashboard_version table v1",
|
||||
"add index dashboard_version.dashboard_id",
|
||||
"add unique index dashboard_version.dashboard_id and dashboard_version.version",
|
||||
"Set dashboard version to 1 where 0",
|
||||
"save existing dashboard data in dashboard_version table v1",
|
||||
"alter dashboard_version.data to mediumtext v1",
|
||||
"Add apiVersion for dashboard_version",
|
||||
"create team table",
|
||||
"add index team.org_id",
|
||||
"add unique index team_org_id_name",
|
||||
"Add column uid in team",
|
||||
"Update uid column values in team",
|
||||
"Add unique index team_org_id_uid",
|
||||
"create team member table",
|
||||
"add index team_member.org_id",
|
||||
"add unique index team_member_org_id_team_id_user_id",
|
||||
"add index team_member.team_id",
|
||||
"Add column email to team table",
|
||||
"Add column external to team_member table",
|
||||
"Add column permission to team_member table",
|
||||
"add unique index team_member_user_id_org_id",
|
||||
"create dashboard acl table",
|
||||
"add index dashboard_acl_dashboard_id",
|
||||
"add unique index dashboard_acl_dashboard_id_user_id",
|
||||
"add unique index dashboard_acl_dashboard_id_team_id",
|
||||
"add index dashboard_acl_user_id",
|
||||
"add index dashboard_acl_team_id",
|
||||
"add index dashboard_acl_org_id_role",
|
||||
"add index dashboard_permission",
|
||||
"save default acl rules in dashboard_acl table",
|
||||
"delete acl rules for deleted dashboards and folders",
|
||||
"create tag table",
|
||||
"add index tag.key_value",
|
||||
"create login attempt table",
|
||||
"add index login_attempt.username",
|
||||
"drop index IDX_login_attempt_username - v1",
|
||||
"Rename table login_attempt to login_attempt_tmp_qwerty - v1",
|
||||
"create login_attempt v2",
|
||||
"create index IDX_login_attempt_username - v2",
|
||||
"copy login_attempt v1 to v2",
|
||||
"drop login_attempt_tmp_qwerty",
|
||||
"create user auth table",
|
||||
"create index IDX_user_auth_auth_module_auth_id - v1",
|
||||
"alter user_auth.auth_id to length 190",
|
||||
"Add OAuth access token to user_auth",
|
||||
"Add OAuth refresh token to user_auth",
|
||||
"Add OAuth token type to user_auth",
|
||||
"Add OAuth expiry to user_auth",
|
||||
"Add index to user_id column in user_auth",
|
||||
"Add OAuth ID token to user_auth",
|
||||
"create server_lock table",
|
||||
"add index server_lock.operation_uid",
|
||||
"create user auth token table",
|
||||
"add unique index user_auth_token.auth_token",
|
||||
"add unique index user_auth_token.prev_auth_token",
|
||||
"add index user_auth_token.user_id",
|
||||
"Add revoked_at to the user auth token",
|
||||
"add index user_auth_token.revoked_at",
|
||||
"add external_session_id to user_auth_token",
|
||||
"create cache_data table",
|
||||
"add unique index cache_data.cache_key",
|
||||
"create short_url table v1",
|
||||
"add index short_url.org_id-uid",
|
||||
"alter table short_url alter column created_by type to bigint",
|
||||
"delete alert_definition table",
|
||||
"recreate alert_definition table",
|
||||
"add index in alert_definition on org_id and title columns",
|
||||
"add index in alert_definition on org_id and uid columns",
|
||||
"alter alert_definition table data column to mediumtext in mysql",
|
||||
"drop index in alert_definition on org_id and title columns",
|
||||
"drop index in alert_definition on org_id and uid columns",
|
||||
"add unique index in alert_definition on org_id and title columns",
|
||||
"add unique index in alert_definition on org_id and uid columns",
|
||||
"Add column paused in alert_definition",
|
||||
"drop alert_definition table",
|
||||
"delete alert_definition_version table",
|
||||
"recreate alert_definition_version table",
|
||||
"add index in alert_definition_version table on alert_definition_id and version columns",
|
||||
"add index in alert_definition_version table on alert_definition_uid and version columns",
|
||||
"alter alert_definition_version table data column to mediumtext in mysql",
|
||||
"drop alert_definition_version table",
|
||||
"create alert_instance table",
|
||||
"add index in alert_instance table on def_org_id, def_uid and current_state columns",
|
||||
"add index in alert_instance table on def_org_id, current_state columns",
|
||||
"add column current_state_end to alert_instance",
|
||||
"remove index def_org_id, def_uid, current_state on alert_instance",
|
||||
"remove index def_org_id, current_state on alert_instance",
|
||||
"rename def_org_id to rule_org_id in alert_instance",
|
||||
"rename def_uid to rule_uid in alert_instance",
|
||||
"add index rule_org_id, rule_uid, current_state on alert_instance",
|
||||
"add index rule_org_id, current_state on alert_instance",
|
||||
"add current_reason column related to current_state",
|
||||
"add result_fingerprint column to alert_instance",
|
||||
"create alert_rule table",
|
||||
"add index in alert_rule on org_id and title columns",
|
||||
"add index in alert_rule on org_id and uid columns",
|
||||
"add index in alert_rule on org_id, namespace_uid, group_uid columns",
|
||||
"alter alert_rule table data column to mediumtext in mysql",
|
||||
"add column for to alert_rule",
|
||||
"add column annotations to alert_rule",
|
||||
"add column labels to alert_rule",
|
||||
"remove unique index from alert_rule on org_id, title columns",
|
||||
"add index in alert_rule on org_id, namespase_uid and title columns",
|
||||
"add dashboard_uid column to alert_rule",
|
||||
"add panel_id column to alert_rule",
|
||||
"add index in alert_rule on org_id, dashboard_uid and panel_id columns",
|
||||
"add rule_group_idx column to alert_rule",
|
||||
"add is_paused column to alert_rule table",
|
||||
"fix is_paused column for alert_rule table",
|
||||
"create alert_rule_version table",
|
||||
"add index in alert_rule_version table on rule_org_id, rule_uid and version columns",
|
||||
"add index in alert_rule_version table on rule_org_id, rule_namespace_uid and rule_group columns",
|
||||
"alter alert_rule_version table data column to mediumtext in mysql",
|
||||
"add column for to alert_rule_version",
|
||||
"add column annotations to alert_rule_version",
|
||||
"add column labels to alert_rule_version",
|
||||
"add rule_group_idx column to alert_rule_version",
|
||||
"add is_paused column to alert_rule_versions table",
|
||||
"fix is_paused column for alert_rule_version table",
|
||||
"create_alert_configuration_table",
|
||||
"Add column default in alert_configuration",
|
||||
"alert alert_configuration alertmanager_configuration column from TEXT to MEDIUMTEXT if mysql",
|
||||
"add column org_id in alert_configuration",
|
||||
"add index in alert_configuration table on org_id column",
|
||||
"add configuration_hash column to alert_configuration",
|
||||
"create_ngalert_configuration_table",
|
||||
"add index in ngalert_configuration on org_id column",
|
||||
"add column send_alerts_to in ngalert_configuration",
|
||||
"create provenance_type table",
|
||||
"add index to uniquify (record_key, record_type, org_id) columns",
|
||||
"create alert_image table",
|
||||
"add unique index on token to alert_image table",
|
||||
"support longer URLs in alert_image table",
|
||||
"create_alert_configuration_history_table",
|
||||
"drop non-unique orgID index on alert_configuration",
|
||||
"drop unique orgID index on alert_configuration if exists",
|
||||
"extract alertmanager configuration history to separate table",
|
||||
"add unique index on orgID to alert_configuration",
|
||||
"add last_applied column to alert_configuration_history",
|
||||
"create library_element table v1",
|
||||
"add index library_element org_id-folder_id-name-kind",
|
||||
"create library_element_connection table v1",
|
||||
"add index library_element_connection element_id-kind-connection_id",
|
||||
"add unique index library_element org_id_uid",
|
||||
"increase max description length to 2048",
|
||||
"alter library_element model to mediumtext",
|
||||
"add library_element folder uid",
|
||||
"populate library_element folder_uid",
|
||||
"add index library_element org_id-folder_uid-name-kind",
|
||||
"clone move dashboard alerts to unified alerting",
|
||||
"create data_keys table",
|
||||
"create secrets table",
|
||||
"rename data_keys name column to id",
|
||||
"add name column into data_keys",
|
||||
"copy data_keys id column values into name",
|
||||
"rename data_keys name column to label",
|
||||
"rename data_keys id column back to name",
|
||||
"create kv_store table v1",
|
||||
"add index kv_store.org_id-namespace-key",
|
||||
"update dashboard_uid and panel_id from existing annotations",
|
||||
"create permission table",
|
||||
"add unique index permission.role_id",
|
||||
"add unique index role_id_action_scope",
|
||||
"create role table",
|
||||
"add column display_name",
|
||||
"add column group_name",
|
||||
"add index role.org_id",
|
||||
"add unique index role_org_id_name",
|
||||
"add index role_org_id_uid",
|
||||
"create team role table",
|
||||
"add index team_role.org_id",
|
||||
"add unique index team_role_org_id_team_id_role_id",
|
||||
"add index team_role.team_id",
|
||||
"create user role table",
|
||||
"add index user_role.org_id",
|
||||
"add unique index user_role_org_id_user_id_role_id",
|
||||
"add index user_role.user_id",
|
||||
"create builtin role table",
|
||||
"add index builtin_role.role_id",
|
||||
"add index builtin_role.name",
|
||||
"Add column org_id to builtin_role table",
|
||||
"add index builtin_role.org_id",
|
||||
"add unique index builtin_role_org_id_role_id_role",
|
||||
"Remove unique index role_org_id_uid",
|
||||
"add unique index role.uid",
|
||||
"create seed assignment table",
|
||||
"add unique index builtin_role_role_name",
|
||||
"add column hidden to role table",
|
||||
"permission kind migration",
|
||||
"permission attribute migration",
|
||||
"permission identifier migration",
|
||||
"add permission identifier index",
|
||||
"add permission action scope role_id index",
|
||||
"remove permission role_id action scope index",
|
||||
"add group mapping UID column to user_role table",
|
||||
"add user_role org ID, user ID, role ID, group mapping UID index",
|
||||
"remove user_role org ID, user ID, role ID index",
|
||||
"create query_history table v1",
|
||||
"add index query_history.org_id-created_by-datasource_uid",
|
||||
"alter table query_history alter column created_by type to bigint",
|
||||
"create query_history_details table v1",
|
||||
"rbac disabled migrator",
|
||||
"teams permissions migration",
|
||||
"dashboard permissions",
|
||||
"dashboard permissions uid scopes",
|
||||
"drop managed folder create actions",
|
||||
"alerting notification permissions",
|
||||
"create query_history_star table v1",
|
||||
"add index query_history.user_id-query_uid",
|
||||
"add column org_id in query_history_star",
|
||||
"alter table query_history_star_mig column user_id type to bigint",
|
||||
"create correlation table v1",
|
||||
"add index correlations.uid",
|
||||
"add index correlations.source_uid",
|
||||
"add correlation config column",
|
||||
"drop index IDX_correlation_uid - v1",
|
||||
"drop index IDX_correlation_source_uid - v1",
|
||||
"Rename table correlation to correlation_tmp_qwerty - v1",
|
||||
"create correlation v2",
|
||||
"create index IDX_correlation_uid - v2",
|
||||
"create index IDX_correlation_source_uid - v2",
|
||||
"create index IDX_correlation_org_id - v2",
|
||||
"copy correlation v1 to v2",
|
||||
"drop correlation_tmp_qwerty",
|
||||
"add provisioning column",
|
||||
"add type column",
|
||||
"create entity_events table",
|
||||
"create dashboard public config v1",
|
||||
"drop index UQE_dashboard_public_config_uid - v1",
|
||||
"drop index IDX_dashboard_public_config_org_id_dashboard_uid - v1",
|
||||
"Drop old dashboard public config table",
|
||||
"recreate dashboard public config v1",
|
||||
"create index UQE_dashboard_public_config_uid - v1",
|
||||
"create index IDX_dashboard_public_config_org_id_dashboard_uid - v1",
|
||||
"drop index UQE_dashboard_public_config_uid - v2",
|
||||
"drop index IDX_dashboard_public_config_org_id_dashboard_uid - v2",
|
||||
"Drop public config table",
|
||||
"Recreate dashboard public config v2",
|
||||
"create index UQE_dashboard_public_config_uid - v2",
|
||||
"create index IDX_dashboard_public_config_org_id_dashboard_uid - v2",
|
||||
"create index UQE_dashboard_public_config_access_token - v2",
|
||||
"Rename table dashboard_public_config to dashboard_public - v2",
|
||||
"add annotations_enabled column",
|
||||
"add time_selection_enabled column",
|
||||
"delete orphaned public dashboards",
|
||||
"add share column",
|
||||
"backfill empty share column fields with default of public",
|
||||
"create file table",
|
||||
"file table idx: path natural pk",
|
||||
"file table idx: parent_folder_path_hash fast folder retrieval",
|
||||
"create file_meta table",
|
||||
"file table idx: path key",
|
||||
"set path collation in file table",
|
||||
"migrate contents column to mediumblob for MySQL",
|
||||
"managed permissions migration",
|
||||
"managed folder permissions alert actions migration",
|
||||
"RBAC action name migrator",
|
||||
"Add UID column to playlist",
|
||||
"Update uid column values in playlist",
|
||||
"Add index for uid in playlist",
|
||||
"update group index for alert rules",
|
||||
"managed folder permissions alert actions repeated migration",
|
||||
"admin only folder/dashboard permission",
|
||||
"add action column to seed_assignment",
|
||||
"add scope column to seed_assignment",
|
||||
"remove unique index builtin_role_role_name before nullable update",
|
||||
"update seed_assignment role_name column to nullable",
|
||||
"add unique index builtin_role_name back",
|
||||
"add unique index builtin_role_action_scope",
|
||||
"add primary key to seed_assigment",
|
||||
"add origin column to seed_assignment",
|
||||
"add origin to plugin seed_assignment",
|
||||
"prevent seeding OnCall access",
|
||||
"managed folder permissions alert actions repeated fixed migration",
|
||||
"managed folder permissions library panel actions migration",
|
||||
"migrate external alertmanagers to datsourcse",
|
||||
"create folder table",
|
||||
"Add index for parent_uid",
|
||||
"Add unique index for folder.uid and folder.org_id",
|
||||
"Update folder title length",
|
||||
"Add unique index for folder.title and folder.parent_uid",
|
||||
"Remove unique index for folder.title and folder.parent_uid",
|
||||
"Add unique index for title, parent_uid, and org_id",
|
||||
"Sync dashboard and folder table",
|
||||
"Remove ghost folders from the folder table",
|
||||
"Remove unique index UQE_folder_uid_org_id",
|
||||
"Add unique index UQE_folder_org_id_uid",
|
||||
"Remove unique index UQE_folder_title_parent_uid_org_id",
|
||||
"Add unique index UQE_folder_org_id_parent_uid_title",
|
||||
"Remove index IDX_folder_parent_uid_org_id",
|
||||
"Remove unique index UQE_folder_org_id_parent_uid_title",
|
||||
"create anon_device table",
|
||||
"add unique index anon_device.device_id",
|
||||
"add index anon_device.updated_at",
|
||||
"create signing_key table",
|
||||
"add unique index signing_key.key_id",
|
||||
"set legacy alert migration status in kvstore",
|
||||
"migrate record of created folders during legacy migration to kvstore",
|
||||
"Add folder_uid for dashboard",
|
||||
"Populate dashboard folder_uid column",
|
||||
"Add unique index for dashboard_org_id_folder_uid_title",
|
||||
"Delete unique index for dashboard_org_id_folder_id_title",
|
||||
"Delete unique index for dashboard_org_id_folder_uid_title",
|
||||
"Add unique index for dashboard_org_id_folder_uid_title_is_folder",
|
||||
"Restore index for dashboard_org_id_folder_id_title",
|
||||
"Remove unique index for dashboard_org_id_folder_uid_title_is_folder",
|
||||
"create sso_setting table",
|
||||
"copy kvstore migration status to each org",
|
||||
"add back entry for orgid=0 migrated status",
|
||||
"create cloud_migration table v1",
|
||||
"create cloud_migration_run table v1",
|
||||
"add stack_id column",
|
||||
"add region_slug column",
|
||||
"add cluster_slug column",
|
||||
"add migration uid column",
|
||||
"Update uid column values for migration",
|
||||
"Add unique index migration_uid",
|
||||
"add migration run uid column",
|
||||
"Update uid column values for migration run",
|
||||
"Add unique index migration_run_uid",
|
||||
"Rename table cloud_migration to cloud_migration_session_tmp_qwerty - v1",
|
||||
"create cloud_migration_session v2",
|
||||
"create index UQE_cloud_migration_session_uid - v2",
|
||||
"copy cloud_migration_session v1 to v2",
|
||||
"drop cloud_migration_session_tmp_qwerty",
|
||||
"Rename table cloud_migration_run to cloud_migration_snapshot_tmp_qwerty - v1",
|
||||
"create cloud_migration_snapshot v2",
|
||||
"create index UQE_cloud_migration_snapshot_uid - v2",
|
||||
"copy cloud_migration_snapshot v1 to v2",
|
||||
"drop cloud_migration_snapshot_tmp_qwerty",
|
||||
"add snapshot upload_url column",
|
||||
"add snapshot status column",
|
||||
"add snapshot local_directory column",
|
||||
"add snapshot gms_snapshot_uid column",
|
||||
"add snapshot encryption_key column",
|
||||
"add snapshot error_string column",
|
||||
"create cloud_migration_resource table v1",
|
||||
"delete cloud_migration_snapshot.result column",
|
||||
"add cloud_migration_resource.name column",
|
||||
"add cloud_migration_resource.parent_name column",
|
||||
"add cloud_migration_session.org_id column",
|
||||
"add cloud_migration_resource.error_code column",
|
||||
"increase resource_uid column length",
|
||||
"alter kv_store.value to longtext",
|
||||
"add notification_settings column to alert_rule table",
|
||||
"add notification_settings column to alert_rule_version table",
|
||||
"removing scope from alert.instances:read action migration",
|
||||
"managed folder permissions alerting silences actions migration",
|
||||
"add record column to alert_rule table",
|
||||
"add record column to alert_rule_version table",
|
||||
"add resolved_at column to alert_instance table",
|
||||
"add last_sent_at column to alert_instance table",
|
||||
"Enable traceQL streaming for all Tempo datasources",
|
||||
"Add scope to alert.notifications.receivers:read and alert.notifications.receivers.secrets:read",
|
||||
"add metadata column to alert_rule table",
|
||||
"add metadata column to alert_rule_version table",
|
||||
"delete orphaned service account permissions",
|
||||
"adding action set permissions",
|
||||
"create user_external_session table",
|
||||
"increase name_id column length to 1024",
|
||||
"increase session_id column length to 1024",
|
||||
"remove scope from alert.notifications.receivers:create",
|
||||
"add created_by column to alert_rule_version table",
|
||||
"add updated_by column to alert_rule table",
|
||||
"add alert_rule_state table",
|
||||
"add index to alert_rule_state on org_id and rule_uid columns",
|
||||
"add guid column to alert_rule table",
|
||||
"add rule_guid column to alert_rule_version table",
|
||||
"drop index in alert_rule_version table on rule_org_id, rule_uid and version columns",
|
||||
"populate rule guid in alert rule table",
|
||||
"add index in alert_rule_version table on rule_org_id, rule_uid, rule_guid and version columns",
|
||||
"add index in alert_rule_version table on rule_guid and version columns",
|
||||
"add index in alert_rule table on guid columns"
|
||||
]
|
||||
@@ -3,12 +3,28 @@
|
||||
package migrator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/spanner"
|
||||
"cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
|
||||
"github.com/googleapis/gax-go/v2"
|
||||
spannerdriver "github.com/googleapis/go-sql-spanner"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"xorm.io/core"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
_ "embed"
|
||||
|
||||
database "cloud.google.com/go/spanner/admin/database/apiv1"
|
||||
)
|
||||
|
||||
type SpannerDialect struct {
|
||||
@@ -60,7 +76,17 @@ func (s *SpannerDialect) CreateTableSQL(table *Table) string {
|
||||
t.Name = table.Name
|
||||
t.PrimaryKeys = table.PrimaryKeys
|
||||
for _, c := range table.Columns {
|
||||
t.AddColumn(core.NewColumn(c.Name, c.Name, core.SQLType{Name: c.Type}, c.Length, c.Length2, c.Nullable))
|
||||
col := core.NewColumn(c.Name, c.Name, core.SQLType{Name: c.Type}, c.Length, c.Length2, c.Nullable)
|
||||
col.IsAutoIncrement = c.IsAutoIncrement
|
||||
col.Default = c.Default
|
||||
t.AddColumn(col)
|
||||
}
|
||||
if len(t.PrimaryKeys) == 0 {
|
||||
for _, ix := range table.Indices {
|
||||
if ix.Name == "PRIMARY_KEY" {
|
||||
t.PrimaryKeys = append(t.PrimaryKeys, ix.Cols...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return s.d.CreateTableSql(t, t.Name, "", "")
|
||||
}
|
||||
@@ -82,3 +108,220 @@ func (s *SpannerDialect) DropIndexSQL(tableName string, index *Index) string {
|
||||
func (s *SpannerDialect) DropTable(tableName string) string {
|
||||
return fmt.Sprintf("DROP TABLE %s", s.Quote(tableName))
|
||||
}
|
||||
|
||||
func (s *SpannerDialect) ColStringNoPk(col *Column) string {
|
||||
sql := s.dialect.Quote(col.Name) + " "
|
||||
|
||||
sql += s.dialect.SQLType(col) + " "
|
||||
|
||||
if s.dialect.ShowCreateNull() && !col.Nullable {
|
||||
sql += "NOT NULL "
|
||||
}
|
||||
|
||||
if col.Default != "" {
|
||||
// Default value must be in parentheses.
|
||||
sql += "DEFAULT (" + s.dialect.Default(col) + ") "
|
||||
}
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
func (s *SpannerDialect) TruncateDBTables(engine *xorm.Engine) error {
|
||||
tables, err := engine.DBMetas()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sess := engine.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
for _, table := range tables {
|
||||
switch table.Name {
|
||||
case "":
|
||||
continue
|
||||
case "migration_log":
|
||||
continue
|
||||
case "dashboard_acl":
|
||||
// keep default dashboard permissions
|
||||
if _, err := sess.Exec(fmt.Sprintf("DELETE FROM %v WHERE dashboard_id != -1 AND org_id != -1;", s.Quote(table.Name))); err != nil {
|
||||
return fmt.Errorf("failed to truncate table %q: %w", table.Name, err)
|
||||
}
|
||||
default:
|
||||
if _, err := sess.Exec(fmt.Sprintf("DELETE FROM %v WHERE TRUE;", s.Quote(table.Name))); err != nil {
|
||||
return fmt.Errorf("failed to truncate table %q: %w", table.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanDB drops all existing tables and their indexes.
|
||||
func (s *SpannerDialect) CleanDB(engine *xorm.Engine) error {
|
||||
tables, err := engine.DBMetas()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Collect all DROP statements.
|
||||
var statements []string
|
||||
for _, table := range tables {
|
||||
// Ignore these tables used by Unified storage.
|
||||
if table.Name == "resource" || table.Name == "resource_blob" || table.Name == "resource_history" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Indexes must be dropped first, otherwise dropping tables fails.
|
||||
for _, index := range table.Indexes {
|
||||
if !index.IsRegular {
|
||||
// Don't drop primary key.
|
||||
continue
|
||||
}
|
||||
sql := fmt.Sprintf("DROP INDEX %s", s.Quote(index.XName(table.Name)))
|
||||
statements = append(statements, sql)
|
||||
}
|
||||
|
||||
sql := fmt.Sprintf("DROP TABLE %s", s.Quote(table.Name))
|
||||
statements = append(statements, sql)
|
||||
}
|
||||
|
||||
if len(statements) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.executeDDLStatements(context.Background(), engine, statements)
|
||||
}
|
||||
|
||||
//go:embed snapshot/spanner-ddl.json
|
||||
var snapshotDDL string
|
||||
|
||||
//go:embed snapshot/spanner-log.json
|
||||
var snapshotMigrations string
|
||||
|
||||
func (s *SpannerDialect) CreateDatabaseFromSnapshot(ctx context.Context, engine *xorm.Engine, tableName string) error {
|
||||
var statements, migrationIDs []string
|
||||
err := json.Unmarshal([]byte(snapshotDDL), &statements)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal([]byte(snapshotMigrations), &migrationIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.executeDDLStatements(ctx, engine, statements)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.recordMigrationsToMigrationLog(engine, migrationIDs, tableName)
|
||||
}
|
||||
|
||||
func (s *SpannerDialect) recordMigrationsToMigrationLog(engine *xorm.Engine, migrationIDs []string, tableName string) error {
|
||||
now := time.Now()
|
||||
makeRecord := func(id string) MigrationLog {
|
||||
return MigrationLog{
|
||||
MigrationID: id,
|
||||
SQL: "",
|
||||
Success: true,
|
||||
Timestamp: now,
|
||||
}
|
||||
}
|
||||
|
||||
sess := engine.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
// Insert records in batches to avoid many roundtrips to database.
|
||||
// Inserting all records at once fails due to "Number of parameters in query exceeds the maximum
|
||||
// allowed limit of 950." error, so we use smaller batches.
|
||||
const batchSize = 100
|
||||
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
records := make([]MigrationLog, 0, len(migrationIDs))
|
||||
for _, mid := range migrationIDs {
|
||||
records = append(records, makeRecord(mid))
|
||||
|
||||
if len(records) >= batchSize {
|
||||
if _, err := sess.Table(tableName).InsertMulti(records); err != nil {
|
||||
err2 := sess.Rollback()
|
||||
return errors.Join(fmt.Errorf("failed to insert migration logs: %w", err), err2)
|
||||
}
|
||||
records = records[:0]
|
||||
}
|
||||
}
|
||||
|
||||
// Insert remaining records.
|
||||
if len(records) > 0 {
|
||||
if _, err := sess.Table(tableName).InsertMulti(records); err != nil {
|
||||
err2 := sess.Rollback()
|
||||
return errors.Join(fmt.Errorf("failed to insert migration logs: %w", err), err2)
|
||||
}
|
||||
}
|
||||
|
||||
if err := sess.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Spanner can be very slow at executing single DDL statements (it can take up to a minute), but when
|
||||
// many DDL statements are batched together, Spanner is *much* faster (total time to execute all statements
|
||||
// is often in tens of seconds). We can't execute batch of DDL statements using sql wrapper, we use "database admin client"
|
||||
// from Spanner library instead.
|
||||
func (s *SpannerDialect) executeDDLStatements(ctx context.Context, engine *xorm.Engine, statements []string) error {
|
||||
// Datasource name contains string used for sql.Open.
|
||||
dsn := engine.Dialect().DataSourceName()
|
||||
cfg, err := spannerdriver.ExtractConnectorConfig(dsn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opts := confToClientOptions(cfg)
|
||||
|
||||
databaseAdminClient, err := database.NewDatabaseAdminClient(ctx, opts...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create database admin client: %v", err)
|
||||
}
|
||||
defer databaseAdminClient.Close()
|
||||
|
||||
databaseName := fmt.Sprintf("projects/%s/instances/%s/databases/%s", cfg.Project, cfg.Instance, cfg.Database)
|
||||
|
||||
op, err := databaseAdminClient.UpdateDatabaseDdl(ctx, &databasepb.UpdateDatabaseDdlRequest{
|
||||
Database: databaseName,
|
||||
Statements: statements,
|
||||
}, gax.WithTimeout(0)) /* disable default timeout */
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start database DDL update: %v", err)
|
||||
}
|
||||
|
||||
err = op.Wait(ctx, gax.WithTimeout(0)) /* disable default timeout */
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to apply database DDL update: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Adapted from https://github.com/googleapis/go-sql-spanner/blob/main/driver.go#L341-L477, from version 1.11.1.
|
||||
func confToClientOptions(connectorConfig spannerdriver.ConnectorConfig) []option.ClientOption {
|
||||
var opts []option.ClientOption
|
||||
if connectorConfig.Host != "" {
|
||||
opts = append(opts, option.WithEndpoint(connectorConfig.Host))
|
||||
}
|
||||
if strval, ok := connectorConfig.Params["credentials"]; ok {
|
||||
opts = append(opts, option.WithCredentialsFile(strval))
|
||||
}
|
||||
if strval, ok := connectorConfig.Params["credentialsjson"]; ok {
|
||||
opts = append(opts, option.WithCredentialsJSON([]byte(strval)))
|
||||
}
|
||||
if strval, ok := connectorConfig.Params["useplaintext"]; ok {
|
||||
if val, err := strconv.ParseBool(strval); err == nil && val {
|
||||
opts = append(opts,
|
||||
option.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
|
||||
option.WithoutAuthentication())
|
||||
}
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"cloud.google.com/go/spanner/spannertest"
|
||||
)
|
||||
|
||||
// ITestDB is an interface of arguments for testing db
|
||||
@@ -42,6 +44,8 @@ func GetTestDB(dbType string) (*TestDB, error) {
|
||||
return postgresTestDB()
|
||||
case "sqlite3":
|
||||
return sqLite3TestDB()
|
||||
case "spanner":
|
||||
return spannerTestDB()
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unknown test db type: %s", dbType)
|
||||
@@ -151,3 +155,49 @@ func postgresTestDB() (*TestDB, error) {
|
||||
Cleanup: func() {},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func spannerTestDB() (*TestDB, error) {
|
||||
// See https://github.com/googleapis/go-sql-spanner/blob/main/driver.go#L56-L81 for connection string options.
|
||||
|
||||
spannerDB := os.Getenv("SPANNER_DB")
|
||||
if spannerDB == "" {
|
||||
return nil, errors.New("SPANNER_DB environment variable not set")
|
||||
}
|
||||
|
||||
if spannerDB == "spannertest" {
|
||||
// Start in-memory spannertest instance.
|
||||
srv, err := spannertest.NewServer("localhost:0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &TestDB{
|
||||
DriverName: "spanner",
|
||||
ConnStr: fmt.Sprintf("%s/projects/grafanatest/instances/grafanatest/databases/grafanatest;usePlainText=true", srv.Addr),
|
||||
Cleanup: srv.Close,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if spannerDB == "emulator" {
|
||||
host := os.Getenv("SPANNER_EMULATOR_HOST")
|
||||
if host == "" {
|
||||
host = "localhost:9010"
|
||||
}
|
||||
|
||||
// To create instance and database manually, run:
|
||||
//
|
||||
// $ curl "localhost:9020/v1/projects/grafanatest/instances" --data '{"instanceId": "'grafanatest'"}'
|
||||
// $ curl "localhost:9020/v1/projects/grafanatest/instances/grafanatest/databases" --data '{"createStatement": "CREATE DATABASE `grafanatest`"}'
|
||||
return &TestDB{
|
||||
DriverName: "spanner",
|
||||
ConnStr: fmt.Sprintf("%s/projects/grafanatest/instances/grafanatest/databases/grafanatest;usePlainText=true", host),
|
||||
Cleanup: func() {},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &TestDB{
|
||||
DriverName: "spanner",
|
||||
ConnStr: spannerDB,
|
||||
Cleanup: func() {},
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user