Files
grafana/pkg/storage/unified/sql/db/migrations/resource_mig.go
T
Peter Štibraný 8a160a8ca1 Convert unique keys in 3 tables to primary keys (#115421)
* Added method for adding migrations for convering unique to primary key.

Based on existing migration for `file` table (in `db_file_storage.go`) migrations.

* Added better default migration names. Added ability to override migration name.

* Use ConvertUniqueKeyToPrimaryKey for cloud_migration_snapshot_partition table.

* Convert resource_version UQE to PK.

* Convert secret_encrypted_value UQE to PK.

* Removed extra test.

* Removed testdata.

* Remove support for renaming migrations for now. We can bring it in later, when we want to convert existing migrations for file, file_meta and setting tables.

* Revert removal of ColumnName to ease backporting, since this field is referenced from enterprise code.

* Use quoted identifiers in Postgres statement.
2025-12-17 15:37:49 +01:00

222 lines
9.6 KiB
Go

package migrations
import (
"fmt"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
)
func initResourceTables(mg *migrator.Migrator) string {
marker := "Initialize resource tables"
mg.AddMigration(marker, &migrator.RawSQLMigration{})
resource_table := migrator.Table{
Name: "resource",
Columns: []*migrator.Column{
// primary identifier
{Name: "guid", Type: migrator.DB_NVarchar, Length: 36, Nullable: false, IsPrimaryKey: true},
{Name: "resource_version", Type: migrator.DB_BigInt, Nullable: true},
// K8s Identity group+(version)+namespace+resource+name
{Name: "group", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
{Name: "resource", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
{Name: "namespace", Type: migrator.DB_NVarchar, Length: 63, Nullable: false},
{Name: "name", Type: migrator.DB_NVarchar, Length: 253, Nullable: false},
{Name: "value", Type: migrator.DB_LongText, Nullable: true},
{Name: "action", Type: migrator.DB_Int, Nullable: false}, // 1: create, 2: update, 3: delete
// Hashed label set
{Name: "label_set", Type: migrator.DB_NVarchar, Length: 64, Nullable: true}, // null is no labels
},
Indices: []*migrator.Index{
{Cols: []string{"namespace", "group", "resource", "name"}, Type: migrator.UniqueIndex},
},
}
resource_history_table := migrator.Table{
Name: "resource_history",
Columns: []*migrator.Column{
// primary identifier
{Name: "guid", Type: migrator.DB_NVarchar, Length: 36, Nullable: false, IsPrimaryKey: true},
{Name: "resource_version", Type: migrator.DB_BigInt, Nullable: true},
// K8s Identity group+(version)+namespace+resource+name
{Name: "group", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
{Name: "resource", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
{Name: "namespace", Type: migrator.DB_NVarchar, Length: 63, Nullable: false},
{Name: "name", Type: migrator.DB_NVarchar, Length: 253, Nullable: false},
{Name: "value", Type: migrator.DB_LongText, Nullable: true},
{Name: "action", Type: migrator.DB_Int, Nullable: false}, // 1: create, 2: update, 3: delete
// Hashed label set
{Name: "label_set", Type: migrator.DB_NVarchar, Length: 64, Nullable: true}, // null is no labels
},
Indices: []*migrator.Index{
{
Cols: []string{"namespace", "group", "resource", "name", "resource_version"},
Type: migrator.UniqueIndex,
Name: "UQE_resource_history_namespace_group_name_version",
},
// index to support watch poller
{Cols: []string{"resource_version"}, Type: migrator.IndexType},
},
}
tables := []migrator.Table{resource_table, resource_history_table}
// tables = append(tables, migrator.Table{
// Name: "resource_label_set",
// Columns: []*migrator.Column{
// {Name: "label_set", Type: migrator.DB_NVarchar, Length: 64, Nullable: false},
// {Name: "label", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
// {Name: "value", Type: migrator.DB_Text, Nullable: false},
// },
// Indices: []*migrator.Index{
// {Cols: []string{"label_set", "label"}, Type: migrator.UniqueIndex},
// },
// })
tables = append(tables, migrator.Table{
Name: "resource_version",
Columns: []*migrator.Column{
{Name: "group", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
{Name: "resource", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
{Name: "resource_version", Type: migrator.DB_BigInt, Nullable: false},
},
Indices: []*migrator.Index{
{Cols: []string{"group", "resource"}, Type: migrator.UniqueIndex},
},
})
tables = append(tables, migrator.Table{
Name: "resource_blob",
Columns: []*migrator.Column{
{Name: "uuid", Type: migrator.DB_Uuid, Length: 36, Nullable: false, IsPrimaryKey: true},
{Name: "created", Type: migrator.DB_DateTime, Nullable: false},
{Name: "group", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
{Name: "resource", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
{Name: "namespace", Type: migrator.DB_NVarchar, Length: 63, Nullable: false},
{Name: "name", Type: migrator.DB_NVarchar, Length: 253, Nullable: false},
// The raw bytes
{Name: "value", Type: migrator.DB_LongBlob, Nullable: false},
// Used as an etag
{Name: "hash", Type: migrator.DB_NVarchar, Length: 64, Nullable: false},
{Name: "content_type", Type: migrator.DB_NVarchar, Length: 255, Nullable: false},
},
Indices: []*migrator.Index{
{
Cols: []string{"namespace", "group", "resource", "name"},
Type: migrator.IndexType,
Name: "IDX_resource_history_namespace_group_name",
},
{Cols: []string{"created"}, Type: migrator.IndexType}, // sort field
},
})
resource_last_import_time := migrator.Table{
Name: "resource_last_import_time",
Columns: []*migrator.Column{
{Name: "group", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
{Name: "resource", Type: migrator.DB_NVarchar, Length: 190, Nullable: false},
{Name: "namespace", Type: migrator.DB_NVarchar, Length: 63, Nullable: false},
{Name: "last_import_time", Type: migrator.DB_DateTime, Nullable: false},
},
PrimaryKeys: []string{"group", "resource", "namespace"},
}
tables = append(tables, resource_last_import_time)
// Initialize all tables
for t := range tables {
mg.AddMigration("drop table "+tables[t].Name, migrator.NewDropTableMigration(tables[t].Name))
mg.AddMigration("create table "+tables[t].Name, migrator.NewAddTableMigration(tables[t]))
for i := range tables[t].Indices {
mg.AddMigration(fmt.Sprintf("create table %s, index: %d", tables[t].Name, i), migrator.NewAddIndexMigration(tables[t], tables[t].Indices[i]))
}
}
mg.AddMigration("Add column previous_resource_version in resource_history", migrator.NewAddColumnMigration(resource_history_table, &migrator.Column{
Name: "previous_resource_version", Type: migrator.DB_BigInt, Nullable: true,
}))
mg.AddMigration("Add column previous_resource_version in resource", migrator.NewAddColumnMigration(resource_table, &migrator.Column{
Name: "previous_resource_version", Type: migrator.DB_BigInt, Nullable: true,
}))
mg.AddMigration("Add index to resource_history for polling", migrator.NewAddIndexMigration(resource_history_table, &migrator.Index{
Cols: []string{"group", "resource", "resource_version"}, Type: migrator.IndexType,
}))
mg.AddMigration("Add index to resource for loading", migrator.NewAddIndexMigration(resource_table, &migrator.Index{
Cols: []string{"group", "resource"}, Type: migrator.IndexType,
}))
mg.AddMigration("Add column folder in resource_history", migrator.NewAddColumnMigration(resource_history_table, &migrator.Column{
Name: "folder", Type: migrator.DB_NVarchar, Length: 253, Nullable: false, Default: "''",
}))
mg.AddMigration("Add column folder in resource", migrator.NewAddColumnMigration(resource_table, &migrator.Column{
Name: "folder", Type: migrator.DB_NVarchar, Length: 253, Nullable: false, Default: "''",
}))
mg.AddMigration("Migrate DeletionMarkers to real Resource objects", &deletionMarkerMigrator{})
mg.AddMigration("Add index to resource_history for get trash", migrator.NewAddIndexMigration(resource_history_table, &migrator.Index{
Name: "IDX_resource_history_namespace_group_resource_action_version",
Cols: []string{"namespace", "group", "resource", "action", "resource_version"},
Type: migrator.IndexType,
}))
// Add generation column so we can use it for more aggressive pruning
mg.AddMigration("Add generation to resource history", migrator.NewAddColumnMigration(resource_history_table, &migrator.Column{
Name: "generation", Type: migrator.DB_BigInt, Nullable: false, Default: "0",
}))
mg.AddMigration("Add generation index to resource history", migrator.NewAddIndexMigration(resource_history_table, &migrator.Index{
Cols: []string{"namespace", "group", "resource", "name", "generation"},
Type: migrator.IndexType,
Name: "IDX_resource_history_namespace_group_resource_name_generation",
}))
mg.AddMigration("Add UQE_resource_last_import_time_last_import_time index", migrator.NewAddIndexMigration(resource_last_import_time, &migrator.Index{
Cols: []string{"last_import_time"},
Type: migrator.IndexType,
Name: "UQE_resource_last_import_time_last_import_time",
}))
mg.AddMigration("Add key_path column to resource_history", migrator.NewAddColumnMigration(resource_history_table, &migrator.Column{
Name: "key_path", Type: migrator.DB_NVarchar, Length: 2048, Nullable: false, Default: "''", IsLatin: true,
}))
resource_events_table := migrator.Table{
Name: "resource_events",
Columns: []*migrator.Column{
{Name: "key_path", Type: migrator.DB_NVarchar, Length: 2048, Nullable: false, IsPrimaryKey: true, IsLatin: true},
{Name: "value", Type: migrator.DB_MediumText, Nullable: false},
},
}
mg.AddMigration("create table "+resource_events_table.Name, migrator.NewAddTableMigration(resource_events_table))
mg.AddMigration("Add IDX_resource_history_key_path index", migrator.NewAddIndexMigration(resource_history_table, &migrator.Index{
Cols: []string{"key_path"},
Type: migrator.IndexType,
Name: "IDX_resource_history_key_path",
}))
oldResourceVersionUniqueKey := migrator.Index{Cols: []string{"group", "resource"}, Type: migrator.UniqueIndex}
updatedResourceVersionTable := migrator.Table{
Name: "resource_version",
Columns: []*migrator.Column{
{Name: "group", Type: migrator.DB_NVarchar, Length: 190, Nullable: false, IsPrimaryKey: true},
{Name: "resource", Type: migrator.DB_NVarchar, Length: 190, Nullable: false, IsPrimaryKey: true},
{Name: "resource_version", Type: migrator.DB_BigInt, Nullable: false},
},
PrimaryKeys: []string{"group", "resource"},
}
migrator.ConvertUniqueKeyToPrimaryKey(mg, oldResourceVersionUniqueKey, updatedResourceVersionTable)
return marker
}