diff --git a/pkg/ccl/backupccl/BUILD.bazel b/pkg/ccl/backupccl/BUILD.bazel index feb2a7c57182..2424f7e75374 100644 --- a/pkg/ccl/backupccl/BUILD.bazel +++ b/pkg/ccl/backupccl/BUILD.bazel @@ -78,6 +78,7 @@ go_library( "//pkg/sql/catalog/colinfo", "//pkg/sql/catalog/dbdesc", "//pkg/sql/catalog/descbuilder", + "//pkg/sql/catalog/descidgen", "//pkg/sql/catalog/descpb", "//pkg/sql/catalog/descs", "//pkg/sql/catalog/ingesting", diff --git a/pkg/ccl/backupccl/backup_test.go b/pkg/ccl/backupccl/backup_test.go index 4d1cae2af64a..ea3cdc9b95a2 100644 --- a/pkg/ccl/backupccl/backup_test.go +++ b/pkg/ccl/backupccl/backup_test.go @@ -66,13 +66,11 @@ import ( "github.com/cockroachdb/cockroach/pkg/roachpb" "github.com/cockroachdb/cockroach/pkg/security" "github.com/cockroachdb/cockroach/pkg/security/username" - "github.com/cockroachdb/cockroach/pkg/server" "github.com/cockroachdb/cockroach/pkg/settings/cluster" "github.com/cockroachdb/cockroach/pkg/spanconfig" "github.com/cockroachdb/cockroach/pkg/sql" "github.com/cockroachdb/cockroach/pkg/sql/catalog" "github.com/cockroachdb/cockroach/pkg/sql/catalog/bootstrap" - "github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkeys" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/desctestutils" "github.com/cockroachdb/cockroach/pkg/sql/catalog/systemschema" @@ -1071,7 +1069,7 @@ func TestBackupRestoreSystemTables(t *testing.T) { // At the time this test was written, these were the only system tables that // were reasonable for a user to backup and restore into another cluster. - tables := []string{"locations", "role_members", "users", "zones", "role_id_seq"} + tables := []string{"locations", "role_members", "users", "zones"} tableSpec := "system." + strings.Join(tables, ", system.") // Take a consistent fingerprint of the original tables. @@ -1079,9 +1077,6 @@ func TestBackupRestoreSystemTables(t *testing.T) { expectedFingerprints := map[string][][]string{} err := crdb.ExecuteTx(ctx, conn, nil /* txopts */, func(tx *gosql.Tx) error { for _, table := range tables { - if table == "role_id_seq" { - continue - } rows, err := conn.Query("SHOW EXPERIMENTAL_FINGERPRINTS FROM TABLE system." + table) if err != nil { return err @@ -1107,9 +1102,6 @@ func TestBackupRestoreSystemTables(t *testing.T) { // Verify the fingerprints match. for _, table := range tables { - if table == "role_id_seq" { - continue - } a := sqlDB.QueryStr(t, "SHOW EXPERIMENTAL_FINGERPRINTS FROM TABLE system_new."+table) if e := expectedFingerprints[table]; !reflect.DeepEqual(e, a) { t.Fatalf("fingerprints between system.%[1]s and system_new.%[1]s did not match:%s\n", @@ -9555,7 +9547,6 @@ func TestExcludeDataFromBackupDoesNotHoldupGC(t *testing.T) { func TestBackupRestoreSystemUsers(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) - skip.WithIssue(t, 78963) sqlDB, tempDir, cleanupFn := createEmptyCluster(t, singleNode) _, sqlDBRestore, cleanupEmptyCluster := backupRestoreTestSetupEmpty(t, singleNode, tempDir, InitManualReplication, base.TestClusterArgs{}) @@ -9616,18 +9607,17 @@ func TestBackupRestoreSystemUsers(t *testing.T) { defer cleanupEmptyCluster1() t.Run("restore-from-backup-with-no-system-role-members", func(t *testing.T) { sqlDBRestore1.Exec(t, "RESTORE SYSTEM USERS FROM $1", localFoo+"/3") - - sqlDBRestore1.CheckQueryResults(t, "SELECT username, \"hashedPassword\", \"isRole\" FROM system.users", [][]string{ - {"admin", "", "true"}, - {"app", "NULL", "false"}, - {"app_role", "NULL", "true"}, - {"root", "", "false"}, - {"test", "NULL", "false"}, - {"test_role", "NULL", "true"}, - }) sqlDBRestore1.CheckQueryResults(t, "SELECT \"role\", \"member\", \"isAdmin\" FROM system.role_members", [][]string{ {"admin", "root", "true"}, }) + sqlDBRestore1.CheckQueryResults(t, "SELECT username, \"hashedPassword\", \"isRole\", \"user_id\" FROM system.users", [][]string{ + {"admin", "", "true", "2"}, + {"app", "NULL", "false", "100"}, + {"app_role", "NULL", "true", "101"}, + {"root", "", "false", "1"}, + {"test", "NULL", "false", "102"}, + {"test_role", "NULL", "true", "103"}, + }) sqlDBRestore1.CheckQueryResults(t, "SHOW USERS", [][]string{ {"admin", "", "{}"}, {"app", "", "{}"}, @@ -9637,6 +9627,35 @@ func TestBackupRestoreSystemUsers(t *testing.T) { {"test_role", "", "{}"}, }) }) + _, sqlDBRestore2, cleanupEmptyCluster2 := backupRestoreTestSetupEmpty(t, singleNode, tempDir, InitManualReplication, base.TestClusterArgs{}) + defer cleanupEmptyCluster2() + t.Run("restore-from-backup-with-existing-user", func(t *testing.T) { + // Create testuser and verify that the system user ids are + // allocated properly in the restore. + sqlDBRestore2.Exec(t, "CREATE USER testuser") + sqlDBRestore2.Exec(t, "RESTORE SYSTEM USERS FROM $1", localFoo+"/3") + sqlDBRestore2.CheckQueryResults(t, "SELECT \"role\", \"member\", \"isAdmin\" FROM system.role_members", [][]string{ + {"admin", "root", "true"}, + }) + sqlDBRestore2.CheckQueryResults(t, "SELECT username, \"hashedPassword\", \"isRole\", \"user_id\" FROM system.users", [][]string{ + {"admin", "", "true", "2"}, + {"app", "NULL", "false", "101"}, + {"app_role", "NULL", "true", "102"}, + {"root", "", "false", "1"}, + {"test", "NULL", "false", "103"}, + {"test_role", "NULL", "true", "104"}, + {"testuser", "NULL", "false", "100"}, + }) + sqlDBRestore2.CheckQueryResults(t, "SHOW USERS", [][]string{ + {"admin", "", "{}"}, + {"app", "", "{}"}, + {"app_role", "", "{}"}, + {"root", "", "{admin}"}, + {"test", "", "{}"}, + {"test_role", "", "{}"}, + {"testuser", "", "{}"}, + }) + }) } // TestUserfileNormalizationIncrementalShowBackup tests to see that file @@ -10157,78 +10176,6 @@ func TestBackupNoOverwriteLatest(t *testing.T) { require.NotEqual(t, firstLatest, thirdLatest) } -// TestBackupLatestInBaseDirectory tests to see that a LATEST -// file in the base directory can be properly read when one is not found -// in metadata/latest. This can occur when an older version node creates -// the backup. -func TestBackupLatestInBaseDirectory(t *testing.T) { - defer leaktest.AfterTest(t)() - defer log.Scope(t).Close(t) - - disableUpgradeCh := make(chan struct{}) - const numAccounts = 1 - const userfile = "'userfile:///a'" - args := base.TestClusterArgs{ - ServerArgs: base.TestServerArgs{ - Knobs: base.TestingKnobs{ - Server: &server.TestingKnobs{ - BinaryVersionOverride: clusterversion.ByKey(clusterversion.BackupDoesNotOverwriteLatestAndCheckpoint - 1), - DisableAutomaticVersionUpgrade: disableUpgradeCh, - }, - }, - }, - } - - tc, sqlDB, _, cleanupFn := backupRestoreTestSetupWithParams(t, singleNode, numAccounts, InitManualReplication, args) - defer cleanupFn() - execCfg := tc.Server(0).ExecutorConfig().(sql.ExecutorConfig) - ctx := context.Background() - store, err := execCfg.DistSQLSrv.ExternalStorageFromURI(ctx, "userfile:///a", username.RootUserName()) - require.NoError(t, err) - - query := fmt.Sprintf("BACKUP INTO %s", userfile) - sqlDB.Exec(t, query) - - // Confirm that the LATEST file was written to the base directory. - r, err := store.ReadFile(ctx, backupbase.LatestFileName) - require.NoError(t, err) - r.Close(ctx) - - // Drop the system.role_seq_id so that we can perform the migration. - sqlDB.Exec(t, `INSERT INTO system.users VALUES ('node', '', false, 0)`) - sqlDB.Exec(t, `GRANT node TO root`) - sqlDB.Exec(t, `DROP SEQUENCE system.role_id_seq`) - sqlDB.Exec(t, `REVOKE node FROM root`) - - err = tc.Servers[0].DB().Del(ctx, catalogkeys.MakeDescMetadataKey(keys.SystemSQLCodec, keys.RoleIDSequenceID)) - require.NoError(t, err) - err = tc.Servers[0].DB().Del(ctx, keys.SystemSQLCodec.SequenceKey(uint32(keys.RoleIDSequenceID))) - require.NoError(t, err) - - // Close the channel so that the cluster version is upgraded. - close(disableUpgradeCh) - // Check the cluster version is bumped to newVersion. - testutils.SucceedsSoon(t, func() error { - var version string - sqlDB.QueryRow(t, "SELECT value FROM system.settings WHERE name = 'version'").Scan(&version) - var v clusterversion.ClusterVersion - if err := protoutil.Unmarshal([]byte(version), &v); err != nil { - return err - } - version = v.String() - if version != clusterversion.TestingBinaryVersion.String() { - return errors.Errorf("cluster version is still %s, should be %s", version, clusterversion.TestingBinaryVersion.String()) - } - return nil - }) - - // Take an incremental backup on the new version using the latest file - // written by the old version in the base directory. - query = fmt.Sprintf("BACKUP INTO LATEST IN %s", userfile) - sqlDB.Exec(t, query) - -} - // TestBackupRestoreTelemetryEvents tests that BACKUP and RESTORE correctly // publishes telemetry events. func TestBackupRestoreTelemetryEvents(t *testing.T) { diff --git a/pkg/ccl/backupccl/full_cluster_backup_restore_test.go b/pkg/ccl/backupccl/full_cluster_backup_restore_test.go index 4b6dd21b24bc..7d68157ce7f4 100644 --- a/pkg/ccl/backupccl/full_cluster_backup_restore_test.go +++ b/pkg/ccl/backupccl/full_cluster_backup_restore_test.go @@ -1112,3 +1112,51 @@ DROP DATABASE defaultdb; {fmt.Sprint(parentID), fmt.Sprint(parentSchemaID), name, fmt.Sprint(ID)}, }) } + +func TestFullClusterRestoreWithUserIDs(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + + params := base.TestClusterArgs{ + ServerArgs: base.TestServerArgs{ + Knobs: base.TestingKnobs{ + JobsTestingKnobs: jobs.NewTestingKnobsWithShortIntervals(), + }, + }, + } + const numAccounts = 10 + _, sqlDB, tempDir, cleanupFn := backupRestoreTestSetupWithParams(t, singleNode, numAccounts, InitManualReplication, params) + _, sqlDBRestore, cleanupEmptyCluster := backupRestoreTestSetupEmpty(t, singleNode, tempDir, InitManualReplication, params) + defer cleanupFn() + defer cleanupEmptyCluster() + + sqlDB.Exec(t, `CREATE USER test1`) + sqlDB.Exec(t, `CREATE USER test2`) + sqlDB.Exec(t, `BACKUP TO $1`, localFoo) + + sqlDB.CheckQueryResults(t, `SELECT * FROM system.users ORDER BY user_id`, [][]string{ + {"root", "", "false", "1"}, + {"admin", "", "true", "2"}, + {"test1", "NULL", "false", "100"}, + {"test2", "NULL", "false", "101"}, + }) + // Ensure that the new backup succeeds. + sqlDBRestore.Exec(t, `RESTORE FROM $1`, localFoo) + + sqlDBRestore.CheckQueryResults(t, `SELECT * FROM system.users ORDER BY user_id`, [][]string{ + {"root", "", "false", "1"}, + {"admin", "", "true", "2"}, + {"test1", "NULL", "false", "100"}, + {"test2", "NULL", "false", "101"}, + }) + + sqlDBRestore.Exec(t, `CREATE USER test3`) + + sqlDBRestore.CheckQueryResults(t, `SELECT * FROM system.users ORDER BY user_id`, [][]string{ + {"root", "", "false", "1"}, + {"admin", "", "true", "2"}, + {"test1", "NULL", "false", "100"}, + {"test2", "NULL", "false", "101"}, + {"test3", "NULL", "false", "102"}, + }) +} diff --git a/pkg/ccl/backupccl/restore_job.go b/pkg/ccl/backupccl/restore_job.go index ba4deb83fabe..ecf9607b99f3 100644 --- a/pkg/ccl/backupccl/restore_job.go +++ b/pkg/ccl/backupccl/restore_job.go @@ -37,6 +37,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkeys" "github.com/cockroachdb/cockroach/pkg/sql/catalog/catpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/dbdesc" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/descidgen" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descs" "github.com/cockroachdb/cockroach/pkg/sql/catalog/ingesting" @@ -2400,11 +2401,25 @@ func (r *restoreResumer) restoreSystemUsers( } insertUser := `INSERT INTO system.users ("username", "hashedPassword", "isRole") VALUES ($1, $2, $3)` + if r.execCfg.Settings.Version.IsActive(ctx, clusterversion.AddSystemUserIDColumn) { + insertUser = `INSERT INTO system.users ("username", "hashedPassword", "isRole", "user_id") VALUES ($1, $2, $3, $4)` + } newUsernames := make(map[string]bool) + args := make([]interface{}, 4) for _, user := range users { newUsernames[user[0].String()] = true + args[0] = user[0] + args[1] = user[1] + args[2] = user[2] + if r.execCfg.Settings.Version.IsActive(ctx, clusterversion.AddSystemUserIDColumn) { + id, err := descidgen.GenerateUniqueRoleID(ctx, r.execCfg.DB, r.execCfg.Codec) + if err != nil { + return err + } + args[3] = id + } if _, err = executor.Exec(ctx, "insert-non-existent-users", txn, insertUser, - user[0], user[1], user[2]); err != nil { + args...); err != nil { return err } } diff --git a/pkg/ccl/backupccl/restore_old_versions_test.go b/pkg/ccl/backupccl/restore_old_versions_test.go index 2eba95834351..2baa01871024 100644 --- a/pkg/ccl/backupccl/restore_old_versions_test.go +++ b/pkg/ccl/backupccl/restore_old_versions_test.go @@ -74,6 +74,7 @@ func TestRestoreOldVersions(t *testing.T) { privilegeDirs = testdataBase + "/privileges" multiRegionDirs = testdataBase + "/multi-region" publicSchemaDirs = testdataBase + "/public-schema-remap" + systemUsersDirs = testdataBase + "/system-users-restore" ) t.Run("table-restore", func(t *testing.T) { @@ -300,6 +301,28 @@ ORDER BY object_type, object_name`, [][]string{ t.Run(dir.Name(), restoreSyntheticPublicSchemaNamespaceEntryCleanupOnFail(exportDir)) } }) + + t.Run("system-users-restore", func(t *testing.T) { + dirs, err := ioutil.ReadDir(systemUsersDirs) + require.NoError(t, err) + for _, dir := range dirs { + require.True(t, dir.IsDir()) + exportDir, err := filepath.Abs(filepath.Join(systemUsersDirs, dir.Name())) + require.NoError(t, err) + t.Run(dir.Name(), restoreSystemUsersWithoutIDs(exportDir)) + } + }) + + t.Run("full-cluster-restore-users-without-ids", func(t *testing.T) { + dirs, err := ioutil.ReadDir(systemUsersDirs) + require.NoError(t, err) + for _, dir := range dirs { + require.True(t, dir.IsDir()) + exportDir, err := filepath.Abs(filepath.Join(systemUsersDirs, dir.Name())) + require.NoError(t, err) + t.Run(dir.Name(), fullClusterRestoreUsersWithoutIDs(exportDir)) + } + }) } func restoreOldVersionTestWithInterleave(exportDir string) func(t *testing.T) { @@ -1112,3 +1135,119 @@ func restoreSyntheticPublicSchemaNamespaceEntryCleanupOnFail(exportDir string) f sqlDB.CheckQueryResults(t, `SELECT id FROM system.namespace WHERE name = 'public' AND id=29 AND "parentID"!=1`, [][]string{}) } } + +func fullClusterRestoreUsersWithoutIDs(exportDir string) func(t *testing.T) { + return func(t *testing.T) { + const numAccounts = 1000 + _, _, tmpDir, cleanupFn := backupRestoreTestSetup(t, multiNode, numAccounts, InitManualReplication) + defer cleanupFn() + + _, sqlDB, cleanup := backupRestoreTestSetupEmpty(t, singleNode, tmpDir, + InitManualReplication, base.TestClusterArgs{ + ServerArgs: base.TestServerArgs{ + Knobs: base.TestingKnobs{ + JobsTestingKnobs: jobs.NewTestingKnobsWithShortIntervals(), + }, + }}) + defer cleanup() + err := os.Symlink(exportDir, filepath.Join(tmpDir, "foo")) + require.NoError(t, err) + + sqlDB.Exec(t, fmt.Sprintf("RESTORE FROM '%s'", localFoo)) + + sqlDB.CheckQueryResults(t, `SELECT username, "hashedPassword", "isRole", user_id FROM system.users`, [][]string{ + {"admin", "", "true", "2"}, + {"root", "", "false", "1"}, + {"testrole", "NULL", "true", "100"}, + {"testuser", "NULL", "false", "101"}, + {"testuser2", "NULL", "false", "102"}, + {"testuser3", "NULL", "false", "103"}, + }) + + // Verify that the next user we create uses the next biggest ID. + sqlDB.Exec(t, "CREATE USER testuser4") + + sqlDB.CheckQueryResults(t, `SELECT username, "hashedPassword", "isRole", user_id FROM system.users`, [][]string{ + {"admin", "", "true", "2"}, + {"root", "", "false", "1"}, + {"testrole", "NULL", "true", "100"}, + {"testuser", "NULL", "false", "101"}, + {"testuser2", "NULL", "false", "102"}, + {"testuser3", "NULL", "false", "103"}, + {"testuser4", "NULL", "false", "104"}, + }) + } +} + +func restoreSystemUsersWithoutIDs(exportDir string) func(t *testing.T) { + return func(t *testing.T) { + const numAccounts = 1000 + _, _, tmpDir, cleanupFn := backupRestoreTestSetup(t, multiNode, numAccounts, InitManualReplication) + defer cleanupFn() + + _, sqlDB, cleanup := backupRestoreTestSetupEmpty(t, singleNode, tmpDir, + InitManualReplication, base.TestClusterArgs{ + ServerArgs: base.TestServerArgs{ + Knobs: base.TestingKnobs{ + JobsTestingKnobs: jobs.NewTestingKnobsWithShortIntervals(), + }, + }}) + defer cleanup() + err := os.Symlink(exportDir, filepath.Join(tmpDir, "foo")) + require.NoError(t, err) + + sqlDB.Exec(t, fmt.Sprintf("RESTORE SYSTEM USERS FROM '%s'", localFoo)) + + sqlDB.CheckQueryResults(t, `SELECT username, "hashedPassword", "isRole", user_id FROM system.users`, [][]string{ + {"admin", "", "true", "2"}, + {"root", "", "false", "1"}, + {"testrole", "NULL", "true", "100"}, + {"testuser", "NULL", "false", "101"}, + {"testuser2", "NULL", "false", "102"}, + {"testuser3", "NULL", "false", "103"}, + }) + + // Verify that the next user we create uses the next biggest ID. + sqlDB.Exec(t, "CREATE USER testuser4") + + sqlDB.CheckQueryResults(t, `SELECT username, "hashedPassword", "isRole", user_id FROM system.users`, [][]string{ + {"admin", "", "true", "2"}, + {"root", "", "false", "1"}, + {"testrole", "NULL", "true", "100"}, + {"testuser", "NULL", "false", "101"}, + {"testuser2", "NULL", "false", "102"}, + {"testuser3", "NULL", "false", "103"}, + {"testuser4", "NULL", "false", "104"}, + }) + + // Drop some users and try restoring again. + sqlDB.Exec(t, "DROP ROLE testrole") + sqlDB.Exec(t, "DROP ROLE testuser2") + sqlDB.Exec(t, "DROP ROLE testuser3") + sqlDB.Exec(t, "DROP ROLE testuser4") + + sqlDB.Exec(t, fmt.Sprintf("RESTORE SYSTEM USERS FROM '%s'", localFoo)) + + // testrole, testuser2, testuser3 should be reassigned higher ids. + sqlDB.CheckQueryResults(t, `SELECT username, "hashedPassword", "isRole", user_id FROM system.users`, [][]string{ + {"admin", "", "true", "2"}, + {"root", "", "false", "1"}, + {"testrole", "NULL", "true", "105"}, + {"testuser", "NULL", "false", "101"}, + {"testuser2", "NULL", "false", "106"}, + {"testuser3", "NULL", "false", "107"}, + }) + + // Verify that the next user we create uses the next biggest ID. + sqlDB.Exec(t, "CREATE USER testuser4") + sqlDB.CheckQueryResults(t, `SELECT username, "hashedPassword", "isRole", user_id FROM system.users`, [][]string{ + {"admin", "", "true", "2"}, + {"root", "", "false", "1"}, + {"testrole", "NULL", "true", "105"}, + {"testuser", "NULL", "false", "101"}, + {"testuser2", "NULL", "false", "106"}, + {"testuser3", "NULL", "false", "107"}, + {"testuser4", "NULL", "false", "108"}, + }) + } +} diff --git a/pkg/ccl/backupccl/system_schema.go b/pkg/ccl/backupccl/system_schema.go index a8f6e0b0a110..24686d6db2d2 100644 --- a/pkg/ccl/backupccl/system_schema.go +++ b/pkg/ccl/backupccl/system_schema.go @@ -14,14 +14,18 @@ import ( "math" "sort" + "github.com/cockroachdb/cockroach/pkg/clusterversion" "github.com/cockroachdb/cockroach/pkg/jobs/jobspb" + "github.com/cockroachdb/cockroach/pkg/keys" "github.com/cockroachdb/cockroach/pkg/kv" "github.com/cockroachdb/cockroach/pkg/sql" "github.com/cockroachdb/cockroach/pkg/sql/catalog" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/descidgen" descpb "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descs" "github.com/cockroachdb/cockroach/pkg/sql/catalog/systemschema" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" "github.com/cockroachdb/cockroach/pkg/util/log" "github.com/cockroachdb/errors" ) @@ -83,6 +87,10 @@ type systemBackupConfiguration struct { expectMissingInSystemTenant bool } +// roleIDSequenceRestoreOrder is set to 1 since it must be after system.users +// which has the default 0. +const roleIDSequenceRestoreOrder = 1 + // defaultSystemTableRestoreFunc is how system table data is restored. This can // be overwritten with the system table's // systemBackupConfiguration.customRestoreFunc. @@ -110,6 +118,7 @@ func defaultSystemTableRestoreFunc( if _, err := executor.Exec(ctx, opName, txn, restoreQuery); err != nil { return errors.Wrapf(err, "inserting data to system.%s", systemTableName) } + return nil } @@ -152,6 +161,84 @@ func queryTableRowCount( return int64(*count), nil } +func usersRestoreFunc( + ctx context.Context, + execCfg *sql.ExecutorConfig, + txn *kv.Txn, + systemTableName, tempTableName string, +) error { + if !execCfg.Settings.Version.IsActive(ctx, clusterversion.AddSystemUserIDColumn) { + return defaultSystemTableRestoreFunc( + ctx, execCfg, txn, systemTableName, tempTableName, + ) + } + + executor := execCfg.InternalExecutor + hasIDColumnQuery := fmt.Sprintf( + `SELECT EXISTS (SELECT 1 FROM [SHOW COLUMNS FROM %s] WHERE column_name = 'user_id')`, tempTableName) + row, err := executor.QueryRow(ctx, "has-id-column", txn, hasIDColumnQuery) + if err != nil { + return err + } + hasIDColumn := tree.MustBeDBool(row[0]) + if hasIDColumn { + return defaultSystemTableRestoreFunc( + ctx, execCfg, txn, systemTableName, tempTableName, + ) + } + + deleteQuery := fmt.Sprintf("DELETE FROM system.%s WHERE true", systemTableName) + opName := systemTableName + "-data-deletion" + log.Eventf(ctx, "clearing data from system table %s with query %q", + systemTableName, deleteQuery) + + _, err = executor.Exec(ctx, opName, txn, deleteQuery) + if err != nil { + return errors.Wrapf(err, "deleting data from system.%s", systemTableName) + } + + it, err := executor.QueryIteratorEx(ctx, "query-system-users-in-backup", + txn, sessiondata.NodeUserSessionDataOverride, + fmt.Sprintf(`SELECT * FROM %s`, tempTableName)) + if err != nil { + return err + } + + for { + ok, err := it.Next(ctx) + if err != nil { + return err + } + if !ok { + break + } + + username := tree.MustBeDString(it.Cur()[0]) + password := it.Cur()[1] + isRole := tree.MustBeDBool(it.Cur()[2]) + + var id int64 + if username == "root" { + id = 1 + } else if username == "admin" { + id = 2 + } else { + id, err = descidgen.GenerateUniqueRoleID(ctx, execCfg.DB, execCfg.Codec) + if err != nil { + return err + } + } + + restoreQuery := fmt.Sprintf("INSERT INTO system.%s VALUES ($1, $2, $3, $4)", + systemTableName) + opName = systemTableName + "-data-insert" + if _, err := executor.Exec(ctx, opName, txn, restoreQuery, username, password, isRole, id); err != nil { + return errors.Wrapf(err, "inserting data to system.%s", systemTableName) + } + } + return nil +} + // When restoring the settings table, we want to make sure to not override the // version. func settingsRestoreFunc( @@ -181,6 +268,28 @@ func settingsRestoreFunc( return nil } +func roleIDSeqRestoreFunc( + ctx context.Context, + execCfg *sql.ExecutorConfig, + txn *kv.Txn, + systemTableName, tempTableName string, +) error { + if execCfg.Settings.Version.IsActive(ctx, clusterversion.AddSystemUserIDColumn) { + datums, err := execCfg.InternalExecutor.QueryRowEx( + ctx, "role-id-seq-custom-restore", txn, + sessiondata.NodeUserSessionDataOverride, + `SELECT max(user_id) FROM system.users`, + ) + if err != nil { + return err + } + max := tree.MustBeDOid(datums[0]) + return execCfg.DB.Put(ctx, execCfg.Codec.SequenceKey(keys.RoleIDSequenceID), max.Oid+1) + } + // Nothing to be done since no user ids have been assigned. + return nil +} + // systemTableBackupConfiguration is a map from every systemTable present in the // cluster to a configuration struct which specifies how it should be treated by // backup. Every system table should have a specification defined here, enforced @@ -188,6 +297,7 @@ func settingsRestoreFunc( var systemTableBackupConfiguration = map[string]systemBackupConfiguration{ systemschema.UsersTable.GetName(): { shouldIncludeInClusterBackup: optInToClusterBackup, // No desc ID columns. + customRestoreFunc: usersRestoreFunc, }, systemschema.ZonesTable.GetName(): { shouldIncludeInClusterBackup: optInToClusterBackup, // ID in "id". @@ -351,7 +461,9 @@ var systemTableBackupConfiguration = map[string]systemBackupConfiguration{ shouldIncludeInClusterBackup: optInToClusterBackup, // No desc ID columns. }, systemschema.RoleIDSequence.GetName(): { - shouldIncludeInClusterBackup: optOutOfClusterBackup, + shouldIncludeInClusterBackup: optInToClusterBackup, + customRestoreFunc: roleIDSeqRestoreFunc, + restoreInOrder: roleIDSequenceRestoreOrder, }, } diff --git a/pkg/ccl/backupccl/testdata/backup-restore/feature-flags b/pkg/ccl/backupccl/testdata/backup-restore/feature-flags index 8780ff8473ed..bc2e34597508 100644 --- a/pkg/ccl/backupccl/testdata/backup-restore/feature-flags +++ b/pkg/ccl/backupccl/testdata/backup-restore/feature-flags @@ -81,4 +81,9 @@ RESTORE TABLE d.t FROM 'nodelocal://1/deprecated'; ---- NOTICE: The `RESTORE FROM ` syntax will be removed in a future release, please switch over to using `RESTORE FROM IN ` to restore a particular backup from a collection: https://www.cockroachlabs.com/docs/stable/restore.html#view-the-backup-subdirectories +exec-sql +RESTORE SYSTEM USERS FROM 'nodelocal://1/deprecated'; +---- +NOTICE: The `RESTORE FROM ` syntax will be removed in a future release, please switch over to using `RESTORE FROM IN ` to restore a particular backup from a collection: https://www.cockroachlabs.com/docs/stable/restore.html#view-the-backup-subdirectories + subtest end diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP-LOCK-778749314546466817 b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP-LOCK-778749314546466817 new file mode 100644 index 000000000000..19104f172a34 --- /dev/null +++ b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP-LOCK-778749314546466817 @@ -0,0 +1 @@ +lock \ No newline at end of file diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP-STATISTICS b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP-STATISTICS new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP_MANIFEST b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP_MANIFEST new file mode 100644 index 000000000000..446274ecf5c8 Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP_MANIFEST differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP_MANIFEST-CHECKSUM b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP_MANIFEST-CHECKSUM new file mode 100644 index 000000000000..29cf52bd46c2 --- /dev/null +++ b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/BACKUP_MANIFEST-CHECKSUM @@ -0,0 +1 @@ +–èÉA \ No newline at end of file diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/data/778749316061200385.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/data/778749316061200385.sst new file mode 100644 index 000000000000..7f5c92283c4b Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/data/778749316061200385.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/data/778749316187160577.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/data/778749316187160577.sst new file mode 100644 index 000000000000..ec3ac90009ae Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/data/778749316187160577.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/data/778749316254040065.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/data/778749316254040065.sst new file mode 100644 index 000000000000..d81a70864cbc Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/data/778749316254040065.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/fileinfo.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/fileinfo.sst new file mode 100644 index 000000000000..8b761e3f1c50 Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/fileinfo.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/metadata.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/metadata.sst new file mode 100644 index 000000000000..814e201b490f Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/metadata.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c6c9c9cbdfd4cfcfcfcfdfaaabbcfffe b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c6c9c9cbdfd4cfcfcfcfdfaaabbcfffe new file mode 100644 index 000000000000..49b1e216643a Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c6c9c9cbdfd4cfcfcfcfdfaaabbcfffe differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c6c9c9cbdfd4cfcfcfcfdfaaabbcfffe-CHECKSUM b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c6c9c9cbdfd4cfcfcfcfdfaaabbcfffe-CHECKSUM new file mode 100644 index 000000000000..9ffafb9bdf9e --- /dev/null +++ b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c6c9c9cbdfd4cfcfcfcfdfaaabbcfffe-CHECKSUM @@ -0,0 +1 @@ +œ‹ì \ No newline at end of file diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c8c6c7cdcdcbdfd4cfcfcfcfdfaaabbcfffe b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c8c6c7cdcdcbdfd4cfcfcfcfdfaaabbcfffe new file mode 100644 index 000000000000..f46f9785f2c2 Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c8c6c7cdcdcbdfd4cfcfcfcfdfaaabbcfffe differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c8c6c7cdcdcbdfd4cfcfcfcfdfaaabbcfffe-CHECKSUM b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c8c6c7cdcdcbdfd4cfcfcfcfdfaaabbcfffe-CHECKSUM new file mode 100644 index 000000000000..cc7de46ef007 --- /dev/null +++ b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/2022/07/13-152350.46/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5cacfd1c8c6c7cdcdcbdfd4cfcfcfcfdfaaabbcfffe-CHECKSUM @@ -0,0 +1 @@ +ƾÂ: \ No newline at end of file diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP-LOCK-782466617872318465 b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP-LOCK-782466617872318465 new file mode 100644 index 000000000000..19104f172a34 --- /dev/null +++ b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP-LOCK-782466617872318465 @@ -0,0 +1 @@ +lock \ No newline at end of file diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP-STATISTICS b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP-STATISTICS new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP_MANIFEST b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP_MANIFEST new file mode 100644 index 000000000000..d0098cbf4b66 Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP_MANIFEST differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP_MANIFEST-CHECKSUM b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP_MANIFEST-CHECKSUM new file mode 100644 index 000000000000..724758f736b6 --- /dev/null +++ b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/BACKUP_MANIFEST-CHECKSUM @@ -0,0 +1 @@ +y<µã \ No newline at end of file diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466619668725761.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466619668725761.sst new file mode 100644 index 000000000000..c30b1142c49e Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466619668725761.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466619788066817.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466619788066817.sst new file mode 100644 index 000000000000..c377a503da00 Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466619788066817.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466619853340673.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466619853340673.sst new file mode 100644 index 000000000000..8726c4c9b5c1 Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466619853340673.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466620157657089.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466620157657089.sst new file mode 100644 index 000000000000..1ab4086ff803 Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/data/782466620157657089.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/fileinfo.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/fileinfo.sst new file mode 100644 index 000000000000..7f904c1b2679 Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/fileinfo.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/metadata.sst b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/metadata.sst new file mode 100644 index 000000000000..f7ad05aada0f Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/metadata.sst differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/metadata/latest/LATEST-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5caced1cdc8cdcac7dfd4cfcfcfcfdfaaabbcfffe b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/metadata/latest/LATEST-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5caced1cdc8cdcac7dfd4cfcfcfcfdfaaabbcfffe new file mode 100644 index 000000000000..87e8647205b0 --- /dev/null +++ b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/metadata/latest/LATEST-13cdcfcdcdd2cfc8d2ceccdfcecac5cdccc5caced1cdc8cdcac7dfd4cfcfcfcfdfaaabbcfffe @@ -0,0 +1 @@ +/2022/07/13-152350.46 \ No newline at end of file diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c6c6c8cecbcadfd4cfcfcfcfdfaaabbcfffe b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c6c6c8cecbcadfd4cfcfcfcfdfaaabbcfffe new file mode 100644 index 000000000000..4e38e6e64bff Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c6c6c8cecbcadfd4cfcfcfcfdfaaabbcfffe differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c6c6c8cecbcadfd4cfcfcfcfdfaaabbcfffe-CHECKSUM b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c6c6c8cecbcadfd4cfcfcfcfdfaaabbcfffe-CHECKSUM new file mode 100644 index 000000000000..9c31c2d3e05f --- /dev/null +++ b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c6c6c8cecbcadfd4cfcfcfcfdfaaabbcfffe-CHECKSUM @@ -0,0 +1 @@ +ïYÇS \ No newline at end of file diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c8c7c9ccc7c7dfd4cfcfcfcfdfaaabbcfffe b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c8c7c9ccc7c7dfd4cfcfcfcfdfaaabbcfffe new file mode 100644 index 000000000000..5cb3f8b9ee6b Binary files /dev/null and b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c8c7c9ccc7c7dfd4cfcfcfcfdfaaabbcfffe differ diff --git a/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c8c7c9ccc7c7dfd4cfcfcfcfdfaaabbcfffe-CHECKSUM b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c8c7c9ccc7c7dfd4cfcfcfcfdfaaabbcfffe-CHECKSUM new file mode 100644 index 000000000000..5c61472c663c --- /dev/null +++ b/pkg/ccl/backupccl/testdata/restore_old_versions/system-users-restore/22.1.3/progress/BACKUP-CHECKPOINT-13cdcfcdcdd2cfc8d2cdc9dfcec7c5cccec5cfced1c8c7c9ccc7c7dfd4cfcfcfcfdfaaabbcfffe-CHECKSUM @@ -0,0 +1 @@ +ž MÅ \ No newline at end of file