package headscale import "gorm.io/gorm" const ( errorSameNamespace = Error("Destination namespace same as origin") errorMachineAlreadyShared = Error("Node already shared to this namespace") errorMachineNotShared = Error("Machine not shared to this namespace") ) // SharedMachine is a join table to support sharing nodes between namespaces. type SharedMachine struct { gorm.Model MachineID uint64 Machine Machine NamespaceID uint Namespace Namespace } // AddSharedMachineToNamespace adds a machine as a shared node to a namespace. func (h *Headscale) AddSharedMachineToNamespace(m *Machine, ns *Namespace) error { if m.NamespaceID == ns.ID { return errorSameNamespace } sharedMachines := []SharedMachine{} if err := h.db.Where("machine_id = ? AND namespace_id = ?", m.ID, ns.ID).Find(&sharedMachines).Error; err != nil { return err } if len(sharedMachines) > 0 { return errorMachineAlreadyShared } sharedMachine := SharedMachine{ MachineID: m.ID, Machine: *m, NamespaceID: ns.ID, Namespace: *ns, } h.db.Save(&sharedMachine) return nil } // RemoveSharedMachineFromNamespace removes a shared machine from a namespace. func (h *Headscale) RemoveSharedMachineFromNamespace(m *Machine, ns *Namespace) error { if m.NamespaceID == ns.ID { // Can't unshare from primary namespace return errorMachineNotShared } sharedMachine := SharedMachine{} result := h.db.Where("machine_id = ? AND namespace_id = ?", m.ID, ns.ID). Unscoped(). Delete(&sharedMachine) if result.Error != nil { return result.Error } if result.RowsAffected == 0 { return errorMachineNotShared } err := h.RequestMapUpdates(ns.ID) if err != nil { return err } return nil } // RemoveSharedMachineFromAllNamespaces removes a machine as a shared node from all namespaces. func (h *Headscale) RemoveSharedMachineFromAllNamespaces(m *Machine) error { sharedMachine := SharedMachine{} if result := h.db.Where("machine_id = ?", m.ID).Unscoped().Delete(&sharedMachine); result.Error != nil { return result.Error } return nil }