diff --git a/hscontrol/db/db.go b/hscontrol/db/db.go index 591c1c92..7f4ecb32 100644 --- a/hscontrol/db/db.go +++ b/hscontrol/db/db.go @@ -512,7 +512,7 @@ COMMIT; err := tx.AutoMigrate(&types.User{}) if err != nil { - return err + return fmt.Errorf("automigrating types.User: %w", err) } return nil @@ -527,7 +527,7 @@ COMMIT; Migrate: func(tx *gorm.DB) error { err := tx.AutoMigrate(&types.User{}) if err != nil { - return err + return fmt.Errorf("automigrating types.User: %w", err) } // Set up indexes and unique constraints outside of GORM, it does not support @@ -575,7 +575,7 @@ COMMIT; err := tx.AutoMigrate(&types.Route{}) if err != nil { - return err + return fmt.Errorf("automigrating types.Route: %w", err) } return nil @@ -589,11 +589,33 @@ COMMIT; Migrate: func(tx *gorm.DB) error { err := tx.AutoMigrate(&types.PreAuthKey{}) if err != nil { - return err + return fmt.Errorf("automigrating types.PreAuthKey: %w", err) } err = tx.AutoMigrate(&types.Node{}) if err != nil { - return err + return fmt.Errorf("automigrating types.Node: %w", err) + } + + return nil + }, + Rollback: func(db *gorm.DB) error { return nil }, + }, + // Ensure there are no nodes refering to a deleted preauthkey. + { + ID: "202502070949", + Migrate: func(tx *gorm.DB) error { + if tx.Migrator().HasTable(&types.PreAuthKey{}) { + err := tx.Exec(` +UPDATE nodes +SET auth_key_id = NULL +WHERE auth_key_id IS NOT NULL +AND auth_key_id NOT IN ( + SELECT id FROM pre_auth_keys +); + `).Error + if err != nil { + return fmt.Errorf("setting auth_key to null on nodes with non-existing keys: %w", err) + } } return nil diff --git a/hscontrol/db/db_test.go b/hscontrol/db/db_test.go index 8ca77303..079f632f 100644 --- a/hscontrol/db/db_test.go +++ b/hscontrol/db/db_test.go @@ -201,6 +201,26 @@ func TestMigrationsSQLite(t *testing.T) { } }, }, + { + dbPath: "testdata/failing-node-preauth-constraint.sqlite", + wantFunc: func(t *testing.T, h *HSDatabase) { + nodes, err := Read(h.DB, func(rx *gorm.DB) (types.Nodes, error) { + return ListNodes(rx) + }) + require.NoError(t, err) + + for _, node := range nodes { + assert.Falsef(t, node.MachineKey.IsZero(), "expected non zero machinekey") + assert.Contains(t, node.MachineKey.String(), "mkey:") + assert.Falsef(t, node.NodeKey.IsZero(), "expected non zero nodekey") + assert.Contains(t, node.NodeKey.String(), "nodekey:") + assert.Falsef(t, node.DiscoKey.IsZero(), "expected non zero discokey") + assert.Contains(t, node.DiscoKey.String(), "discokey:") + assert.Nil(t, node.AuthKey) + assert.Nil(t, node.AuthKeyID) + } + }, + }, } for _, tt := range tests { diff --git a/hscontrol/db/testdata/failing-node-preauth-constraint.sqlite b/hscontrol/db/testdata/failing-node-preauth-constraint.sqlite new file mode 100644 index 00000000..911c2434 Binary files /dev/null and b/hscontrol/db/testdata/failing-node-preauth-constraint.sqlite differ