mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-11-04 10:01:05 +01:00 
			
		
		
		
	tests for that feature. Other fixes: clean up a few typos in comments. Fix a bug that caused the tests to run four times each. Be more consistent in the use of log rather than fmt to print errors and notices.
		
			
				
	
	
		
			158 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package headscale
 | 
						|
 | 
						|
import (
 | 
						|
	"log"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/jinzhu/gorm"
 | 
						|
	"tailscale.com/tailcfg"
 | 
						|
)
 | 
						|
 | 
						|
const errorNamespaceExists = Error("Namespace already exists")
 | 
						|
const errorNamespaceNotFound = Error("Namespace not found")
 | 
						|
const errorNamespaceNotEmpty = Error("Namespace not empty")
 | 
						|
 | 
						|
// Namespace is the way Headscale implements the concept of users in Tailscale
 | 
						|
//
 | 
						|
// At the end of the day, users in Tailscale are some kind of 'bubbles' or namespaces
 | 
						|
// that contain our machines.
 | 
						|
type Namespace struct {
 | 
						|
	gorm.Model
 | 
						|
	Name string `gorm:"unique"`
 | 
						|
}
 | 
						|
 | 
						|
// CreateNamespace creates a new Namespace. Returns error if could not be created
 | 
						|
// or another namespace already exists
 | 
						|
func (h *Headscale) CreateNamespace(name string) (*Namespace, error) {
 | 
						|
	db, err := h.db()
 | 
						|
	if err != nil {
 | 
						|
		log.Printf("Cannot open DB: %s", err)
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer db.Close()
 | 
						|
 | 
						|
	n := Namespace{}
 | 
						|
	if err := db.Where("name = ?", name).First(&n).Error; err == nil {
 | 
						|
		return nil, errorNamespaceExists
 | 
						|
	}
 | 
						|
	n.Name = name
 | 
						|
	if err := db.Create(&n).Error; err != nil {
 | 
						|
		log.Printf("Could not create row: %s", err)
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return &n, nil
 | 
						|
}
 | 
						|
 | 
						|
// DestroyNamespace destroys a Namespace. Returns error if the Namespace does
 | 
						|
// not exist or if there are machines associated with it.
 | 
						|
func (h *Headscale) DestroyNamespace(name string) error {
 | 
						|
	db, err := h.db()
 | 
						|
	if err != nil {
 | 
						|
		log.Printf("Cannot open DB: %s", err)
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer db.Close()
 | 
						|
 | 
						|
	n, err := h.GetNamespace(name)
 | 
						|
	if err != nil {
 | 
						|
		return errorNamespaceNotFound
 | 
						|
	}
 | 
						|
 | 
						|
	m, err := h.ListMachinesInNamespace(name)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if len(*m) > 0 {
 | 
						|
		return errorNamespaceNotEmpty
 | 
						|
	}
 | 
						|
 | 
						|
	err = db.Unscoped().Delete(&n).Error
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// GetNamespace fetches a namespace by name
 | 
						|
func (h *Headscale) GetNamespace(name string) (*Namespace, error) {
 | 
						|
	db, err := h.db()
 | 
						|
	if err != nil {
 | 
						|
		log.Printf("Cannot open DB: %s", err)
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer db.Close()
 | 
						|
 | 
						|
	n := Namespace{}
 | 
						|
	if db.First(&n, "name = ?", name).RecordNotFound() {
 | 
						|
		return nil, errorNamespaceNotFound
 | 
						|
	}
 | 
						|
	return &n, nil
 | 
						|
}
 | 
						|
 | 
						|
// ListNamespaces gets all the existing namespaces
 | 
						|
func (h *Headscale) ListNamespaces() (*[]Namespace, error) {
 | 
						|
	db, err := h.db()
 | 
						|
	if err != nil {
 | 
						|
		log.Printf("Cannot open DB: %s", err)
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer db.Close()
 | 
						|
	namespaces := []Namespace{}
 | 
						|
	if err := db.Find(&namespaces).Error; err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return &namespaces, nil
 | 
						|
}
 | 
						|
 | 
						|
// ListMachinesInNamespace gets all the nodes in a given namespace
 | 
						|
func (h *Headscale) ListMachinesInNamespace(name string) (*[]Machine, error) {
 | 
						|
	n, err := h.GetNamespace(name)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	db, err := h.db()
 | 
						|
	if err != nil {
 | 
						|
		log.Printf("Cannot open DB: %s", err)
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer db.Close()
 | 
						|
 | 
						|
	machines := []Machine{}
 | 
						|
	if err := db.Preload("AuthKey").Where(&Machine{NamespaceID: n.ID}).Find(&machines).Error; err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return &machines, nil
 | 
						|
}
 | 
						|
 | 
						|
// SetMachineNamespace assigns a Machine to a namespace
 | 
						|
func (h *Headscale) SetMachineNamespace(m *Machine, namespaceName string) error {
 | 
						|
	n, err := h.GetNamespace(namespaceName)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	db, err := h.db()
 | 
						|
	if err != nil {
 | 
						|
		log.Printf("Cannot open DB: %s", err)
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer db.Close()
 | 
						|
	m.NamespaceID = n.ID
 | 
						|
	db.Save(&m)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) toUser() *tailcfg.User {
 | 
						|
	u := tailcfg.User{
 | 
						|
		ID:            tailcfg.UserID(n.ID),
 | 
						|
		LoginName:     "",
 | 
						|
		DisplayName:   n.Name,
 | 
						|
		ProfilePicURL: "",
 | 
						|
		Domain:        "",
 | 
						|
		Logins:        []tailcfg.LoginID{},
 | 
						|
		Roles:         []tailcfg.RoleID{},
 | 
						|
		Created:       time.Time{},
 | 
						|
	}
 | 
						|
	return &u
 | 
						|
}
 |