db: use PolicyManager for RequestTags migration
Refactor the RequestTags migration (202601121700-migrate-hostinfo-request-tags) to use PolicyManager.NodeCanHaveTag() instead of reimplementing tag validation. Changes: - NewHeadscaleDatabase now accepts *types.Config to allow migrations access to policy configuration - Add loadPolicyBytes helper to load policy from file or DB based on config - Add standalone GetPolicy(tx *gorm.DB) for use during migrations - Replace custom tag validation logic with PolicyManager Benefits: - Full HuJSON parsing support (not just JSON) - Proper group expansion via PolicyManager - Support for nested tags and autogroups - Works with both file and database policy modes - Single source of truth for tag validation Co-Authored-By: Shourya Gautam <shouryamgautam@gmail.com>
This commit is contained in:
parent
22afb2c61b
commit
4e1834adaf
9 changed files with 413 additions and 103 deletions
|
|
@ -2,8 +2,10 @@ package db
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/juanfont/headscale/hscontrol/types"
|
||||
"github.com/juanfont/headscale/hscontrol/util"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
|
@ -24,14 +26,22 @@ func (hsdb *HSDatabase) SetPolicy(policy string) (*types.Policy, error) {
|
|||
|
||||
// GetPolicy returns the latest policy in the database.
|
||||
func (hsdb *HSDatabase) GetPolicy() (*types.Policy, error) {
|
||||
return GetPolicy(hsdb.DB)
|
||||
}
|
||||
|
||||
// GetPolicy returns the latest policy from the database.
|
||||
// This standalone function can be used in contexts where HSDatabase is not available,
|
||||
// such as during migrations.
|
||||
func GetPolicy(tx *gorm.DB) (*types.Policy, error) {
|
||||
var p types.Policy
|
||||
|
||||
// Query:
|
||||
// SELECT * FROM policies ORDER BY id DESC LIMIT 1;
|
||||
if err := hsdb.DB.
|
||||
err := tx.
|
||||
Order("id DESC").
|
||||
Limit(1).
|
||||
First(&p).Error; err != nil {
|
||||
First(&p).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, types.ErrPolicyNotFound
|
||||
}
|
||||
|
|
@ -41,3 +51,41 @@ func (hsdb *HSDatabase) GetPolicy() (*types.Policy, error) {
|
|||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
// PolicyBytes loads policy configuration from file or database based on the configured mode.
|
||||
// Returns nil if no policy is configured, which is valid.
|
||||
// This standalone function can be used in contexts where HSDatabase is not available,
|
||||
// such as during migrations.
|
||||
func PolicyBytes(tx *gorm.DB, cfg *types.Config) ([]byte, error) {
|
||||
switch cfg.Policy.Mode {
|
||||
case types.PolicyModeFile:
|
||||
path := cfg.Policy.Path
|
||||
|
||||
// It is fine to start headscale without a policy file.
|
||||
if len(path) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
absPath := util.AbsolutePathFromConfigPath(path)
|
||||
|
||||
return os.ReadFile(absPath)
|
||||
|
||||
case types.PolicyModeDB:
|
||||
p, err := GetPolicy(tx)
|
||||
if err != nil {
|
||||
if errors.Is(err, types.ErrPolicyNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if p.Data == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return []byte(p.Data), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue