mirror of
https://github.com/juanfont/headscale.git
synced 2026-11-04 04:34:07 +09:00
db, types: add a column for auto-approved routes
It starts empty: the current policy cannot tell which earlier approvals were automatic, so all of them stay as an admin's.
This commit is contained in:
1 parent
177920d84e
commit
20117e7060
7 files changed
+89
-55
No files matched your search
@@ -282,6 +282,18 @@ WHERE tags IS NOT NULL AND tags != '[]' AND tags != '' AND tags != 'null'
|
||||
},
|
||||
Rollback: func(db *gorm.DB) error { return nil },
|
||||
},
|
||||
{
|
||||
// Records which approved routes only auto-approval granted. It
|
||||
// starts empty: the current policy cannot tell which earlier
|
||||
// approvals were automatic, so all of them stay as an admin's.
|
||||
ID: "202610211200-node-auto-approved-routes",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.Transaction(func(tx *gorm.DB) error {
|
||||
return tx.Exec(`ALTER TABLE nodes ADD COLUMN auto_approved_routes text`).Error
|
||||
})
|
||||
},
|
||||
Rollback: func(db *gorm.DB) error { return nil },
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -117,6 +117,11 @@ func TestSQLiteMigrationAndDataValidation(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Len(t, nodes, 5)
|
||||
|
||||
// Approvals from before the upgrade carry no auto-approval mark.
|
||||
for _, n := range nodes {
|
||||
assert.Empty(t, n.AutoApprovedRoutes, "node %d", n.ID)
|
||||
}
|
||||
|
||||
// Pre-auth key ids are preserved, so every node keeps its key.
|
||||
for _, n := range nodes {
|
||||
require.NotNil(t, n.AuthKeyID, "node %d", n.ID)
|
||||
|
||||
@@ -89,6 +89,7 @@ CREATE TABLE nodes(
|
||||
last_seen datetime,
|
||||
expiry datetime,
|
||||
approved_routes text,
|
||||
auto_approved_routes text,
|
||||
|
||||
created_at datetime,
|
||||
updated_at datetime,
|
||||
|
||||
@@ -1960,7 +1960,8 @@ var nodeFieldImpact = map[string]string{
|
||||
"ID": "relation", "IPv4": "relation", "IPv6": "relation",
|
||||
"UserID": "relation", "User": "relation", "Tags": "relation",
|
||||
"ApprovedRoutes": "relation", "Hostinfo": "relation",
|
||||
"IsOnline": "election", "Unhealthy": "election",
|
||||
"AutoApprovedRoutes": "payload",
|
||||
"IsOnline": "election", "Unhealthy": "election",
|
||||
"MachineKey": "payload", "NodeKey": "payload", "DiscoKey": "payload",
|
||||
"Endpoints": "payload", "Hostname": "payload", "GivenName": "payload",
|
||||
"RegisterMethod": "payload", "AuthKeyID": "payload", "AuthKey": "payload",
|
||||
|
||||
@@ -184,6 +184,11 @@ type Node struct {
|
||||
// See [Node.Hostinfo]
|
||||
ApprovedRoutes Prefixes `gorm:"column:approved_routes;serializer:json"`
|
||||
|
||||
// AutoApprovedRoutes are the approved routes only auto-approval granted.
|
||||
// The node loses one when it stops announcing it; a route an admin
|
||||
// approved stays.
|
||||
AutoApprovedRoutes Prefixes `gorm:"column:auto_approved_routes;serializer:json"`
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
|
||||
@@ -71,6 +71,7 @@ func (src *Node) Clone() *Node {
|
||||
dst.LastSeen = new(*src.LastSeen)
|
||||
}
|
||||
dst.ApprovedRoutes = append(src.ApprovedRoutes[:0:0], src.ApprovedRoutes...)
|
||||
dst.AutoApprovedRoutes = append(src.AutoApprovedRoutes[:0:0], src.AutoApprovedRoutes...)
|
||||
if dst.DeletedAt != nil {
|
||||
dst.DeletedAt = new(*src.DeletedAt)
|
||||
}
|
||||
@@ -82,33 +83,34 @@ func (src *Node) Clone() *Node {
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _NodeCloneNeedsRegeneration = Node(struct {
|
||||
ID NodeID
|
||||
MachineKey key.MachinePublic
|
||||
NodeKey key.NodePublic
|
||||
DiscoKey key.DiscoPublic
|
||||
Endpoints AddrPorts
|
||||
Hostinfo *tailcfg.Hostinfo
|
||||
IPv4 *netip.Addr
|
||||
IPv6 *netip.Addr
|
||||
Hostname string
|
||||
GivenName string
|
||||
UserID *uint
|
||||
User *User
|
||||
RegisterMethod string
|
||||
Tags Strings
|
||||
AuthKeyID *uint64
|
||||
AuthKey *Credential
|
||||
Expiry *time.Time
|
||||
LastSeen *time.Time
|
||||
ApprovedRoutes Prefixes
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
IsOnline *bool
|
||||
Unhealthy bool
|
||||
ActiveSessions int
|
||||
SessionEpoch uint64
|
||||
SessionStart time.Time
|
||||
ID NodeID
|
||||
MachineKey key.MachinePublic
|
||||
NodeKey key.NodePublic
|
||||
DiscoKey key.DiscoPublic
|
||||
Endpoints AddrPorts
|
||||
Hostinfo *tailcfg.Hostinfo
|
||||
IPv4 *netip.Addr
|
||||
IPv6 *netip.Addr
|
||||
Hostname string
|
||||
GivenName string
|
||||
UserID *uint
|
||||
User *User
|
||||
RegisterMethod string
|
||||
Tags Strings
|
||||
AuthKeyID *uint64
|
||||
AuthKey *Credential
|
||||
Expiry *time.Time
|
||||
LastSeen *time.Time
|
||||
ApprovedRoutes Prefixes
|
||||
AutoApprovedRoutes Prefixes
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
IsOnline *bool
|
||||
Unhealthy bool
|
||||
ActiveSessions int
|
||||
SessionEpoch uint64
|
||||
SessionStart time.Time
|
||||
}{})
|
||||
|
||||
// Clone makes a deep copy of PreAuthKey.
|
||||
|
||||
@@ -252,6 +252,13 @@ func (v NodeView) LastSeen() views.ValuePointer[time.Time] {
|
||||
func (v NodeView) ApprovedRoutes() views.Slice[netip.Prefix] {
|
||||
return views.SliceOf(v.ж.ApprovedRoutes)
|
||||
}
|
||||
|
||||
// AutoApprovedRoutes are the approved routes only auto-approval granted.
|
||||
// The node loses one when it stops announcing it; a route an admin
|
||||
// approved stays.
|
||||
func (v NodeView) AutoApprovedRoutes() views.Slice[netip.Prefix] {
|
||||
return views.SliceOf(v.ж.AutoApprovedRoutes)
|
||||
}
|
||||
func (v NodeView) CreatedAt() time.Time { return v.ж.CreatedAt }
|
||||
func (v NodeView) UpdatedAt() time.Time { return v.ж.UpdatedAt }
|
||||
func (v NodeView) DeletedAt() views.ValuePointer[time.Time] {
|
||||
@@ -291,33 +298,34 @@ func (v NodeView) String() string { return v.ж.String() }
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _NodeViewNeedsRegeneration = Node(struct {
|
||||
ID NodeID
|
||||
MachineKey key.MachinePublic
|
||||
NodeKey key.NodePublic
|
||||
DiscoKey key.DiscoPublic
|
||||
Endpoints AddrPorts
|
||||
Hostinfo *tailcfg.Hostinfo
|
||||
IPv4 *netip.Addr
|
||||
IPv6 *netip.Addr
|
||||
Hostname string
|
||||
GivenName string
|
||||
UserID *uint
|
||||
User *User
|
||||
RegisterMethod string
|
||||
Tags Strings
|
||||
AuthKeyID *uint64
|
||||
AuthKey *Credential
|
||||
Expiry *time.Time
|
||||
LastSeen *time.Time
|
||||
ApprovedRoutes Prefixes
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
IsOnline *bool
|
||||
Unhealthy bool
|
||||
ActiveSessions int
|
||||
SessionEpoch uint64
|
||||
SessionStart time.Time
|
||||
ID NodeID
|
||||
MachineKey key.MachinePublic
|
||||
NodeKey key.NodePublic
|
||||
DiscoKey key.DiscoPublic
|
||||
Endpoints AddrPorts
|
||||
Hostinfo *tailcfg.Hostinfo
|
||||
IPv4 *netip.Addr
|
||||
IPv6 *netip.Addr
|
||||
Hostname string
|
||||
GivenName string
|
||||
UserID *uint
|
||||
User *User
|
||||
RegisterMethod string
|
||||
Tags Strings
|
||||
AuthKeyID *uint64
|
||||
AuthKey *Credential
|
||||
Expiry *time.Time
|
||||
LastSeen *time.Time
|
||||
ApprovedRoutes Prefixes
|
||||
AutoApprovedRoutes Prefixes
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
IsOnline *bool
|
||||
Unhealthy bool
|
||||
ActiveSessions int
|
||||
SessionEpoch uint64
|
||||
SessionStart time.Time
|
||||
}{})
|
||||
|
||||
// View returns a read-only view of PreAuthKey.
|
||||
|
||||
Reference in new issue
Block a user