4
4
"strings"
5
5
6
6
"github.com/pkg/errors"
7
+ "github.com/rs/zerolog/log"
8
+ "gorm.io/gorm"
7
9
)
8
10
9
11
func (db Database ) autoMigrate () error {
@@ -21,12 +23,18 @@ func (db Database) autoMigrate() error {
21
23
return err
22
24
}
23
25
26
+ err := db .MigrateNodeLastSeen ()
27
+ if err != nil {
28
+ return errors .Wrap (err , "failed to migrate node last seen data" )
29
+ }
30
+
24
31
return nil
25
32
}
26
33
27
34
func (db Database ) migrateNodes () error {
28
35
// if nodes are already migrated skip migration
29
36
if result := db .gormDB .First (& Node {}); result .Error == nil {
37
+ log .Info ().Msg ("nodes Interfaces are already migrated" )
30
38
return nil
31
39
}
32
40
@@ -36,56 +44,63 @@ func (db Database) migrateNodes() error {
36
44
IPs string `json:"ips"`
37
45
}
38
46
47
+ // we'd only load the data we actually need from the database
39
48
type nodeType struct {
40
- NodeID uint64 `json:"node_id" gorm:"primaryKey;autoIncrement"`
41
- FarmID uint64 `json:"farm_id" gorm:"not null;check:farm_id> 0;foreignKey:FarmID;references:FarmID;constraint:OnDelete:RESTRICT"`
42
- TwinID uint64 `json:"twin_id" gorm:"not null;unique;check:twin_id > 0;foreignKey:TwinID;references:TwinID;constraint:OnDelete:RESTRICT"`
43
-
44
- Location Location `json:"location" gorm:"not null;type:json;serializer:json"`
45
-
46
- Resources Resources `json:"resources" gorm:"not null;type:json;serializer:json"`
47
- Interfaces []oldInterface `gorm:"not null;type:json;serializer:json"`
48
- SecureBoot bool `json:"secure_boot"`
49
- Virtualized bool `json:"virtualized"`
50
- SerialNumber string `json:"serial_number"`
51
-
52
- Approved bool `json:"approved"`
49
+ NodeID uint64 `json:"node_id" gorm:"primaryKey"`
50
+ Interfaces []oldInterface `gorm:"not null;type:json;serializer:json"`
53
51
}
54
52
55
- var nodes []nodeType
56
- result := db .gormDB .Model (& Node {}).Find (& nodes )
57
- if result .Error != nil {
58
- return result .Error
59
- }
53
+ // Use a single transaction for all updates to ensure atomicity
54
+ return db .Transaction (func (tx * gorm.DB ) error {
55
+ var nodes []nodeType
56
+ if err := tx .Model (& Node {}).Find (& nodes ).Error ; err != nil {
57
+ return err
58
+ }
60
59
61
- for _ , node := range nodes {
62
- var interfaces []Interface
63
- for _ , i := range node .Interfaces {
64
- ips := strings .Split (i .IPs , "/" )
65
- newInterface := Interface {
66
- Name : i .Name ,
67
- Mac : i .Mac ,
68
- IPs : ips ,
60
+ for _ , node := range nodes {
61
+ var interfaces []Interface
62
+ for _ , i := range node .Interfaces {
63
+ ips := strings .Split (i .IPs , "/" )
64
+ newInterface := Interface {
65
+ Name : i .Name ,
66
+ Mac : i .Mac ,
67
+ IPs : ips ,
68
+ }
69
+ interfaces = append (interfaces , newInterface )
69
70
}
70
- interfaces = append (interfaces , newInterface )
71
- }
72
71
73
- updatedNode := Node {
74
- NodeID : node .NodeID ,
75
- FarmID : node .FarmID ,
76
- TwinID : node .TwinID ,
77
- Location : node .Location ,
78
- Resources : node .Resources ,
79
- Interfaces : interfaces ,
80
- SecureBoot : node .SecureBoot ,
81
- Virtualized : node .Virtualized ,
82
- Approved : node .Approved ,
72
+ // Update only the interfaces field
73
+ if err := tx .Model (& Node {}).
74
+ Where ("node_id = ?" , node .NodeID ).
75
+ Update ("interfaces" , interfaces ).Error ; err != nil {
76
+ return err // This will roll back the entire transaction
77
+ }
83
78
}
84
79
85
- err := db .gormDB .Model (& Node {}).Where ("node_id = ?" , node .NodeID ).Updates (updatedNode ).Error
86
- if err != nil {
87
- return err
88
- }
80
+ return nil
81
+ })
82
+ }
83
+
84
+ // MigrateNodeLastSeen updates the LastSeen field for existing nodes that don't have it set
85
+ func (db Database ) MigrateNodeLastSeen () error {
86
+ query := `
87
+ UPDATE nodes n
88
+ SET last_seen = (
89
+ SELECT MAX(timestamp)
90
+ FROM uptime_reports ur
91
+ WHERE ur.node_id = n.node_id
92
+ )
93
+ WHERE (last_seen IS NULL OR last_seen = '0001-01-01 00:00:00+00')
94
+ AND EXISTS (
95
+ SELECT 1
96
+ FROM uptime_reports ur
97
+ WHERE ur.node_id = n.node_id
98
+ )
99
+ `
100
+
101
+ result := db .gormDB .Exec (query )
102
+ if result .Error == nil {
103
+ log .Info ().Msgf ("Migration: Updated LastSeen for %d nodes" , result .RowsAffected )
89
104
}
90
- return nil
105
+ return result . Error
91
106
}
0 commit comments