mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-11-04 01:51:04 +01:00 
			
		
		
		
	Consolidate machine related lookups
This commit moves the routes lookup functions to be subcommands of Machine, making them a lot simpler and more specific/composable. It also moves the register command from cli.go into machine, so we can clear out the extra file. Finally a toProto function has been added to convert between the machine database model and the proto/rpc model.
This commit is contained in:
		
							parent
							
								
									67adea5cab
								
							
						
					
					
						commit
						787814ea89
					
				
							
								
								
									
										43
									
								
								cli.go
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								cli.go
									
									
									
									
									
								
							@ -1,43 +0,0 @@
 | 
				
			|||||||
package headscale
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"gorm.io/gorm"
 | 
					 | 
				
			||||||
	"tailscale.com/types/wgkey"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// RegisterMachine is executed from the CLI to register a new Machine using its MachineKey
 | 
					 | 
				
			||||||
func (h *Headscale) RegisterMachine(key string, namespace string) (*Machine, error) {
 | 
					 | 
				
			||||||
	ns, err := h.GetNamespace(namespace)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	mKey, err := wgkey.ParseHex(key)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	m := Machine{}
 | 
					 | 
				
			||||||
	if result := h.db.First(&m, "machine_key = ?", mKey.HexString()); errors.Is(result.Error, gorm.ErrRecordNotFound) {
 | 
					 | 
				
			||||||
		return nil, errors.New("Machine not found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	h.updateMachineExpiry(&m) // update the machine's expiry before bailing if its already registered
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if m.isAlreadyRegistered() {
 | 
					 | 
				
			||||||
		return nil, errors.New("Machine already registered")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ip, err := h.getAvailableIP()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	m.IPAddress = ip.String()
 | 
					 | 
				
			||||||
	m.NamespaceID = ns.ID
 | 
					 | 
				
			||||||
	m.Registered = true
 | 
					 | 
				
			||||||
	m.RegisterMethod = "cli"
 | 
					 | 
				
			||||||
	h.db.Save(&m)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return &m, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										249
									
								
								machine.go
									
									
									
									
									
								
							
							
						
						
									
										249
									
								
								machine.go
									
									
									
									
									
								
							@ -2,6 +2,7 @@ package headscale
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
@ -10,8 +11,11 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/fatih/set"
 | 
						"github.com/fatih/set"
 | 
				
			||||||
	"github.com/rs/zerolog/log"
 | 
						"github.com/rs/zerolog/log"
 | 
				
			||||||
 | 
						"google.golang.org/protobuf/types/known/timestamppb"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
 | 
				
			||||||
	"gorm.io/datatypes"
 | 
						"gorm.io/datatypes"
 | 
				
			||||||
 | 
						"gorm.io/gorm"
 | 
				
			||||||
	"inet.af/netaddr"
 | 
						"inet.af/netaddr"
 | 
				
			||||||
	"tailscale.com/tailcfg"
 | 
						"tailscale.com/tailcfg"
 | 
				
			||||||
	"tailscale.com/types/wgkey"
 | 
						"tailscale.com/types/wgkey"
 | 
				
			||||||
@ -91,7 +95,7 @@ func (h *Headscale) updateMachineExpiry(m *Machine) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (h *Headscale) getDirectPeers(m *Machine) (Machines, error) {
 | 
					func (h *Headscale) getDirectPeers(m *Machine) (Machines, error) {
 | 
				
			||||||
	log.Trace().
 | 
						log.Trace().
 | 
				
			||||||
		Str("func", "getDirectPeers").
 | 
							Caller().
 | 
				
			||||||
		Str("machine", m.Name).
 | 
							Str("machine", m.Name).
 | 
				
			||||||
		Msg("Finding direct peers")
 | 
							Msg("Finding direct peers")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -105,7 +109,7 @@ func (h *Headscale) getDirectPeers(m *Machine) (Machines, error) {
 | 
				
			|||||||
	sort.Slice(machines, func(i, j int) bool { return machines[i].ID < machines[j].ID })
 | 
						sort.Slice(machines, func(i, j int) bool { return machines[i].ID < machines[j].ID })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Trace().
 | 
						log.Trace().
 | 
				
			||||||
		Str("func", "getDirectmachines").
 | 
							Caller().
 | 
				
			||||||
		Str("machine", m.Name).
 | 
							Str("machine", m.Name).
 | 
				
			||||||
		Msgf("Found direct machines: %s", machines.String())
 | 
							Msgf("Found direct machines: %s", machines.String())
 | 
				
			||||||
	return machines, nil
 | 
						return machines, nil
 | 
				
			||||||
@ -114,7 +118,7 @@ func (h *Headscale) getDirectPeers(m *Machine) (Machines, error) {
 | 
				
			|||||||
// getShared fetches machines that are shared to the `Namespace` of the machine we are getting peers for
 | 
					// getShared fetches machines that are shared to the `Namespace` of the machine we are getting peers for
 | 
				
			||||||
func (h *Headscale) getShared(m *Machine) (Machines, error) {
 | 
					func (h *Headscale) getShared(m *Machine) (Machines, error) {
 | 
				
			||||||
	log.Trace().
 | 
						log.Trace().
 | 
				
			||||||
		Str("func", "getShared").
 | 
							Caller().
 | 
				
			||||||
		Str("machine", m.Name).
 | 
							Str("machine", m.Name).
 | 
				
			||||||
		Msg("Finding shared peers")
 | 
							Msg("Finding shared peers")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -132,7 +136,7 @@ func (h *Headscale) getShared(m *Machine) (Machines, error) {
 | 
				
			|||||||
	sort.Slice(peers, func(i, j int) bool { return peers[i].ID < peers[j].ID })
 | 
						sort.Slice(peers, func(i, j int) bool { return peers[i].ID < peers[j].ID })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Trace().
 | 
						log.Trace().
 | 
				
			||||||
		Str("func", "getShared").
 | 
							Caller().
 | 
				
			||||||
		Str("machine", m.Name).
 | 
							Str("machine", m.Name).
 | 
				
			||||||
		Msgf("Found shared peers: %s", peers.String())
 | 
							Msgf("Found shared peers: %s", peers.String())
 | 
				
			||||||
	return peers, nil
 | 
						return peers, nil
 | 
				
			||||||
@ -141,7 +145,7 @@ func (h *Headscale) getShared(m *Machine) (Machines, error) {
 | 
				
			|||||||
// getSharedTo fetches the machines of the namespaces this machine is shared in
 | 
					// getSharedTo fetches the machines of the namespaces this machine is shared in
 | 
				
			||||||
func (h *Headscale) getSharedTo(m *Machine) (Machines, error) {
 | 
					func (h *Headscale) getSharedTo(m *Machine) (Machines, error) {
 | 
				
			||||||
	log.Trace().
 | 
						log.Trace().
 | 
				
			||||||
		Str("func", "getSharedTo").
 | 
							Caller().
 | 
				
			||||||
		Str("machine", m.Name).
 | 
							Str("machine", m.Name).
 | 
				
			||||||
		Msg("Finding peers in namespaces this machine is shared with")
 | 
							Msg("Finding peers in namespaces this machine is shared with")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -157,13 +161,13 @@ func (h *Headscale) getSharedTo(m *Machine) (Machines, error) {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return Machines{}, err
 | 
								return Machines{}, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		peers = append(peers, *namespaceMachines...)
 | 
							peers = append(peers, namespaceMachines...)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sort.Slice(peers, func(i, j int) bool { return peers[i].ID < peers[j].ID })
 | 
						sort.Slice(peers, func(i, j int) bool { return peers[i].ID < peers[j].ID })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Trace().
 | 
						log.Trace().
 | 
				
			||||||
		Str("func", "getSharedTo").
 | 
							Caller().
 | 
				
			||||||
		Str("machine", m.Name).
 | 
							Str("machine", m.Name).
 | 
				
			||||||
		Msgf("Found peers we are shared with: %s", peers.String())
 | 
							Msgf("Found peers we are shared with: %s", peers.String())
 | 
				
			||||||
	return peers, nil
 | 
						return peers, nil
 | 
				
			||||||
@ -173,7 +177,7 @@ func (h *Headscale) getPeers(m *Machine) (Machines, error) {
 | 
				
			|||||||
	direct, err := h.getDirectPeers(m)
 | 
						direct, err := h.getDirectPeers(m)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Error().
 | 
							log.Error().
 | 
				
			||||||
			Str("func", "getPeers").
 | 
								Caller().
 | 
				
			||||||
			Err(err).
 | 
								Err(err).
 | 
				
			||||||
			Msg("Cannot fetch peers")
 | 
								Msg("Cannot fetch peers")
 | 
				
			||||||
		return Machines{}, err
 | 
							return Machines{}, err
 | 
				
			||||||
@ -182,7 +186,7 @@ func (h *Headscale) getPeers(m *Machine) (Machines, error) {
 | 
				
			|||||||
	shared, err := h.getShared(m)
 | 
						shared, err := h.getShared(m)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Error().
 | 
							log.Error().
 | 
				
			||||||
			Str("func", "getShared").
 | 
								Caller().
 | 
				
			||||||
			Err(err).
 | 
								Err(err).
 | 
				
			||||||
			Msg("Cannot fetch peers")
 | 
								Msg("Cannot fetch peers")
 | 
				
			||||||
		return Machines{}, err
 | 
							return Machines{}, err
 | 
				
			||||||
@ -191,7 +195,7 @@ func (h *Headscale) getPeers(m *Machine) (Machines, error) {
 | 
				
			|||||||
	sharedTo, err := h.getSharedTo(m)
 | 
						sharedTo, err := h.getSharedTo(m)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Error().
 | 
							log.Error().
 | 
				
			||||||
			Str("func", "sharedTo").
 | 
								Caller().
 | 
				
			||||||
			Err(err).
 | 
								Err(err).
 | 
				
			||||||
			Msg("Cannot fetch peers")
 | 
								Msg("Cannot fetch peers")
 | 
				
			||||||
		return Machines{}, err
 | 
							return Machines{}, err
 | 
				
			||||||
@ -203,13 +207,21 @@ func (h *Headscale) getPeers(m *Machine) (Machines, error) {
 | 
				
			|||||||
	sort.Slice(peers, func(i, j int) bool { return peers[i].ID < peers[j].ID })
 | 
						sort.Slice(peers, func(i, j int) bool { return peers[i].ID < peers[j].ID })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Trace().
 | 
						log.Trace().
 | 
				
			||||||
		Str("func", "getShared").
 | 
							Caller().
 | 
				
			||||||
		Str("machine", m.Name).
 | 
							Str("machine", m.Name).
 | 
				
			||||||
		Msgf("Found total peers: %s", peers.String())
 | 
							Msgf("Found total peers: %s", peers.String())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return peers, nil
 | 
						return peers, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *Headscale) ListMachines() ([]Machine, error) {
 | 
				
			||||||
 | 
						machines := []Machine{}
 | 
				
			||||||
 | 
						if err := h.db.Preload("AuthKey").Preload("AuthKey.Namespace").Preload("Namespace").Find(&machines).Error; err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return machines, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetMachine finds a Machine by name and namespace and returns the Machine struct
 | 
					// GetMachine finds a Machine by name and namespace and returns the Machine struct
 | 
				
			||||||
func (h *Headscale) GetMachine(namespace string, name string) (*Machine, error) {
 | 
					func (h *Headscale) GetMachine(namespace string, name string) (*Machine, error) {
 | 
				
			||||||
	machines, err := h.ListMachinesInNamespace(namespace)
 | 
						machines, err := h.ListMachinesInNamespace(namespace)
 | 
				
			||||||
@ -217,7 +229,7 @@ func (h *Headscale) GetMachine(namespace string, name string) (*Machine, error)
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, m := range *machines {
 | 
						for _, m := range machines {
 | 
				
			||||||
		if m.Name == name {
 | 
							if m.Name == name {
 | 
				
			||||||
			return &m, nil
 | 
								return &m, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -326,7 +338,7 @@ func (h *Headscale) isOutdated(m *Machine) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	lastChange := h.getLastStateChange(namespaces...)
 | 
						lastChange := h.getLastStateChange(namespaces...)
 | 
				
			||||||
	log.Trace().
 | 
						log.Trace().
 | 
				
			||||||
		Str("func", "keepAlive").
 | 
							Caller().
 | 
				
			||||||
		Str("machine", m.Name).
 | 
							Str("machine", m.Name).
 | 
				
			||||||
		Time("last_successful_update", *m.LastSuccessfulUpdate).
 | 
							Time("last_successful_update", *m.LastSuccessfulUpdate).
 | 
				
			||||||
		Time("last_state_change", lastChange).
 | 
							Time("last_state_change", lastChange).
 | 
				
			||||||
@ -405,7 +417,7 @@ func (m Machine) toNode(baseDomain string, dnsConfig *tailcfg.DNSConfig, include
 | 
				
			|||||||
	ip, err := netaddr.ParseIPPrefix(fmt.Sprintf("%s/32", m.IPAddress))
 | 
						ip, err := netaddr.ParseIPPrefix(fmt.Sprintf("%s/32", m.IPAddress))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Trace().
 | 
							log.Trace().
 | 
				
			||||||
			Str("func", "toNode").
 | 
								Caller().
 | 
				
			||||||
			Str("ip", m.IPAddress).
 | 
								Str("ip", m.IPAddress).
 | 
				
			||||||
			Msgf("Failed to parse IP Prefix from IP: %s", m.IPAddress)
 | 
								Msgf("Failed to parse IP Prefix from IP: %s", m.IPAddress)
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@ -508,3 +520,212 @@ func (m Machine) toNode(baseDomain string, dnsConfig *tailcfg.DNSConfig, include
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return &n, nil
 | 
						return &n, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Machine) toProto() *v1.Machine {
 | 
				
			||||||
 | 
						machine := &v1.Machine{
 | 
				
			||||||
 | 
							Id:         m.ID,
 | 
				
			||||||
 | 
							MachineKey: m.MachineKey,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NodeKey:   m.NodeKey,
 | 
				
			||||||
 | 
							DiscoKey:  m.DiscoKey,
 | 
				
			||||||
 | 
							IpAddress: m.IPAddress,
 | 
				
			||||||
 | 
							Name:      m.Name,
 | 
				
			||||||
 | 
							Namespace: m.Namespace.toProto(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Registered: m.Registered,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// TODO(kradalby): Implement register method enum converter
 | 
				
			||||||
 | 
							// RegisterMethod: ,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CreatedAt: timestamppb.New(m.CreatedAt),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if m.AuthKey != nil {
 | 
				
			||||||
 | 
							machine.PreAuthKey = m.AuthKey.toProto()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if m.LastSeen != nil {
 | 
				
			||||||
 | 
							machine.LastSeen = timestamppb.New(*m.LastSeen)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if m.LastSuccessfulUpdate != nil {
 | 
				
			||||||
 | 
							machine.LastSuccessfulUpdate = timestamppb.New(*m.LastSuccessfulUpdate)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if m.Expiry != nil {
 | 
				
			||||||
 | 
							machine.Expiry = timestamppb.New(*m.Expiry)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return machine
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RegisterMachine is executed from the CLI to register a new Machine using its MachineKey
 | 
				
			||||||
 | 
					func (h *Headscale) RegisterMachine(key string, namespace string) (*Machine, error) {
 | 
				
			||||||
 | 
						ns, err := h.GetNamespace(namespace)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mKey, err := wgkey.ParseHex(key)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m := Machine{}
 | 
				
			||||||
 | 
						if result := h.db.First(&m, "machine_key = ?", mKey.HexString()); errors.Is(result.Error, gorm.ErrRecordNotFound) {
 | 
				
			||||||
 | 
							return nil, errors.New("Machine not found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Trace().
 | 
				
			||||||
 | 
							Caller().
 | 
				
			||||||
 | 
							Str("machine", m.Name).
 | 
				
			||||||
 | 
							Msg("Attempting to register machine")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if m.isAlreadyRegistered() {
 | 
				
			||||||
 | 
							err := errors.New("Machine already registered")
 | 
				
			||||||
 | 
							log.Error().
 | 
				
			||||||
 | 
								Caller().
 | 
				
			||||||
 | 
								Err(err).
 | 
				
			||||||
 | 
								Str("machine", m.Name).
 | 
				
			||||||
 | 
								Msg("Attempting to register machine")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ip, err := h.getAvailableIP()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error().
 | 
				
			||||||
 | 
								Caller().
 | 
				
			||||||
 | 
								Err(err).
 | 
				
			||||||
 | 
								Str("machine", m.Name).
 | 
				
			||||||
 | 
								Msg("Could not find IP for the new machine")
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Trace().
 | 
				
			||||||
 | 
							Caller().
 | 
				
			||||||
 | 
							Str("machine", m.Name).
 | 
				
			||||||
 | 
							Str("ip", ip.String()).
 | 
				
			||||||
 | 
							Msg("Found IP for host")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m.IPAddress = ip.String()
 | 
				
			||||||
 | 
						m.NamespaceID = ns.ID
 | 
				
			||||||
 | 
						m.Registered = true
 | 
				
			||||||
 | 
						m.RegisterMethod = "cli"
 | 
				
			||||||
 | 
						h.db.Save(&m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Trace().
 | 
				
			||||||
 | 
							Caller().
 | 
				
			||||||
 | 
							Str("machine", m.Name).
 | 
				
			||||||
 | 
							Str("ip", ip.String()).
 | 
				
			||||||
 | 
							Msg("Machine registered with the database")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &m, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Machine) GetAdvertisedRoutes() ([]netaddr.IPPrefix, error) {
 | 
				
			||||||
 | 
						hostInfo, err := m.GetHostInfo()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return hostInfo.RoutableIPs, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Machine) GetEnabledRoutes() ([]netaddr.IPPrefix, error) {
 | 
				
			||||||
 | 
						data, err := m.EnabledRoutes.MarshalJSON()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						routesStr := []string{}
 | 
				
			||||||
 | 
						err = json.Unmarshal(data, &routesStr)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						routes := make([]netaddr.IPPrefix, len(routesStr))
 | 
				
			||||||
 | 
						for index, routeStr := range routesStr {
 | 
				
			||||||
 | 
							route, err := netaddr.ParseIPPrefix(routeStr)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							routes[index] = route
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return routes, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Machine) IsRoutesEnabled(routeStr string) bool {
 | 
				
			||||||
 | 
						route, err := netaddr.ParseIPPrefix(routeStr)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enabledRoutes, err := m.GetEnabledRoutes()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, enabledRoute := range enabledRoutes {
 | 
				
			||||||
 | 
							if route == enabledRoute {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EnableNodeRoute enables new routes based on a list of new routes. It will _replace_ the
 | 
				
			||||||
 | 
					// previous list of routes.
 | 
				
			||||||
 | 
					func (h *Headscale) EnableRoutes(m *Machine, routeStrs ...string) error {
 | 
				
			||||||
 | 
						newRoutes := make([]netaddr.IPPrefix, len(routeStrs))
 | 
				
			||||||
 | 
						for index, routeStr := range routeStrs {
 | 
				
			||||||
 | 
							route, err := netaddr.ParseIPPrefix(routeStr)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							newRoutes[index] = route
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						availableRoutes, err := m.GetAdvertisedRoutes()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, newRoute := range newRoutes {
 | 
				
			||||||
 | 
							if !containsIpPrefix(availableRoutes, newRoute) {
 | 
				
			||||||
 | 
								return fmt.Errorf("route (%s) is not available on node %s", m.Name, newRoute)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						routes, err := json.Marshal(newRoutes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m.EnabledRoutes = datatypes.JSON(routes)
 | 
				
			||||||
 | 
						h.db.Save(&m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = h.RequestMapUpdates(m.NamespaceID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Machine) RoutesToProto() (*v1.Routes, error) {
 | 
				
			||||||
 | 
						availableRoutes, err := m.GetAdvertisedRoutes()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enabledRoutes, err := m.GetEnabledRoutes()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &v1.Routes{
 | 
				
			||||||
 | 
							AdvertisedRoutes: ipPrefixToString(availableRoutes),
 | 
				
			||||||
 | 
							EnabledRoutes:    ipPrefixToString(enabledRoutes),
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								routes.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								routes.go
									
									
									
									
									
								
							@ -3,13 +3,12 @@ package headscale
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/pterm/pterm"
 | 
					 | 
				
			||||||
	"gorm.io/datatypes"
 | 
						"gorm.io/datatypes"
 | 
				
			||||||
	"inet.af/netaddr"
 | 
						"inet.af/netaddr"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: use machine function instead
 | 
				
			||||||
// GetAdvertisedNodeRoutes returns the subnet routes advertised by a node (identified by
 | 
					// GetAdvertisedNodeRoutes returns the subnet routes advertised by a node (identified by
 | 
				
			||||||
// namespace and node name)
 | 
					// namespace and node name)
 | 
				
			||||||
func (h *Headscale) GetAdvertisedNodeRoutes(namespace string, nodeName string) (*[]netaddr.IPPrefix, error) {
 | 
					func (h *Headscale) GetAdvertisedNodeRoutes(namespace string, nodeName string) (*[]netaddr.IPPrefix, error) {
 | 
				
			||||||
@ -25,6 +24,7 @@ func (h *Headscale) GetAdvertisedNodeRoutes(namespace string, nodeName string) (
 | 
				
			|||||||
	return &hostInfo.RoutableIPs, nil
 | 
						return &hostInfo.RoutableIPs, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: use machine function instead
 | 
				
			||||||
// GetEnabledNodeRoutes returns the subnet routes enabled by a node (identified by
 | 
					// GetEnabledNodeRoutes returns the subnet routes enabled by a node (identified by
 | 
				
			||||||
// namespace and node name)
 | 
					// namespace and node name)
 | 
				
			||||||
func (h *Headscale) GetEnabledNodeRoutes(namespace string, nodeName string) ([]netaddr.IPPrefix, error) {
 | 
					func (h *Headscale) GetEnabledNodeRoutes(namespace string, nodeName string) ([]netaddr.IPPrefix, error) {
 | 
				
			||||||
@ -56,6 +56,7 @@ func (h *Headscale) GetEnabledNodeRoutes(namespace string, nodeName string) ([]n
 | 
				
			|||||||
	return routes, nil
 | 
						return routes, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: use machine function instead
 | 
				
			||||||
// IsNodeRouteEnabled checks if a certain route has been enabled
 | 
					// IsNodeRouteEnabled checks if a certain route has been enabled
 | 
				
			||||||
func (h *Headscale) IsNodeRouteEnabled(namespace string, nodeName string, routeStr string) bool {
 | 
					func (h *Headscale) IsNodeRouteEnabled(namespace string, nodeName string, routeStr string) bool {
 | 
				
			||||||
	route, err := netaddr.ParseIPPrefix(routeStr)
 | 
						route, err := netaddr.ParseIPPrefix(routeStr)
 | 
				
			||||||
@ -76,6 +77,7 @@ func (h *Headscale) IsNodeRouteEnabled(namespace string, nodeName string, routeS
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: use EnableRoute in machine.go
 | 
				
			||||||
// EnableNodeRoute enables a subnet route advertised by a node (identified by
 | 
					// EnableNodeRoute enables a subnet route advertised by a node (identified by
 | 
				
			||||||
// namespace and node name)
 | 
					// namespace and node name)
 | 
				
			||||||
func (h *Headscale) EnableNodeRoute(namespace string, nodeName string, routeStr string) error {
 | 
					func (h *Headscale) EnableNodeRoute(namespace string, nodeName string, routeStr string) error {
 | 
				
			||||||
@ -129,15 +131,3 @@ func (h *Headscale) EnableNodeRoute(namespace string, nodeName string, routeStr
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// RoutesToPtables converts the list of routes to a nice table
 | 
					 | 
				
			||||||
func (h *Headscale) RoutesToPtables(namespace string, nodeName string, availableRoutes []netaddr.IPPrefix) pterm.TableData {
 | 
					 | 
				
			||||||
	d := pterm.TableData{{"Route", "Enabled"}}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, route := range availableRoutes {
 | 
					 | 
				
			||||||
		enabled := h.IsNodeRouteEnabled(namespace, nodeName, route.String())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		d = append(d, []string{route.String(), strconv.FormatBool(enabled)})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return d
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user