mirror of
https://github.com/juanfont/headscale.git
synced 2024-11-29 18:33:05 +00:00
Rename Machine to Node (#1553)
This commit is contained in:
parent
096ac31bb3
commit
0030af3fa4
57 changed files with 5222 additions and 5238 deletions
|
@ -5,6 +5,7 @@
|
||||||
### BREAKING
|
### BREAKING
|
||||||
|
|
||||||
- Code reorganisation, a lot of code has moved, please review the following PRs accordingly [#1444](https://github.com/juanfont/headscale/pull/1444)
|
- Code reorganisation, a lot of code has moved, please review the following PRs accordingly [#1444](https://github.com/juanfont/headscale/pull/1444)
|
||||||
|
- Rename Machine into Node [#1553](https://github.com/juanfont/headscale/pull/1553)
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ var debugCmd = &cobra.Command{
|
||||||
|
|
||||||
var createNodeCmd = &cobra.Command{
|
var createNodeCmd = &cobra.Command{
|
||||||
Use: "create-node",
|
Use: "create-node",
|
||||||
Short: "Create a node (machine) that can be registered with `nodes register <>` command",
|
Short: "Create a node that can be registered with `nodes register <>` command",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
output, _ := cmd.Flags().GetString("output")
|
output, _ := cmd.Flags().GetString("output")
|
||||||
|
|
||||||
|
@ -115,24 +115,24 @@ var createNodeCmd = &cobra.Command{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
request := &v1.DebugCreateMachineRequest{
|
request := &v1.DebugCreateNodeRequest{
|
||||||
Key: machineKey,
|
Key: machineKey,
|
||||||
Name: name,
|
Name: name,
|
||||||
User: user,
|
User: user,
|
||||||
Routes: routes,
|
Routes: routes,
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := client.DebugCreateMachine(ctx, request)
|
response, err := client.DebugCreateNode(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(
|
ErrorOutput(
|
||||||
err,
|
err,
|
||||||
fmt.Sprintf("Cannot create machine: %s", status.Convert(err).Message()),
|
fmt.Sprintf("Cannot create node: %s", status.Convert(err).Message()),
|
||||||
output,
|
output,
|
||||||
)
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
SuccessOutput(response.Machine, "Machine created", output)
|
SuccessOutput(response.Node, "Node created", output)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ var nodeCmd = &cobra.Command{
|
||||||
|
|
||||||
var registerNodeCmd = &cobra.Command{
|
var registerNodeCmd = &cobra.Command{
|
||||||
Use: "register",
|
Use: "register",
|
||||||
Short: "Registers a machine to your network",
|
Short: "Registers a node to your network",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
output, _ := cmd.Flags().GetString("output")
|
output, _ := cmd.Flags().GetString("output")
|
||||||
user, err := cmd.Flags().GetString("user")
|
user, err := cmd.Flags().GetString("user")
|
||||||
|
@ -132,17 +132,17 @@ var registerNodeCmd = &cobra.Command{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
request := &v1.RegisterMachineRequest{
|
request := &v1.RegisterNodeRequest{
|
||||||
Key: machineKey,
|
Key: machineKey,
|
||||||
User: user,
|
User: user,
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := client.RegisterMachine(ctx, request)
|
response, err := client.RegisterNode(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(
|
ErrorOutput(
|
||||||
err,
|
err,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"Cannot register machine: %s\n",
|
"Cannot register node: %s\n",
|
||||||
status.Convert(err).Message(),
|
status.Convert(err).Message(),
|
||||||
),
|
),
|
||||||
output,
|
output,
|
||||||
|
@ -152,8 +152,8 @@ var registerNodeCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
SuccessOutput(
|
SuccessOutput(
|
||||||
response.Machine,
|
response.Node,
|
||||||
fmt.Sprintf("Machine %s registered", response.Machine.GivenName), output)
|
fmt.Sprintf("Node %s registered", response.Node.GivenName), output)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,11 +180,11 @@ var listNodesCmd = &cobra.Command{
|
||||||
defer cancel()
|
defer cancel()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
request := &v1.ListMachinesRequest{
|
request := &v1.ListNodesRequest{
|
||||||
User: user,
|
User: user,
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := client.ListMachines(ctx, request)
|
response, err := client.ListNodes(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(
|
ErrorOutput(
|
||||||
err,
|
err,
|
||||||
|
@ -196,12 +196,12 @@ var listNodesCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
if output != "" {
|
if output != "" {
|
||||||
SuccessOutput(response.Machines, "", output)
|
SuccessOutput(response.Nodes, "", output)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tableData, err := nodesToPtables(user, showTags, response.Machines)
|
tableData, err := nodesToPtables(user, showTags, response.Nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(err, fmt.Sprintf("Error converting to table: %s", err), output)
|
ErrorOutput(err, fmt.Sprintf("Error converting to table: %s", err), output)
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ var listNodesCmd = &cobra.Command{
|
||||||
|
|
||||||
var expireNodeCmd = &cobra.Command{
|
var expireNodeCmd = &cobra.Command{
|
||||||
Use: "expire",
|
Use: "expire",
|
||||||
Short: "Expire (log out) a machine in your network",
|
Short: "Expire (log out) a node in your network",
|
||||||
Long: "Expiring a node will keep the node in the database and force it to reauthenticate.",
|
Long: "Expiring a node will keep the node in the database and force it to reauthenticate.",
|
||||||
Aliases: []string{"logout", "exp", "e"},
|
Aliases: []string{"logout", "exp", "e"},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
@ -244,16 +244,16 @@ var expireNodeCmd = &cobra.Command{
|
||||||
defer cancel()
|
defer cancel()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
request := &v1.ExpireMachineRequest{
|
request := &v1.ExpireNodeRequest{
|
||||||
MachineId: identifier,
|
NodeId: identifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := client.ExpireMachine(ctx, request)
|
response, err := client.ExpireNode(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(
|
ErrorOutput(
|
||||||
err,
|
err,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"Cannot expire machine: %s\n",
|
"Cannot expire node: %s\n",
|
||||||
status.Convert(err).Message(),
|
status.Convert(err).Message(),
|
||||||
),
|
),
|
||||||
output,
|
output,
|
||||||
|
@ -262,13 +262,13 @@ var expireNodeCmd = &cobra.Command{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
SuccessOutput(response.Machine, "Machine expired", output)
|
SuccessOutput(response.Node, "Node expired", output)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var renameNodeCmd = &cobra.Command{
|
var renameNodeCmd = &cobra.Command{
|
||||||
Use: "rename NEW_NAME",
|
Use: "rename NEW_NAME",
|
||||||
Short: "Renames a machine in your network",
|
Short: "Renames a node in your network",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
output, _ := cmd.Flags().GetString("output")
|
output, _ := cmd.Flags().GetString("output")
|
||||||
|
|
||||||
|
@ -291,17 +291,17 @@ var renameNodeCmd = &cobra.Command{
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
newName = args[0]
|
newName = args[0]
|
||||||
}
|
}
|
||||||
request := &v1.RenameMachineRequest{
|
request := &v1.RenameNodeRequest{
|
||||||
MachineId: identifier,
|
NodeId: identifier,
|
||||||
NewName: newName,
|
NewName: newName,
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := client.RenameMachine(ctx, request)
|
response, err := client.RenameNode(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(
|
ErrorOutput(
|
||||||
err,
|
err,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"Cannot rename machine: %s\n",
|
"Cannot rename node: %s\n",
|
||||||
status.Convert(err).Message(),
|
status.Convert(err).Message(),
|
||||||
),
|
),
|
||||||
output,
|
output,
|
||||||
|
@ -310,7 +310,7 @@ var renameNodeCmd = &cobra.Command{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
SuccessOutput(response.Machine, "Machine renamed", output)
|
SuccessOutput(response.Node, "Node renamed", output)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,11 +336,11 @@ var deleteNodeCmd = &cobra.Command{
|
||||||
defer cancel()
|
defer cancel()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
getRequest := &v1.GetMachineRequest{
|
getRequest := &v1.GetNodeRequest{
|
||||||
MachineId: identifier,
|
NodeId: identifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
getResponse, err := client.GetMachine(ctx, getRequest)
|
getResponse, err := client.GetNode(ctx, getRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(
|
ErrorOutput(
|
||||||
err,
|
err,
|
||||||
|
@ -354,8 +354,8 @@ var deleteNodeCmd = &cobra.Command{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteRequest := &v1.DeleteMachineRequest{
|
deleteRequest := &v1.DeleteNodeRequest{
|
||||||
MachineId: identifier,
|
NodeId: identifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
confirm := false
|
confirm := false
|
||||||
|
@ -364,7 +364,7 @@ var deleteNodeCmd = &cobra.Command{
|
||||||
prompt := &survey.Confirm{
|
prompt := &survey.Confirm{
|
||||||
Message: fmt.Sprintf(
|
Message: fmt.Sprintf(
|
||||||
"Do you want to remove the node %s?",
|
"Do you want to remove the node %s?",
|
||||||
getResponse.GetMachine().Name,
|
getResponse.GetNode().Name,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
err = survey.AskOne(prompt, &confirm)
|
err = survey.AskOne(prompt, &confirm)
|
||||||
|
@ -374,7 +374,7 @@ var deleteNodeCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
if confirm || force {
|
if confirm || force {
|
||||||
response, err := client.DeleteMachine(ctx, deleteRequest)
|
response, err := client.DeleteNode(ctx, deleteRequest)
|
||||||
if output != "" {
|
if output != "" {
|
||||||
SuccessOutput(response, "", output)
|
SuccessOutput(response, "", output)
|
||||||
|
|
||||||
|
@ -436,11 +436,11 @@ var moveNodeCmd = &cobra.Command{
|
||||||
defer cancel()
|
defer cancel()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
getRequest := &v1.GetMachineRequest{
|
getRequest := &v1.GetNodeRequest{
|
||||||
MachineId: identifier,
|
NodeId: identifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.GetMachine(ctx, getRequest)
|
_, err = client.GetNode(ctx, getRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(
|
ErrorOutput(
|
||||||
err,
|
err,
|
||||||
|
@ -454,12 +454,12 @@ var moveNodeCmd = &cobra.Command{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
moveRequest := &v1.MoveMachineRequest{
|
moveRequest := &v1.MoveNodeRequest{
|
||||||
MachineId: identifier,
|
NodeId: identifier,
|
||||||
User: user,
|
User: user,
|
||||||
}
|
}
|
||||||
|
|
||||||
moveResponse, err := client.MoveMachine(ctx, moveRequest)
|
moveResponse, err := client.MoveNode(ctx, moveRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(
|
ErrorOutput(
|
||||||
err,
|
err,
|
||||||
|
@ -473,14 +473,14 @@ var moveNodeCmd = &cobra.Command{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
SuccessOutput(moveResponse.Machine, "Node moved to another user", output)
|
SuccessOutput(moveResponse.Node, "Node moved to another user", output)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodesToPtables(
|
func nodesToPtables(
|
||||||
currentUser string,
|
currentUser string,
|
||||||
showTags bool,
|
showTags bool,
|
||||||
machines []*v1.Machine,
|
nodes []*v1.Node,
|
||||||
) (pterm.TableData, error) {
|
) (pterm.TableData, error) {
|
||||||
tableHeader := []string{
|
tableHeader := []string{
|
||||||
"ID",
|
"ID",
|
||||||
|
@ -505,23 +505,23 @@ func nodesToPtables(
|
||||||
}
|
}
|
||||||
tableData := pterm.TableData{tableHeader}
|
tableData := pterm.TableData{tableHeader}
|
||||||
|
|
||||||
for _, machine := range machines {
|
for _, node := range nodes {
|
||||||
var ephemeral bool
|
var ephemeral bool
|
||||||
if machine.PreAuthKey != nil && machine.PreAuthKey.Ephemeral {
|
if node.PreAuthKey != nil && node.PreAuthKey.Ephemeral {
|
||||||
ephemeral = true
|
ephemeral = true
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastSeen time.Time
|
var lastSeen time.Time
|
||||||
var lastSeenTime string
|
var lastSeenTime string
|
||||||
if machine.LastSeen != nil {
|
if node.LastSeen != nil {
|
||||||
lastSeen = machine.LastSeen.AsTime()
|
lastSeen = node.LastSeen.AsTime()
|
||||||
lastSeenTime = lastSeen.Format("2006-01-02 15:04:05")
|
lastSeenTime = lastSeen.Format("2006-01-02 15:04:05")
|
||||||
}
|
}
|
||||||
|
|
||||||
var expiry time.Time
|
var expiry time.Time
|
||||||
var expiryTime string
|
var expiryTime string
|
||||||
if machine.Expiry != nil {
|
if node.Expiry != nil {
|
||||||
expiry = machine.Expiry.AsTime()
|
expiry = node.Expiry.AsTime()
|
||||||
expiryTime = expiry.Format("2006-01-02 15:04:05")
|
expiryTime = expiry.Format("2006-01-02 15:04:05")
|
||||||
} else {
|
} else {
|
||||||
expiryTime = "N/A"
|
expiryTime = "N/A"
|
||||||
|
@ -529,7 +529,7 @@ func nodesToPtables(
|
||||||
|
|
||||||
var machineKey key.MachinePublic
|
var machineKey key.MachinePublic
|
||||||
err := machineKey.UnmarshalText(
|
err := machineKey.UnmarshalText(
|
||||||
[]byte(util.MachinePublicKeyEnsurePrefix(machine.MachineKey)),
|
[]byte(util.MachinePublicKeyEnsurePrefix(node.MachineKey)),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
machineKey = key.MachinePublic{}
|
machineKey = key.MachinePublic{}
|
||||||
|
@ -537,14 +537,14 @@ func nodesToPtables(
|
||||||
|
|
||||||
var nodeKey key.NodePublic
|
var nodeKey key.NodePublic
|
||||||
err = nodeKey.UnmarshalText(
|
err = nodeKey.UnmarshalText(
|
||||||
[]byte(util.NodePublicKeyEnsurePrefix(machine.NodeKey)),
|
[]byte(util.NodePublicKeyEnsurePrefix(node.NodeKey)),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var online string
|
var online string
|
||||||
if machine.Online {
|
if node.Online {
|
||||||
online = pterm.LightGreen("online")
|
online = pterm.LightGreen("online")
|
||||||
} else {
|
} else {
|
||||||
online = pterm.LightRed("offline")
|
online = pterm.LightRed("offline")
|
||||||
|
@ -558,36 +558,36 @@ func nodesToPtables(
|
||||||
}
|
}
|
||||||
|
|
||||||
var forcedTags string
|
var forcedTags string
|
||||||
for _, tag := range machine.ForcedTags {
|
for _, tag := range node.ForcedTags {
|
||||||
forcedTags += "," + tag
|
forcedTags += "," + tag
|
||||||
}
|
}
|
||||||
forcedTags = strings.TrimLeft(forcedTags, ",")
|
forcedTags = strings.TrimLeft(forcedTags, ",")
|
||||||
var invalidTags string
|
var invalidTags string
|
||||||
for _, tag := range machine.InvalidTags {
|
for _, tag := range node.InvalidTags {
|
||||||
if !contains(machine.ForcedTags, tag) {
|
if !contains(node.ForcedTags, tag) {
|
||||||
invalidTags += "," + pterm.LightRed(tag)
|
invalidTags += "," + pterm.LightRed(tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invalidTags = strings.TrimLeft(invalidTags, ",")
|
invalidTags = strings.TrimLeft(invalidTags, ",")
|
||||||
var validTags string
|
var validTags string
|
||||||
for _, tag := range machine.ValidTags {
|
for _, tag := range node.ValidTags {
|
||||||
if !contains(machine.ForcedTags, tag) {
|
if !contains(node.ForcedTags, tag) {
|
||||||
validTags += "," + pterm.LightGreen(tag)
|
validTags += "," + pterm.LightGreen(tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
validTags = strings.TrimLeft(validTags, ",")
|
validTags = strings.TrimLeft(validTags, ",")
|
||||||
|
|
||||||
var user string
|
var user string
|
||||||
if currentUser == "" || (currentUser == machine.User.Name) {
|
if currentUser == "" || (currentUser == node.User.Name) {
|
||||||
user = pterm.LightMagenta(machine.User.Name)
|
user = pterm.LightMagenta(node.User.Name)
|
||||||
} else {
|
} else {
|
||||||
// Shared into this user
|
// Shared into this user
|
||||||
user = pterm.LightYellow(machine.User.Name)
|
user = pterm.LightYellow(node.User.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var IPV4Address string
|
var IPV4Address string
|
||||||
var IPV6Address string
|
var IPV6Address string
|
||||||
for _, addr := range machine.IpAddresses {
|
for _, addr := range node.IpAddresses {
|
||||||
if netip.MustParseAddr(addr).Is4() {
|
if netip.MustParseAddr(addr).Is4() {
|
||||||
IPV4Address = addr
|
IPV4Address = addr
|
||||||
} else {
|
} else {
|
||||||
|
@ -596,9 +596,9 @@ func nodesToPtables(
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeData := []string{
|
nodeData := []string{
|
||||||
strconv.FormatUint(machine.Id, util.Base10),
|
strconv.FormatUint(node.Id, util.Base10),
|
||||||
machine.Name,
|
node.Name,
|
||||||
machine.GetGivenName(),
|
node.GetGivenName(),
|
||||||
machineKey.ShortString(),
|
machineKey.ShortString(),
|
||||||
nodeKey.ShortString(),
|
nodeKey.ShortString(),
|
||||||
user,
|
user,
|
||||||
|
@ -646,16 +646,16 @@ var tagCmd = &cobra.Command{
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(
|
ErrorOutput(
|
||||||
err,
|
err,
|
||||||
fmt.Sprintf("Error retrieving list of tags to add to machine, %v", err),
|
fmt.Sprintf("Error retrieving list of tags to add to node, %v", err),
|
||||||
output,
|
output,
|
||||||
)
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sending tags to machine
|
// Sending tags to node
|
||||||
request := &v1.SetTagsRequest{
|
request := &v1.SetTagsRequest{
|
||||||
MachineId: identifier,
|
NodeId: identifier,
|
||||||
Tags: tagsToSet,
|
Tags: tagsToSet,
|
||||||
}
|
}
|
||||||
resp, err := client.SetTags(ctx, request)
|
resp, err := client.SetTags(ctx, request)
|
||||||
|
@ -671,8 +671,8 @@ var tagCmd = &cobra.Command{
|
||||||
|
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
SuccessOutput(
|
SuccessOutput(
|
||||||
resp.GetMachine(),
|
resp.GetNode(),
|
||||||
"Machine updated",
|
"Node updated",
|
||||||
output,
|
output,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ func initConfig() {
|
||||||
|
|
||||||
zerolog.SetGlobalLevel(cfg.Log.Level)
|
zerolog.SetGlobalLevel(cfg.Log.Level)
|
||||||
|
|
||||||
// If the user has requested a "machine" readable format,
|
// If the user has requested a "node" readable format,
|
||||||
// then disable login so the output remains valid.
|
// then disable login so the output remains valid.
|
||||||
if machineOutput {
|
if machineOutput {
|
||||||
zerolog.SetGlobalLevel(zerolog.Disabled)
|
zerolog.SetGlobalLevel(zerolog.Disabled)
|
||||||
|
|
|
@ -94,13 +94,13 @@ var listRoutesCmd = &cobra.Command{
|
||||||
|
|
||||||
routes = response.Routes
|
routes = response.Routes
|
||||||
} else {
|
} else {
|
||||||
response, err := client.GetMachineRoutes(ctx, &v1.GetMachineRoutesRequest{
|
response, err := client.GetNodeRoutes(ctx, &v1.GetNodeRoutesRequest{
|
||||||
MachineId: machineID,
|
NodeId: machineID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorOutput(
|
ErrorOutput(
|
||||||
err,
|
err,
|
||||||
fmt.Sprintf("Cannot get routes for machine %d: %s", machineID, status.Convert(err).Message()),
|
fmt.Sprintf("Cannot get routes for node %d: %s", machineID, status.Convert(err).Message()),
|
||||||
output,
|
output,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ var deleteRouteCmd = &cobra.Command{
|
||||||
|
|
||||||
// routesToPtables converts the list of routes to a nice table.
|
// routesToPtables converts the list of routes to a nice table.
|
||||||
func routesToPtables(routes []*v1.Route) pterm.TableData {
|
func routesToPtables(routes []*v1.Route) pterm.TableData {
|
||||||
tableData := pterm.TableData{{"ID", "Machine", "Prefix", "Advertised", "Enabled", "Primary"}}
|
tableData := pterm.TableData{{"ID", "Node", "Prefix", "Advertised", "Enabled", "Primary"}}
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
var isPrimaryStr string
|
var isPrimaryStr string
|
||||||
|
@ -286,7 +286,7 @@ func routesToPtables(routes []*v1.Route) pterm.TableData {
|
||||||
tableData = append(tableData,
|
tableData = append(tableData,
|
||||||
[]string{
|
[]string{
|
||||||
strconv.FormatUint(route.Id, Base10),
|
strconv.FormatUint(route.Id, Base10),
|
||||||
route.Machine.GivenName,
|
route.Node.GivenName,
|
||||||
route.Prefix,
|
route.Prefix,
|
||||||
strconv.FormatBool(route.Advertised),
|
strconv.FormatBool(route.Advertised),
|
||||||
strconv.FormatBool(route.Enabled),
|
strconv.FormatBool(route.Enabled),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.29.1
|
// protoc-gen-go v1.31.0
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: headscale/v1/apikey.proto
|
// source: headscale/v1/apikey.proto
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.29.1
|
// protoc-gen-go v1.31.0
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: headscale/v1/device.proto
|
// source: headscale/v1/device.proto
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.29.1
|
// protoc-gen-go v1.31.0
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: headscale/v1/headscale.proto
|
// source: headscale/v1/headscale.proto
|
||||||
|
|
||||||
|
@ -31,208 +31,199 @@ var file_headscale_v1_headscale_proto_rawDesc = []byte{
|
||||||
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72,
|
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72,
|
||||||
0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76,
|
0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76,
|
||||||
0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f,
|
0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
0x74, 0x6f, 0x1a, 0x1a, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31,
|
0x74, 0x6f, 0x1a, 0x17, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31,
|
||||||
0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19,
|
0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x68, 0x65, 0x61,
|
||||||
0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75,
|
0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73,
|
||||||
0x74, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73,
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
||||||
0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2e, 0x70,
|
0x65, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x32, 0x8d, 0x18, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61,
|
0x6f, 0x32, 0x85, 0x17, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x53,
|
||||||
0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x63, 0x0a, 0x07, 0x47, 0x65, 0x74,
|
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x63, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65,
|
||||||
0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65,
|
0x72, 0x12, 0x1c, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31,
|
||||||
0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
|
0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||||
0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76,
|
0x1d, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47,
|
||||||
0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b,
|
||||||
0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f,
|
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f,
|
||||||
0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x68,
|
0x75, 0x73, 0x65, 0x72, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x68, 0x0a, 0x0a, 0x43,
|
||||||
0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68,
|
0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64,
|
||||||
0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61,
|
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55,
|
||||||
0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e,
|
0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61,
|
||||||
0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65,
|
0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||||
0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3,
|
||||||
0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x61, 0x70, 0x69,
|
0xe4, 0x93, 0x02, 0x11, 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31,
|
||||||
0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x12, 0x82, 0x01, 0x0a, 0x0a, 0x52, 0x65, 0x6e,
|
0x2f, 0x75, 0x73, 0x65, 0x72, 0x12, 0x82, 0x01, 0x0a, 0x0a, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
0x61, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63,
|
0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65,
|
||||||
0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x55, 0x73, 0x65,
|
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65,
|
||||||
0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
||||||
0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x55, 0x73,
|
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52,
|
||||||
0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93,
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22,
|
||||||
0x02, 0x2b, 0x22, 0x29, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72,
|
0x29, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x7b, 0x6f,
|
||||||
0x2f, 0x7b, 0x6f, 0x6c, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x6e, 0x61,
|
0x6c, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x2f,
|
||||||
0x6d, 0x65, 0x2f, 0x7b, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x6c, 0x0a,
|
0x7b, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x6c, 0x0a, 0x0a, 0x44, 0x65,
|
||||||
0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x65,
|
0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
||||||
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
|
0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73,
|
||||||
0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68,
|
0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64,
|
||||||
0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65,
|
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55,
|
||||||
0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b,
|
0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4,
|
||||||
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x2a, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f,
|
0x93, 0x02, 0x15, 0x2a, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65,
|
||||||
0x75, 0x73, 0x65, 0x72, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x62, 0x0a, 0x09, 0x4c,
|
0x72, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x62, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74,
|
||||||
0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
||||||
0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72,
|
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65,
|
||||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
||||||
0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72,
|
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65,
|
||||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c,
|
||||||
0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x12,
|
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x12, 0x80, 0x01, 0x0a,
|
||||||
0x80, 0x01, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74,
|
0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65,
|
||||||
|
0x79, 0x12, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31,
|
||||||
|
0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65,
|
||||||
|
0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
||||||
|
0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72,
|
||||||
|
0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||||
|
0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x01, 0x2a, 0x22, 0x12, 0x2f, 0x61, 0x70,
|
||||||
|
0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6b, 0x65, 0x79, 0x12,
|
||||||
|
0x87, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74,
|
||||||
0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65,
|
0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65,
|
||||||
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74,
|
0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74,
|
||||||
0x68, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x65,
|
0x68, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x65,
|
||||||
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
|
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72,
|
||||||
0x65, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x65, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x01, 0x2a, 0x22, 0x12,
|
0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x3a, 0x01, 0x2a, 0x22, 0x19,
|
||||||
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6b,
|
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6b,
|
||||||
0x65, 0x79, 0x12, 0x87, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, 0x65,
|
0x65, 0x79, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x7a, 0x0a, 0x0f, 0x4c, 0x69, 0x73,
|
||||||
0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63,
|
0x74, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x24, 0x2e, 0x68,
|
||||||
0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, 0x65,
|
0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||||
0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26,
|
0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||||
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78,
|
0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76,
|
||||||
0x70, 0x69, 0x72, 0x65, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x65,
|
0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x3a, 0x01,
|
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
||||||
0x2a, 0x22, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75,
|
0x14, 0x12, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75,
|
||||||
0x74, 0x68, 0x6b, 0x65, 0x79, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x7a, 0x0a, 0x0f,
|
0x74, 0x68, 0x6b, 0x65, 0x79, 0x12, 0x7d, 0x0a, 0x0f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72,
|
||||||
0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x73, 0x12,
|
0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
||||||
0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
|
|
||||||
0x69, 0x73, 0x74, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65,
|
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
|
||||||
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68,
|
|
||||||
0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3,
|
|
||||||
0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72,
|
|
||||||
0x65, 0x61, 0x75, 0x74, 0x68, 0x6b, 0x65, 0x79, 0x12, 0x89, 0x01, 0x0a, 0x12, 0x44, 0x65, 0x62,
|
|
||||||
0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12,
|
|
||||||
0x27, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44,
|
|
||||||
0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
|
||||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
|
||||||
0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65,
|
0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65,
|
||||||
0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25,
|
||||||
0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f,
|
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65,
|
||||||
0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2f, 0x6d, 0x61, 0x63,
|
0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73,
|
||||||
0x68, 0x69, 0x6e, 0x65, 0x12, 0x75, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69,
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x01, 0x2a,
|
||||||
0x6e, 0x65, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76,
|
0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2f,
|
||||||
0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75,
|
0x6e, 0x6f, 0x64, 0x65, 0x12, 0x66, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12,
|
||||||
0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e,
|
0x1c, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47,
|
||||||
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73,
|
0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f,
|
0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
|
||||||
0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b,
|
0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3,
|
||||||
0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x74, 0x0a, 0x07, 0x53,
|
0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f,
|
||||||
0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x12, 0x1c, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61,
|
0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x6e, 0x0a, 0x07,
|
||||||
0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71,
|
0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x12, 0x1c, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63,
|
||||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65,
|
0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65,
|
||||||
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
||||||
0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x3a, 0x01, 0x2a, 0x22, 0x21,
|
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||||
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f,
|
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22,
|
||||||
0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x74, 0x61, 0x67,
|
0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e,
|
||||||
0x73, 0x12, 0x80, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61,
|
0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x74, 0x61, 0x67, 0x73, 0x12, 0x74, 0x0a, 0x0c,
|
||||||
0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x2e, 0x68,
|
||||||
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x63,
|
0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69,
|
||||||
0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65,
|
0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||||
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73,
|
0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52,
|
||||||
0x74, 0x65, 0x72, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x18, 0x2f, 0x61, 0x70, 0x69,
|
0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x15, 0x2f, 0x61, 0x70,
|
||||||
0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x72, 0x65, 0x67, 0x69,
|
0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
|
||||||
0x73, 0x74, 0x65, 0x72, 0x12, 0x7e, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61,
|
0x65, 0x72, 0x12, 0x6f, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65,
|
||||||
0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e,
|
||||||
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69,
|
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x65, 0x61, 0x64,
|
0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31,
|
||||||
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d,
|
0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24,
|
0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x61, 0x70,
|
||||||
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x2a, 0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f,
|
0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f,
|
||||||
0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
0x69, 0x64, 0x7d, 0x12, 0x76, 0x0a, 0x0a, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64,
|
||||||
0x5f, 0x69, 0x64, 0x7d, 0x12, 0x85, 0x01, 0x0a, 0x0d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d,
|
0x65, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31,
|
||||||
0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61,
|
0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||||
0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68,
|
0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76,
|
||||||
0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x65, 0x61,
|
0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70,
|
||||||
0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65,
|
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1d, 0x2f, 0x61,
|
||||||
0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65,
|
||||||
0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31,
|
0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x0a,
|
||||||
0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61,
|
||||||
0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x90, 0x01, 0x0a,
|
0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
0x0d, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x22,
|
0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65,
|
||||||
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65,
|
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d,
|
||||||
0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82,
|
||||||
0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76,
|
0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x22, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e,
|
||||||
0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52,
|
0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x65,
|
||||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x30, 0x22,
|
|
||||||
0x2e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
|
||||||
0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x65,
|
|
||||||
0x6e, 0x61, 0x6d, 0x65, 0x2f, 0x7b, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12,
|
0x6e, 0x61, 0x6d, 0x65, 0x2f, 0x7b, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12,
|
||||||
0x6e, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x12,
|
0x62, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x68,
|
||||||
0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
|
0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||||
0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68,
|
||||||
0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76,
|
0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||||
0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65,
|
0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f,
|
0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e,
|
||||||
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12,
|
0x6f, 0x64, 0x65, 0x12, 0x6e, 0x0a, 0x08, 0x4d, 0x6f, 0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12,
|
||||||
0x7d, 0x0a, 0x0b, 0x4d, 0x6f, 0x76, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x20,
|
0x1d, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d,
|
||||||
|
0x6f, 0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e,
|
||||||
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f,
|
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f,
|
||||||
0x76, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23,
|
||||||
0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e,
|
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f,
|
||||||
0x4d, 0x6f, 0x76, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x75,
|
||||||
0x6e, 0x73, 0x65, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x22, 0x21, 0x2f, 0x61, 0x70,
|
0x73, 0x65, 0x72, 0x12, 0x64, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73,
|
||||||
0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61,
|
0x12, 0x1e, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e,
|
||||||
0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x12, 0x64,
|
0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
0x0a, 0x09, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x68, 0x65,
|
0x1a, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e,
|
||||||
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f,
|
0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x65,
|
0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f,
|
||||||
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f,
|
0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x7c, 0x0a, 0x0b, 0x45, 0x6e, 0x61,
|
||||||
0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3,
|
0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
||||||
0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f,
|
0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f,
|
||||||
0x75, 0x74, 0x65, 0x73, 0x12, 0x7c, 0x0a, 0x0b, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f,
|
0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61,
|
||||||
0x75, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e,
|
0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
||||||
0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65,
|
0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
0xd3, 0xe4, 0x93, 0x02, 0x22, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72,
|
||||||
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
0x6f, 0x75, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x7d,
|
||||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22,
|
0x2f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x80, 0x01, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x61,
|
||||||
0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73,
|
0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
||||||
0x2f, 0x7b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x65, 0x6e, 0x61, 0x62,
|
0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52,
|
||||||
0x6c, 0x65, 0x12, 0x80, 0x01, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f,
|
0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65,
|
||||||
0x75, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e,
|
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x61, 0x62,
|
||||||
0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52,
|
0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61,
|
0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x22, 0x21, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31,
|
||||||
0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75,
|
0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69,
|
||||||
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93,
|
0x64, 0x7d, 0x2f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x7f, 0x0a, 0x0d, 0x47, 0x65,
|
||||||
0x02, 0x23, 0x22, 0x21, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74,
|
0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x68, 0x65,
|
||||||
0x65, 0x73, 0x2f, 0x7b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x64, 0x69,
|
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f,
|
||||||
0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x8e, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63,
|
0x64, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||||
0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x25, 0x2e, 0x68, 0x65, 0x61,
|
0x23, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47,
|
||||||
0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63,
|
0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||||
0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x61,
|
||||||
0x74, 0x1a, 0x26, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31,
|
0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65,
|
||||||
0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x75, 0x0a, 0x0b, 0x44,
|
||||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61,
|
||||||
0x25, 0x12, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
|
||||||
0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f,
|
0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68,
|
||||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x75, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
|
0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65,
|
||||||
0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||||
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x2a, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31,
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63,
|
0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69,
|
||||||
0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x75,
|
0x64, 0x7d, 0x12, 0x70, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b,
|
||||||
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93,
|
0x65, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76,
|
||||||
0x02, 0x1b, 0x2a, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74,
|
0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65,
|
||||||
0x65, 0x73, 0x2f, 0x7b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x70, 0x0a,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c,
|
||||||
0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e,
|
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65,
|
||||||
0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65,
|
0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
||||||
0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70,
|
||||||
0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e,
|
0x69, 0x6b, 0x65, 0x79, 0x12, 0x77, 0x0a, 0x0c, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70,
|
||||||
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70,
|
0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65,
|
||||||
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22,
|
0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79,
|
||||||
0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x12,
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63,
|
||||||
0x77, 0x0a, 0x0c, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12,
|
0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69,
|
||||||
0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45,
|
0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4,
|
||||||
0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
|
0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f,
|
||||||
0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76,
|
0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x6a, 0x0a,
|
||||||
0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65,
|
0x0b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x20, 0x2e, 0x68,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01,
|
0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||||
0x2a, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65,
|
0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21,
|
||||||
0x79, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x6a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74,
|
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69,
|
||||||
0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63,
|
0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65,
|
0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f,
|
||||||
0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64,
|
0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74,
|
||||||
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69,
|
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x75, 0x61, 0x6e, 0x66, 0x6f, 0x6e, 0x74,
|
||||||
0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3,
|
0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67,
|
||||||
0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70,
|
0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x69, 0x6b, 0x65, 0x79, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
|
||||||
0x6f, 0x6d, 0x2f, 0x6a, 0x75, 0x61, 0x6e, 0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64,
|
|
||||||
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62,
|
|
||||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_headscale_v1_headscale_proto_goTypes = []interface{}{
|
var file_headscale_v1_headscale_proto_goTypes = []interface{}{
|
||||||
|
@ -244,19 +235,19 @@ var file_headscale_v1_headscale_proto_goTypes = []interface{}{
|
||||||
(*CreatePreAuthKeyRequest)(nil), // 5: headscale.v1.CreatePreAuthKeyRequest
|
(*CreatePreAuthKeyRequest)(nil), // 5: headscale.v1.CreatePreAuthKeyRequest
|
||||||
(*ExpirePreAuthKeyRequest)(nil), // 6: headscale.v1.ExpirePreAuthKeyRequest
|
(*ExpirePreAuthKeyRequest)(nil), // 6: headscale.v1.ExpirePreAuthKeyRequest
|
||||||
(*ListPreAuthKeysRequest)(nil), // 7: headscale.v1.ListPreAuthKeysRequest
|
(*ListPreAuthKeysRequest)(nil), // 7: headscale.v1.ListPreAuthKeysRequest
|
||||||
(*DebugCreateMachineRequest)(nil), // 8: headscale.v1.DebugCreateMachineRequest
|
(*DebugCreateNodeRequest)(nil), // 8: headscale.v1.DebugCreateNodeRequest
|
||||||
(*GetMachineRequest)(nil), // 9: headscale.v1.GetMachineRequest
|
(*GetNodeRequest)(nil), // 9: headscale.v1.GetNodeRequest
|
||||||
(*SetTagsRequest)(nil), // 10: headscale.v1.SetTagsRequest
|
(*SetTagsRequest)(nil), // 10: headscale.v1.SetTagsRequest
|
||||||
(*RegisterMachineRequest)(nil), // 11: headscale.v1.RegisterMachineRequest
|
(*RegisterNodeRequest)(nil), // 11: headscale.v1.RegisterNodeRequest
|
||||||
(*DeleteMachineRequest)(nil), // 12: headscale.v1.DeleteMachineRequest
|
(*DeleteNodeRequest)(nil), // 12: headscale.v1.DeleteNodeRequest
|
||||||
(*ExpireMachineRequest)(nil), // 13: headscale.v1.ExpireMachineRequest
|
(*ExpireNodeRequest)(nil), // 13: headscale.v1.ExpireNodeRequest
|
||||||
(*RenameMachineRequest)(nil), // 14: headscale.v1.RenameMachineRequest
|
(*RenameNodeRequest)(nil), // 14: headscale.v1.RenameNodeRequest
|
||||||
(*ListMachinesRequest)(nil), // 15: headscale.v1.ListMachinesRequest
|
(*ListNodesRequest)(nil), // 15: headscale.v1.ListNodesRequest
|
||||||
(*MoveMachineRequest)(nil), // 16: headscale.v1.MoveMachineRequest
|
(*MoveNodeRequest)(nil), // 16: headscale.v1.MoveNodeRequest
|
||||||
(*GetRoutesRequest)(nil), // 17: headscale.v1.GetRoutesRequest
|
(*GetRoutesRequest)(nil), // 17: headscale.v1.GetRoutesRequest
|
||||||
(*EnableRouteRequest)(nil), // 18: headscale.v1.EnableRouteRequest
|
(*EnableRouteRequest)(nil), // 18: headscale.v1.EnableRouteRequest
|
||||||
(*DisableRouteRequest)(nil), // 19: headscale.v1.DisableRouteRequest
|
(*DisableRouteRequest)(nil), // 19: headscale.v1.DisableRouteRequest
|
||||||
(*GetMachineRoutesRequest)(nil), // 20: headscale.v1.GetMachineRoutesRequest
|
(*GetNodeRoutesRequest)(nil), // 20: headscale.v1.GetNodeRoutesRequest
|
||||||
(*DeleteRouteRequest)(nil), // 21: headscale.v1.DeleteRouteRequest
|
(*DeleteRouteRequest)(nil), // 21: headscale.v1.DeleteRouteRequest
|
||||||
(*CreateApiKeyRequest)(nil), // 22: headscale.v1.CreateApiKeyRequest
|
(*CreateApiKeyRequest)(nil), // 22: headscale.v1.CreateApiKeyRequest
|
||||||
(*ExpireApiKeyRequest)(nil), // 23: headscale.v1.ExpireApiKeyRequest
|
(*ExpireApiKeyRequest)(nil), // 23: headscale.v1.ExpireApiKeyRequest
|
||||||
|
@ -269,19 +260,19 @@ var file_headscale_v1_headscale_proto_goTypes = []interface{}{
|
||||||
(*CreatePreAuthKeyResponse)(nil), // 30: headscale.v1.CreatePreAuthKeyResponse
|
(*CreatePreAuthKeyResponse)(nil), // 30: headscale.v1.CreatePreAuthKeyResponse
|
||||||
(*ExpirePreAuthKeyResponse)(nil), // 31: headscale.v1.ExpirePreAuthKeyResponse
|
(*ExpirePreAuthKeyResponse)(nil), // 31: headscale.v1.ExpirePreAuthKeyResponse
|
||||||
(*ListPreAuthKeysResponse)(nil), // 32: headscale.v1.ListPreAuthKeysResponse
|
(*ListPreAuthKeysResponse)(nil), // 32: headscale.v1.ListPreAuthKeysResponse
|
||||||
(*DebugCreateMachineResponse)(nil), // 33: headscale.v1.DebugCreateMachineResponse
|
(*DebugCreateNodeResponse)(nil), // 33: headscale.v1.DebugCreateNodeResponse
|
||||||
(*GetMachineResponse)(nil), // 34: headscale.v1.GetMachineResponse
|
(*GetNodeResponse)(nil), // 34: headscale.v1.GetNodeResponse
|
||||||
(*SetTagsResponse)(nil), // 35: headscale.v1.SetTagsResponse
|
(*SetTagsResponse)(nil), // 35: headscale.v1.SetTagsResponse
|
||||||
(*RegisterMachineResponse)(nil), // 36: headscale.v1.RegisterMachineResponse
|
(*RegisterNodeResponse)(nil), // 36: headscale.v1.RegisterNodeResponse
|
||||||
(*DeleteMachineResponse)(nil), // 37: headscale.v1.DeleteMachineResponse
|
(*DeleteNodeResponse)(nil), // 37: headscale.v1.DeleteNodeResponse
|
||||||
(*ExpireMachineResponse)(nil), // 38: headscale.v1.ExpireMachineResponse
|
(*ExpireNodeResponse)(nil), // 38: headscale.v1.ExpireNodeResponse
|
||||||
(*RenameMachineResponse)(nil), // 39: headscale.v1.RenameMachineResponse
|
(*RenameNodeResponse)(nil), // 39: headscale.v1.RenameNodeResponse
|
||||||
(*ListMachinesResponse)(nil), // 40: headscale.v1.ListMachinesResponse
|
(*ListNodesResponse)(nil), // 40: headscale.v1.ListNodesResponse
|
||||||
(*MoveMachineResponse)(nil), // 41: headscale.v1.MoveMachineResponse
|
(*MoveNodeResponse)(nil), // 41: headscale.v1.MoveNodeResponse
|
||||||
(*GetRoutesResponse)(nil), // 42: headscale.v1.GetRoutesResponse
|
(*GetRoutesResponse)(nil), // 42: headscale.v1.GetRoutesResponse
|
||||||
(*EnableRouteResponse)(nil), // 43: headscale.v1.EnableRouteResponse
|
(*EnableRouteResponse)(nil), // 43: headscale.v1.EnableRouteResponse
|
||||||
(*DisableRouteResponse)(nil), // 44: headscale.v1.DisableRouteResponse
|
(*DisableRouteResponse)(nil), // 44: headscale.v1.DisableRouteResponse
|
||||||
(*GetMachineRoutesResponse)(nil), // 45: headscale.v1.GetMachineRoutesResponse
|
(*GetNodeRoutesResponse)(nil), // 45: headscale.v1.GetNodeRoutesResponse
|
||||||
(*DeleteRouteResponse)(nil), // 46: headscale.v1.DeleteRouteResponse
|
(*DeleteRouteResponse)(nil), // 46: headscale.v1.DeleteRouteResponse
|
||||||
(*CreateApiKeyResponse)(nil), // 47: headscale.v1.CreateApiKeyResponse
|
(*CreateApiKeyResponse)(nil), // 47: headscale.v1.CreateApiKeyResponse
|
||||||
(*ExpireApiKeyResponse)(nil), // 48: headscale.v1.ExpireApiKeyResponse
|
(*ExpireApiKeyResponse)(nil), // 48: headscale.v1.ExpireApiKeyResponse
|
||||||
|
@ -296,19 +287,19 @@ var file_headscale_v1_headscale_proto_depIdxs = []int32{
|
||||||
5, // 5: headscale.v1.HeadscaleService.CreatePreAuthKey:input_type -> headscale.v1.CreatePreAuthKeyRequest
|
5, // 5: headscale.v1.HeadscaleService.CreatePreAuthKey:input_type -> headscale.v1.CreatePreAuthKeyRequest
|
||||||
6, // 6: headscale.v1.HeadscaleService.ExpirePreAuthKey:input_type -> headscale.v1.ExpirePreAuthKeyRequest
|
6, // 6: headscale.v1.HeadscaleService.ExpirePreAuthKey:input_type -> headscale.v1.ExpirePreAuthKeyRequest
|
||||||
7, // 7: headscale.v1.HeadscaleService.ListPreAuthKeys:input_type -> headscale.v1.ListPreAuthKeysRequest
|
7, // 7: headscale.v1.HeadscaleService.ListPreAuthKeys:input_type -> headscale.v1.ListPreAuthKeysRequest
|
||||||
8, // 8: headscale.v1.HeadscaleService.DebugCreateMachine:input_type -> headscale.v1.DebugCreateMachineRequest
|
8, // 8: headscale.v1.HeadscaleService.DebugCreateNode:input_type -> headscale.v1.DebugCreateNodeRequest
|
||||||
9, // 9: headscale.v1.HeadscaleService.GetMachine:input_type -> headscale.v1.GetMachineRequest
|
9, // 9: headscale.v1.HeadscaleService.GetNode:input_type -> headscale.v1.GetNodeRequest
|
||||||
10, // 10: headscale.v1.HeadscaleService.SetTags:input_type -> headscale.v1.SetTagsRequest
|
10, // 10: headscale.v1.HeadscaleService.SetTags:input_type -> headscale.v1.SetTagsRequest
|
||||||
11, // 11: headscale.v1.HeadscaleService.RegisterMachine:input_type -> headscale.v1.RegisterMachineRequest
|
11, // 11: headscale.v1.HeadscaleService.RegisterNode:input_type -> headscale.v1.RegisterNodeRequest
|
||||||
12, // 12: headscale.v1.HeadscaleService.DeleteMachine:input_type -> headscale.v1.DeleteMachineRequest
|
12, // 12: headscale.v1.HeadscaleService.DeleteNode:input_type -> headscale.v1.DeleteNodeRequest
|
||||||
13, // 13: headscale.v1.HeadscaleService.ExpireMachine:input_type -> headscale.v1.ExpireMachineRequest
|
13, // 13: headscale.v1.HeadscaleService.ExpireNode:input_type -> headscale.v1.ExpireNodeRequest
|
||||||
14, // 14: headscale.v1.HeadscaleService.RenameMachine:input_type -> headscale.v1.RenameMachineRequest
|
14, // 14: headscale.v1.HeadscaleService.RenameNode:input_type -> headscale.v1.RenameNodeRequest
|
||||||
15, // 15: headscale.v1.HeadscaleService.ListMachines:input_type -> headscale.v1.ListMachinesRequest
|
15, // 15: headscale.v1.HeadscaleService.ListNodes:input_type -> headscale.v1.ListNodesRequest
|
||||||
16, // 16: headscale.v1.HeadscaleService.MoveMachine:input_type -> headscale.v1.MoveMachineRequest
|
16, // 16: headscale.v1.HeadscaleService.MoveNode:input_type -> headscale.v1.MoveNodeRequest
|
||||||
17, // 17: headscale.v1.HeadscaleService.GetRoutes:input_type -> headscale.v1.GetRoutesRequest
|
17, // 17: headscale.v1.HeadscaleService.GetRoutes:input_type -> headscale.v1.GetRoutesRequest
|
||||||
18, // 18: headscale.v1.HeadscaleService.EnableRoute:input_type -> headscale.v1.EnableRouteRequest
|
18, // 18: headscale.v1.HeadscaleService.EnableRoute:input_type -> headscale.v1.EnableRouteRequest
|
||||||
19, // 19: headscale.v1.HeadscaleService.DisableRoute:input_type -> headscale.v1.DisableRouteRequest
|
19, // 19: headscale.v1.HeadscaleService.DisableRoute:input_type -> headscale.v1.DisableRouteRequest
|
||||||
20, // 20: headscale.v1.HeadscaleService.GetMachineRoutes:input_type -> headscale.v1.GetMachineRoutesRequest
|
20, // 20: headscale.v1.HeadscaleService.GetNodeRoutes:input_type -> headscale.v1.GetNodeRoutesRequest
|
||||||
21, // 21: headscale.v1.HeadscaleService.DeleteRoute:input_type -> headscale.v1.DeleteRouteRequest
|
21, // 21: headscale.v1.HeadscaleService.DeleteRoute:input_type -> headscale.v1.DeleteRouteRequest
|
||||||
22, // 22: headscale.v1.HeadscaleService.CreateApiKey:input_type -> headscale.v1.CreateApiKeyRequest
|
22, // 22: headscale.v1.HeadscaleService.CreateApiKey:input_type -> headscale.v1.CreateApiKeyRequest
|
||||||
23, // 23: headscale.v1.HeadscaleService.ExpireApiKey:input_type -> headscale.v1.ExpireApiKeyRequest
|
23, // 23: headscale.v1.HeadscaleService.ExpireApiKey:input_type -> headscale.v1.ExpireApiKeyRequest
|
||||||
|
@ -321,19 +312,19 @@ var file_headscale_v1_headscale_proto_depIdxs = []int32{
|
||||||
30, // 30: headscale.v1.HeadscaleService.CreatePreAuthKey:output_type -> headscale.v1.CreatePreAuthKeyResponse
|
30, // 30: headscale.v1.HeadscaleService.CreatePreAuthKey:output_type -> headscale.v1.CreatePreAuthKeyResponse
|
||||||
31, // 31: headscale.v1.HeadscaleService.ExpirePreAuthKey:output_type -> headscale.v1.ExpirePreAuthKeyResponse
|
31, // 31: headscale.v1.HeadscaleService.ExpirePreAuthKey:output_type -> headscale.v1.ExpirePreAuthKeyResponse
|
||||||
32, // 32: headscale.v1.HeadscaleService.ListPreAuthKeys:output_type -> headscale.v1.ListPreAuthKeysResponse
|
32, // 32: headscale.v1.HeadscaleService.ListPreAuthKeys:output_type -> headscale.v1.ListPreAuthKeysResponse
|
||||||
33, // 33: headscale.v1.HeadscaleService.DebugCreateMachine:output_type -> headscale.v1.DebugCreateMachineResponse
|
33, // 33: headscale.v1.HeadscaleService.DebugCreateNode:output_type -> headscale.v1.DebugCreateNodeResponse
|
||||||
34, // 34: headscale.v1.HeadscaleService.GetMachine:output_type -> headscale.v1.GetMachineResponse
|
34, // 34: headscale.v1.HeadscaleService.GetNode:output_type -> headscale.v1.GetNodeResponse
|
||||||
35, // 35: headscale.v1.HeadscaleService.SetTags:output_type -> headscale.v1.SetTagsResponse
|
35, // 35: headscale.v1.HeadscaleService.SetTags:output_type -> headscale.v1.SetTagsResponse
|
||||||
36, // 36: headscale.v1.HeadscaleService.RegisterMachine:output_type -> headscale.v1.RegisterMachineResponse
|
36, // 36: headscale.v1.HeadscaleService.RegisterNode:output_type -> headscale.v1.RegisterNodeResponse
|
||||||
37, // 37: headscale.v1.HeadscaleService.DeleteMachine:output_type -> headscale.v1.DeleteMachineResponse
|
37, // 37: headscale.v1.HeadscaleService.DeleteNode:output_type -> headscale.v1.DeleteNodeResponse
|
||||||
38, // 38: headscale.v1.HeadscaleService.ExpireMachine:output_type -> headscale.v1.ExpireMachineResponse
|
38, // 38: headscale.v1.HeadscaleService.ExpireNode:output_type -> headscale.v1.ExpireNodeResponse
|
||||||
39, // 39: headscale.v1.HeadscaleService.RenameMachine:output_type -> headscale.v1.RenameMachineResponse
|
39, // 39: headscale.v1.HeadscaleService.RenameNode:output_type -> headscale.v1.RenameNodeResponse
|
||||||
40, // 40: headscale.v1.HeadscaleService.ListMachines:output_type -> headscale.v1.ListMachinesResponse
|
40, // 40: headscale.v1.HeadscaleService.ListNodes:output_type -> headscale.v1.ListNodesResponse
|
||||||
41, // 41: headscale.v1.HeadscaleService.MoveMachine:output_type -> headscale.v1.MoveMachineResponse
|
41, // 41: headscale.v1.HeadscaleService.MoveNode:output_type -> headscale.v1.MoveNodeResponse
|
||||||
42, // 42: headscale.v1.HeadscaleService.GetRoutes:output_type -> headscale.v1.GetRoutesResponse
|
42, // 42: headscale.v1.HeadscaleService.GetRoutes:output_type -> headscale.v1.GetRoutesResponse
|
||||||
43, // 43: headscale.v1.HeadscaleService.EnableRoute:output_type -> headscale.v1.EnableRouteResponse
|
43, // 43: headscale.v1.HeadscaleService.EnableRoute:output_type -> headscale.v1.EnableRouteResponse
|
||||||
44, // 44: headscale.v1.HeadscaleService.DisableRoute:output_type -> headscale.v1.DisableRouteResponse
|
44, // 44: headscale.v1.HeadscaleService.DisableRoute:output_type -> headscale.v1.DisableRouteResponse
|
||||||
45, // 45: headscale.v1.HeadscaleService.GetMachineRoutes:output_type -> headscale.v1.GetMachineRoutesResponse
|
45, // 45: headscale.v1.HeadscaleService.GetNodeRoutes:output_type -> headscale.v1.GetNodeRoutesResponse
|
||||||
46, // 46: headscale.v1.HeadscaleService.DeleteRoute:output_type -> headscale.v1.DeleteRouteResponse
|
46, // 46: headscale.v1.HeadscaleService.DeleteRoute:output_type -> headscale.v1.DeleteRouteResponse
|
||||||
47, // 47: headscale.v1.HeadscaleService.CreateApiKey:output_type -> headscale.v1.CreateApiKeyResponse
|
47, // 47: headscale.v1.HeadscaleService.CreateApiKey:output_type -> headscale.v1.CreateApiKeyResponse
|
||||||
48, // 48: headscale.v1.HeadscaleService.ExpireApiKey:output_type -> headscale.v1.ExpireApiKeyResponse
|
48, // 48: headscale.v1.HeadscaleService.ExpireApiKey:output_type -> headscale.v1.ExpireApiKeyResponse
|
||||||
|
@ -352,7 +343,7 @@ func file_headscale_v1_headscale_proto_init() {
|
||||||
}
|
}
|
||||||
file_headscale_v1_user_proto_init()
|
file_headscale_v1_user_proto_init()
|
||||||
file_headscale_v1_preauthkey_proto_init()
|
file_headscale_v1_preauthkey_proto_init()
|
||||||
file_headscale_v1_machine_proto_init()
|
file_headscale_v1_node_proto_init()
|
||||||
file_headscale_v1_routes_proto_init()
|
file_headscale_v1_routes_proto_init()
|
||||||
file_headscale_v1_apikey_proto_init()
|
file_headscale_v1_apikey_proto_init()
|
||||||
type x struct{}
|
type x struct{}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,19 +27,19 @@ const (
|
||||||
HeadscaleService_CreatePreAuthKey_FullMethodName = "/headscale.v1.HeadscaleService/CreatePreAuthKey"
|
HeadscaleService_CreatePreAuthKey_FullMethodName = "/headscale.v1.HeadscaleService/CreatePreAuthKey"
|
||||||
HeadscaleService_ExpirePreAuthKey_FullMethodName = "/headscale.v1.HeadscaleService/ExpirePreAuthKey"
|
HeadscaleService_ExpirePreAuthKey_FullMethodName = "/headscale.v1.HeadscaleService/ExpirePreAuthKey"
|
||||||
HeadscaleService_ListPreAuthKeys_FullMethodName = "/headscale.v1.HeadscaleService/ListPreAuthKeys"
|
HeadscaleService_ListPreAuthKeys_FullMethodName = "/headscale.v1.HeadscaleService/ListPreAuthKeys"
|
||||||
HeadscaleService_DebugCreateMachine_FullMethodName = "/headscale.v1.HeadscaleService/DebugCreateMachine"
|
HeadscaleService_DebugCreateNode_FullMethodName = "/headscale.v1.HeadscaleService/DebugCreateNode"
|
||||||
HeadscaleService_GetMachine_FullMethodName = "/headscale.v1.HeadscaleService/GetMachine"
|
HeadscaleService_GetNode_FullMethodName = "/headscale.v1.HeadscaleService/GetNode"
|
||||||
HeadscaleService_SetTags_FullMethodName = "/headscale.v1.HeadscaleService/SetTags"
|
HeadscaleService_SetTags_FullMethodName = "/headscale.v1.HeadscaleService/SetTags"
|
||||||
HeadscaleService_RegisterMachine_FullMethodName = "/headscale.v1.HeadscaleService/RegisterMachine"
|
HeadscaleService_RegisterNode_FullMethodName = "/headscale.v1.HeadscaleService/RegisterNode"
|
||||||
HeadscaleService_DeleteMachine_FullMethodName = "/headscale.v1.HeadscaleService/DeleteMachine"
|
HeadscaleService_DeleteNode_FullMethodName = "/headscale.v1.HeadscaleService/DeleteNode"
|
||||||
HeadscaleService_ExpireMachine_FullMethodName = "/headscale.v1.HeadscaleService/ExpireMachine"
|
HeadscaleService_ExpireNode_FullMethodName = "/headscale.v1.HeadscaleService/ExpireNode"
|
||||||
HeadscaleService_RenameMachine_FullMethodName = "/headscale.v1.HeadscaleService/RenameMachine"
|
HeadscaleService_RenameNode_FullMethodName = "/headscale.v1.HeadscaleService/RenameNode"
|
||||||
HeadscaleService_ListMachines_FullMethodName = "/headscale.v1.HeadscaleService/ListMachines"
|
HeadscaleService_ListNodes_FullMethodName = "/headscale.v1.HeadscaleService/ListNodes"
|
||||||
HeadscaleService_MoveMachine_FullMethodName = "/headscale.v1.HeadscaleService/MoveMachine"
|
HeadscaleService_MoveNode_FullMethodName = "/headscale.v1.HeadscaleService/MoveNode"
|
||||||
HeadscaleService_GetRoutes_FullMethodName = "/headscale.v1.HeadscaleService/GetRoutes"
|
HeadscaleService_GetRoutes_FullMethodName = "/headscale.v1.HeadscaleService/GetRoutes"
|
||||||
HeadscaleService_EnableRoute_FullMethodName = "/headscale.v1.HeadscaleService/EnableRoute"
|
HeadscaleService_EnableRoute_FullMethodName = "/headscale.v1.HeadscaleService/EnableRoute"
|
||||||
HeadscaleService_DisableRoute_FullMethodName = "/headscale.v1.HeadscaleService/DisableRoute"
|
HeadscaleService_DisableRoute_FullMethodName = "/headscale.v1.HeadscaleService/DisableRoute"
|
||||||
HeadscaleService_GetMachineRoutes_FullMethodName = "/headscale.v1.HeadscaleService/GetMachineRoutes"
|
HeadscaleService_GetNodeRoutes_FullMethodName = "/headscale.v1.HeadscaleService/GetNodeRoutes"
|
||||||
HeadscaleService_DeleteRoute_FullMethodName = "/headscale.v1.HeadscaleService/DeleteRoute"
|
HeadscaleService_DeleteRoute_FullMethodName = "/headscale.v1.HeadscaleService/DeleteRoute"
|
||||||
HeadscaleService_CreateApiKey_FullMethodName = "/headscale.v1.HeadscaleService/CreateApiKey"
|
HeadscaleService_CreateApiKey_FullMethodName = "/headscale.v1.HeadscaleService/CreateApiKey"
|
||||||
HeadscaleService_ExpireApiKey_FullMethodName = "/headscale.v1.HeadscaleService/ExpireApiKey"
|
HeadscaleService_ExpireApiKey_FullMethodName = "/headscale.v1.HeadscaleService/ExpireApiKey"
|
||||||
|
@ -60,21 +60,21 @@ type HeadscaleServiceClient interface {
|
||||||
CreatePreAuthKey(ctx context.Context, in *CreatePreAuthKeyRequest, opts ...grpc.CallOption) (*CreatePreAuthKeyResponse, error)
|
CreatePreAuthKey(ctx context.Context, in *CreatePreAuthKeyRequest, opts ...grpc.CallOption) (*CreatePreAuthKeyResponse, error)
|
||||||
ExpirePreAuthKey(ctx context.Context, in *ExpirePreAuthKeyRequest, opts ...grpc.CallOption) (*ExpirePreAuthKeyResponse, error)
|
ExpirePreAuthKey(ctx context.Context, in *ExpirePreAuthKeyRequest, opts ...grpc.CallOption) (*ExpirePreAuthKeyResponse, error)
|
||||||
ListPreAuthKeys(ctx context.Context, in *ListPreAuthKeysRequest, opts ...grpc.CallOption) (*ListPreAuthKeysResponse, error)
|
ListPreAuthKeys(ctx context.Context, in *ListPreAuthKeysRequest, opts ...grpc.CallOption) (*ListPreAuthKeysResponse, error)
|
||||||
// --- Machine start ---
|
// --- Node start ---
|
||||||
DebugCreateMachine(ctx context.Context, in *DebugCreateMachineRequest, opts ...grpc.CallOption) (*DebugCreateMachineResponse, error)
|
DebugCreateNode(ctx context.Context, in *DebugCreateNodeRequest, opts ...grpc.CallOption) (*DebugCreateNodeResponse, error)
|
||||||
GetMachine(ctx context.Context, in *GetMachineRequest, opts ...grpc.CallOption) (*GetMachineResponse, error)
|
GetNode(ctx context.Context, in *GetNodeRequest, opts ...grpc.CallOption) (*GetNodeResponse, error)
|
||||||
SetTags(ctx context.Context, in *SetTagsRequest, opts ...grpc.CallOption) (*SetTagsResponse, error)
|
SetTags(ctx context.Context, in *SetTagsRequest, opts ...grpc.CallOption) (*SetTagsResponse, error)
|
||||||
RegisterMachine(ctx context.Context, in *RegisterMachineRequest, opts ...grpc.CallOption) (*RegisterMachineResponse, error)
|
RegisterNode(ctx context.Context, in *RegisterNodeRequest, opts ...grpc.CallOption) (*RegisterNodeResponse, error)
|
||||||
DeleteMachine(ctx context.Context, in *DeleteMachineRequest, opts ...grpc.CallOption) (*DeleteMachineResponse, error)
|
DeleteNode(ctx context.Context, in *DeleteNodeRequest, opts ...grpc.CallOption) (*DeleteNodeResponse, error)
|
||||||
ExpireMachine(ctx context.Context, in *ExpireMachineRequest, opts ...grpc.CallOption) (*ExpireMachineResponse, error)
|
ExpireNode(ctx context.Context, in *ExpireNodeRequest, opts ...grpc.CallOption) (*ExpireNodeResponse, error)
|
||||||
RenameMachine(ctx context.Context, in *RenameMachineRequest, opts ...grpc.CallOption) (*RenameMachineResponse, error)
|
RenameNode(ctx context.Context, in *RenameNodeRequest, opts ...grpc.CallOption) (*RenameNodeResponse, error)
|
||||||
ListMachines(ctx context.Context, in *ListMachinesRequest, opts ...grpc.CallOption) (*ListMachinesResponse, error)
|
ListNodes(ctx context.Context, in *ListNodesRequest, opts ...grpc.CallOption) (*ListNodesResponse, error)
|
||||||
MoveMachine(ctx context.Context, in *MoveMachineRequest, opts ...grpc.CallOption) (*MoveMachineResponse, error)
|
MoveNode(ctx context.Context, in *MoveNodeRequest, opts ...grpc.CallOption) (*MoveNodeResponse, error)
|
||||||
// --- Route start ---
|
// --- Route start ---
|
||||||
GetRoutes(ctx context.Context, in *GetRoutesRequest, opts ...grpc.CallOption) (*GetRoutesResponse, error)
|
GetRoutes(ctx context.Context, in *GetRoutesRequest, opts ...grpc.CallOption) (*GetRoutesResponse, error)
|
||||||
EnableRoute(ctx context.Context, in *EnableRouteRequest, opts ...grpc.CallOption) (*EnableRouteResponse, error)
|
EnableRoute(ctx context.Context, in *EnableRouteRequest, opts ...grpc.CallOption) (*EnableRouteResponse, error)
|
||||||
DisableRoute(ctx context.Context, in *DisableRouteRequest, opts ...grpc.CallOption) (*DisableRouteResponse, error)
|
DisableRoute(ctx context.Context, in *DisableRouteRequest, opts ...grpc.CallOption) (*DisableRouteResponse, error)
|
||||||
GetMachineRoutes(ctx context.Context, in *GetMachineRoutesRequest, opts ...grpc.CallOption) (*GetMachineRoutesResponse, error)
|
GetNodeRoutes(ctx context.Context, in *GetNodeRoutesRequest, opts ...grpc.CallOption) (*GetNodeRoutesResponse, error)
|
||||||
DeleteRoute(ctx context.Context, in *DeleteRouteRequest, opts ...grpc.CallOption) (*DeleteRouteResponse, error)
|
DeleteRoute(ctx context.Context, in *DeleteRouteRequest, opts ...grpc.CallOption) (*DeleteRouteResponse, error)
|
||||||
// --- ApiKeys start ---
|
// --- ApiKeys start ---
|
||||||
CreateApiKey(ctx context.Context, in *CreateApiKeyRequest, opts ...grpc.CallOption) (*CreateApiKeyResponse, error)
|
CreateApiKey(ctx context.Context, in *CreateApiKeyRequest, opts ...grpc.CallOption) (*CreateApiKeyResponse, error)
|
||||||
|
@ -162,18 +162,18 @@ func (c *headscaleServiceClient) ListPreAuthKeys(ctx context.Context, in *ListPr
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *headscaleServiceClient) DebugCreateMachine(ctx context.Context, in *DebugCreateMachineRequest, opts ...grpc.CallOption) (*DebugCreateMachineResponse, error) {
|
func (c *headscaleServiceClient) DebugCreateNode(ctx context.Context, in *DebugCreateNodeRequest, opts ...grpc.CallOption) (*DebugCreateNodeResponse, error) {
|
||||||
out := new(DebugCreateMachineResponse)
|
out := new(DebugCreateNodeResponse)
|
||||||
err := c.cc.Invoke(ctx, HeadscaleService_DebugCreateMachine_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, HeadscaleService_DebugCreateNode_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *headscaleServiceClient) GetMachine(ctx context.Context, in *GetMachineRequest, opts ...grpc.CallOption) (*GetMachineResponse, error) {
|
func (c *headscaleServiceClient) GetNode(ctx context.Context, in *GetNodeRequest, opts ...grpc.CallOption) (*GetNodeResponse, error) {
|
||||||
out := new(GetMachineResponse)
|
out := new(GetNodeResponse)
|
||||||
err := c.cc.Invoke(ctx, HeadscaleService_GetMachine_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, HeadscaleService_GetNode_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -189,54 +189,54 @@ func (c *headscaleServiceClient) SetTags(ctx context.Context, in *SetTagsRequest
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *headscaleServiceClient) RegisterMachine(ctx context.Context, in *RegisterMachineRequest, opts ...grpc.CallOption) (*RegisterMachineResponse, error) {
|
func (c *headscaleServiceClient) RegisterNode(ctx context.Context, in *RegisterNodeRequest, opts ...grpc.CallOption) (*RegisterNodeResponse, error) {
|
||||||
out := new(RegisterMachineResponse)
|
out := new(RegisterNodeResponse)
|
||||||
err := c.cc.Invoke(ctx, HeadscaleService_RegisterMachine_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, HeadscaleService_RegisterNode_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *headscaleServiceClient) DeleteMachine(ctx context.Context, in *DeleteMachineRequest, opts ...grpc.CallOption) (*DeleteMachineResponse, error) {
|
func (c *headscaleServiceClient) DeleteNode(ctx context.Context, in *DeleteNodeRequest, opts ...grpc.CallOption) (*DeleteNodeResponse, error) {
|
||||||
out := new(DeleteMachineResponse)
|
out := new(DeleteNodeResponse)
|
||||||
err := c.cc.Invoke(ctx, HeadscaleService_DeleteMachine_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, HeadscaleService_DeleteNode_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *headscaleServiceClient) ExpireMachine(ctx context.Context, in *ExpireMachineRequest, opts ...grpc.CallOption) (*ExpireMachineResponse, error) {
|
func (c *headscaleServiceClient) ExpireNode(ctx context.Context, in *ExpireNodeRequest, opts ...grpc.CallOption) (*ExpireNodeResponse, error) {
|
||||||
out := new(ExpireMachineResponse)
|
out := new(ExpireNodeResponse)
|
||||||
err := c.cc.Invoke(ctx, HeadscaleService_ExpireMachine_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, HeadscaleService_ExpireNode_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *headscaleServiceClient) RenameMachine(ctx context.Context, in *RenameMachineRequest, opts ...grpc.CallOption) (*RenameMachineResponse, error) {
|
func (c *headscaleServiceClient) RenameNode(ctx context.Context, in *RenameNodeRequest, opts ...grpc.CallOption) (*RenameNodeResponse, error) {
|
||||||
out := new(RenameMachineResponse)
|
out := new(RenameNodeResponse)
|
||||||
err := c.cc.Invoke(ctx, HeadscaleService_RenameMachine_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, HeadscaleService_RenameNode_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *headscaleServiceClient) ListMachines(ctx context.Context, in *ListMachinesRequest, opts ...grpc.CallOption) (*ListMachinesResponse, error) {
|
func (c *headscaleServiceClient) ListNodes(ctx context.Context, in *ListNodesRequest, opts ...grpc.CallOption) (*ListNodesResponse, error) {
|
||||||
out := new(ListMachinesResponse)
|
out := new(ListNodesResponse)
|
||||||
err := c.cc.Invoke(ctx, HeadscaleService_ListMachines_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, HeadscaleService_ListNodes_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *headscaleServiceClient) MoveMachine(ctx context.Context, in *MoveMachineRequest, opts ...grpc.CallOption) (*MoveMachineResponse, error) {
|
func (c *headscaleServiceClient) MoveNode(ctx context.Context, in *MoveNodeRequest, opts ...grpc.CallOption) (*MoveNodeResponse, error) {
|
||||||
out := new(MoveMachineResponse)
|
out := new(MoveNodeResponse)
|
||||||
err := c.cc.Invoke(ctx, HeadscaleService_MoveMachine_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, HeadscaleService_MoveNode_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -270,9 +270,9 @@ func (c *headscaleServiceClient) DisableRoute(ctx context.Context, in *DisableRo
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *headscaleServiceClient) GetMachineRoutes(ctx context.Context, in *GetMachineRoutesRequest, opts ...grpc.CallOption) (*GetMachineRoutesResponse, error) {
|
func (c *headscaleServiceClient) GetNodeRoutes(ctx context.Context, in *GetNodeRoutesRequest, opts ...grpc.CallOption) (*GetNodeRoutesResponse, error) {
|
||||||
out := new(GetMachineRoutesResponse)
|
out := new(GetNodeRoutesResponse)
|
||||||
err := c.cc.Invoke(ctx, HeadscaleService_GetMachineRoutes_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, HeadscaleService_GetNodeRoutes_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -329,21 +329,21 @@ type HeadscaleServiceServer interface {
|
||||||
CreatePreAuthKey(context.Context, *CreatePreAuthKeyRequest) (*CreatePreAuthKeyResponse, error)
|
CreatePreAuthKey(context.Context, *CreatePreAuthKeyRequest) (*CreatePreAuthKeyResponse, error)
|
||||||
ExpirePreAuthKey(context.Context, *ExpirePreAuthKeyRequest) (*ExpirePreAuthKeyResponse, error)
|
ExpirePreAuthKey(context.Context, *ExpirePreAuthKeyRequest) (*ExpirePreAuthKeyResponse, error)
|
||||||
ListPreAuthKeys(context.Context, *ListPreAuthKeysRequest) (*ListPreAuthKeysResponse, error)
|
ListPreAuthKeys(context.Context, *ListPreAuthKeysRequest) (*ListPreAuthKeysResponse, error)
|
||||||
// --- Machine start ---
|
// --- Node start ---
|
||||||
DebugCreateMachine(context.Context, *DebugCreateMachineRequest) (*DebugCreateMachineResponse, error)
|
DebugCreateNode(context.Context, *DebugCreateNodeRequest) (*DebugCreateNodeResponse, error)
|
||||||
GetMachine(context.Context, *GetMachineRequest) (*GetMachineResponse, error)
|
GetNode(context.Context, *GetNodeRequest) (*GetNodeResponse, error)
|
||||||
SetTags(context.Context, *SetTagsRequest) (*SetTagsResponse, error)
|
SetTags(context.Context, *SetTagsRequest) (*SetTagsResponse, error)
|
||||||
RegisterMachine(context.Context, *RegisterMachineRequest) (*RegisterMachineResponse, error)
|
RegisterNode(context.Context, *RegisterNodeRequest) (*RegisterNodeResponse, error)
|
||||||
DeleteMachine(context.Context, *DeleteMachineRequest) (*DeleteMachineResponse, error)
|
DeleteNode(context.Context, *DeleteNodeRequest) (*DeleteNodeResponse, error)
|
||||||
ExpireMachine(context.Context, *ExpireMachineRequest) (*ExpireMachineResponse, error)
|
ExpireNode(context.Context, *ExpireNodeRequest) (*ExpireNodeResponse, error)
|
||||||
RenameMachine(context.Context, *RenameMachineRequest) (*RenameMachineResponse, error)
|
RenameNode(context.Context, *RenameNodeRequest) (*RenameNodeResponse, error)
|
||||||
ListMachines(context.Context, *ListMachinesRequest) (*ListMachinesResponse, error)
|
ListNodes(context.Context, *ListNodesRequest) (*ListNodesResponse, error)
|
||||||
MoveMachine(context.Context, *MoveMachineRequest) (*MoveMachineResponse, error)
|
MoveNode(context.Context, *MoveNodeRequest) (*MoveNodeResponse, error)
|
||||||
// --- Route start ---
|
// --- Route start ---
|
||||||
GetRoutes(context.Context, *GetRoutesRequest) (*GetRoutesResponse, error)
|
GetRoutes(context.Context, *GetRoutesRequest) (*GetRoutesResponse, error)
|
||||||
EnableRoute(context.Context, *EnableRouteRequest) (*EnableRouteResponse, error)
|
EnableRoute(context.Context, *EnableRouteRequest) (*EnableRouteResponse, error)
|
||||||
DisableRoute(context.Context, *DisableRouteRequest) (*DisableRouteResponse, error)
|
DisableRoute(context.Context, *DisableRouteRequest) (*DisableRouteResponse, error)
|
||||||
GetMachineRoutes(context.Context, *GetMachineRoutesRequest) (*GetMachineRoutesResponse, error)
|
GetNodeRoutes(context.Context, *GetNodeRoutesRequest) (*GetNodeRoutesResponse, error)
|
||||||
DeleteRoute(context.Context, *DeleteRouteRequest) (*DeleteRouteResponse, error)
|
DeleteRoute(context.Context, *DeleteRouteRequest) (*DeleteRouteResponse, error)
|
||||||
// --- ApiKeys start ---
|
// --- ApiKeys start ---
|
||||||
CreateApiKey(context.Context, *CreateApiKeyRequest) (*CreateApiKeyResponse, error)
|
CreateApiKey(context.Context, *CreateApiKeyRequest) (*CreateApiKeyResponse, error)
|
||||||
|
@ -380,32 +380,32 @@ func (UnimplementedHeadscaleServiceServer) ExpirePreAuthKey(context.Context, *Ex
|
||||||
func (UnimplementedHeadscaleServiceServer) ListPreAuthKeys(context.Context, *ListPreAuthKeysRequest) (*ListPreAuthKeysResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) ListPreAuthKeys(context.Context, *ListPreAuthKeysRequest) (*ListPreAuthKeysResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ListPreAuthKeys not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ListPreAuthKeys not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) DebugCreateMachine(context.Context, *DebugCreateMachineRequest) (*DebugCreateMachineResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) DebugCreateNode(context.Context, *DebugCreateNodeRequest) (*DebugCreateNodeResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method DebugCreateMachine not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method DebugCreateNode not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) GetMachine(context.Context, *GetMachineRequest) (*GetMachineResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) GetNode(context.Context, *GetNodeRequest) (*GetNodeResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetMachine not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetNode not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) SetTags(context.Context, *SetTagsRequest) (*SetTagsResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) SetTags(context.Context, *SetTagsRequest) (*SetTagsResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method SetTags not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method SetTags not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) RegisterMachine(context.Context, *RegisterMachineRequest) (*RegisterMachineResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) RegisterNode(context.Context, *RegisterNodeRequest) (*RegisterNodeResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method RegisterMachine not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method RegisterNode not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) DeleteMachine(context.Context, *DeleteMachineRequest) (*DeleteMachineResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) DeleteNode(context.Context, *DeleteNodeRequest) (*DeleteNodeResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteMachine not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method DeleteNode not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) ExpireMachine(context.Context, *ExpireMachineRequest) (*ExpireMachineResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) ExpireNode(context.Context, *ExpireNodeRequest) (*ExpireNodeResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ExpireMachine not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ExpireNode not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) RenameMachine(context.Context, *RenameMachineRequest) (*RenameMachineResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) RenameNode(context.Context, *RenameNodeRequest) (*RenameNodeResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method RenameMachine not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method RenameNode not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) ListMachines(context.Context, *ListMachinesRequest) (*ListMachinesResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) ListNodes(context.Context, *ListNodesRequest) (*ListNodesResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ListMachines not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ListNodes not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) MoveMachine(context.Context, *MoveMachineRequest) (*MoveMachineResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) MoveNode(context.Context, *MoveNodeRequest) (*MoveNodeResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method MoveMachine not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method MoveNode not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) GetRoutes(context.Context, *GetRoutesRequest) (*GetRoutesResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) GetRoutes(context.Context, *GetRoutesRequest) (*GetRoutesResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetRoutes not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetRoutes not implemented")
|
||||||
|
@ -416,8 +416,8 @@ func (UnimplementedHeadscaleServiceServer) EnableRoute(context.Context, *EnableR
|
||||||
func (UnimplementedHeadscaleServiceServer) DisableRoute(context.Context, *DisableRouteRequest) (*DisableRouteResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) DisableRoute(context.Context, *DisableRouteRequest) (*DisableRouteResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method DisableRoute not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method DisableRoute not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) GetMachineRoutes(context.Context, *GetMachineRoutesRequest) (*GetMachineRoutesResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) GetNodeRoutes(context.Context, *GetNodeRoutesRequest) (*GetNodeRoutesResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetMachineRoutes not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetNodeRoutes not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHeadscaleServiceServer) DeleteRoute(context.Context, *DeleteRouteRequest) (*DeleteRouteResponse, error) {
|
func (UnimplementedHeadscaleServiceServer) DeleteRoute(context.Context, *DeleteRouteRequest) (*DeleteRouteResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteRoute not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method DeleteRoute not implemented")
|
||||||
|
@ -588,38 +588,38 @@ func _HeadscaleService_ListPreAuthKeys_Handler(srv interface{}, ctx context.Cont
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HeadscaleService_DebugCreateMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HeadscaleService_DebugCreateNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(DebugCreateMachineRequest)
|
in := new(DebugCreateNodeRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(HeadscaleServiceServer).DebugCreateMachine(ctx, in)
|
return srv.(HeadscaleServiceServer).DebugCreateNode(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HeadscaleService_DebugCreateMachine_FullMethodName,
|
FullMethod: HeadscaleService_DebugCreateNode_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HeadscaleServiceServer).DebugCreateMachine(ctx, req.(*DebugCreateMachineRequest))
|
return srv.(HeadscaleServiceServer).DebugCreateNode(ctx, req.(*DebugCreateNodeRequest))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HeadscaleService_GetMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HeadscaleService_GetNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(GetMachineRequest)
|
in := new(GetNodeRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(HeadscaleServiceServer).GetMachine(ctx, in)
|
return srv.(HeadscaleServiceServer).GetNode(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HeadscaleService_GetMachine_FullMethodName,
|
FullMethod: HeadscaleService_GetNode_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HeadscaleServiceServer).GetMachine(ctx, req.(*GetMachineRequest))
|
return srv.(HeadscaleServiceServer).GetNode(ctx, req.(*GetNodeRequest))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
@ -642,110 +642,110 @@ func _HeadscaleService_SetTags_Handler(srv interface{}, ctx context.Context, dec
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HeadscaleService_RegisterMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HeadscaleService_RegisterNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(RegisterMachineRequest)
|
in := new(RegisterNodeRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(HeadscaleServiceServer).RegisterMachine(ctx, in)
|
return srv.(HeadscaleServiceServer).RegisterNode(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HeadscaleService_RegisterMachine_FullMethodName,
|
FullMethod: HeadscaleService_RegisterNode_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HeadscaleServiceServer).RegisterMachine(ctx, req.(*RegisterMachineRequest))
|
return srv.(HeadscaleServiceServer).RegisterNode(ctx, req.(*RegisterNodeRequest))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HeadscaleService_DeleteMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HeadscaleService_DeleteNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(DeleteMachineRequest)
|
in := new(DeleteNodeRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(HeadscaleServiceServer).DeleteMachine(ctx, in)
|
return srv.(HeadscaleServiceServer).DeleteNode(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HeadscaleService_DeleteMachine_FullMethodName,
|
FullMethod: HeadscaleService_DeleteNode_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HeadscaleServiceServer).DeleteMachine(ctx, req.(*DeleteMachineRequest))
|
return srv.(HeadscaleServiceServer).DeleteNode(ctx, req.(*DeleteNodeRequest))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HeadscaleService_ExpireMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HeadscaleService_ExpireNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(ExpireMachineRequest)
|
in := new(ExpireNodeRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(HeadscaleServiceServer).ExpireMachine(ctx, in)
|
return srv.(HeadscaleServiceServer).ExpireNode(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HeadscaleService_ExpireMachine_FullMethodName,
|
FullMethod: HeadscaleService_ExpireNode_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HeadscaleServiceServer).ExpireMachine(ctx, req.(*ExpireMachineRequest))
|
return srv.(HeadscaleServiceServer).ExpireNode(ctx, req.(*ExpireNodeRequest))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HeadscaleService_RenameMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HeadscaleService_RenameNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(RenameMachineRequest)
|
in := new(RenameNodeRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(HeadscaleServiceServer).RenameMachine(ctx, in)
|
return srv.(HeadscaleServiceServer).RenameNode(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HeadscaleService_RenameMachine_FullMethodName,
|
FullMethod: HeadscaleService_RenameNode_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HeadscaleServiceServer).RenameMachine(ctx, req.(*RenameMachineRequest))
|
return srv.(HeadscaleServiceServer).RenameNode(ctx, req.(*RenameNodeRequest))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HeadscaleService_ListMachines_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HeadscaleService_ListNodes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(ListMachinesRequest)
|
in := new(ListNodesRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(HeadscaleServiceServer).ListMachines(ctx, in)
|
return srv.(HeadscaleServiceServer).ListNodes(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HeadscaleService_ListMachines_FullMethodName,
|
FullMethod: HeadscaleService_ListNodes_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HeadscaleServiceServer).ListMachines(ctx, req.(*ListMachinesRequest))
|
return srv.(HeadscaleServiceServer).ListNodes(ctx, req.(*ListNodesRequest))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HeadscaleService_MoveMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HeadscaleService_MoveNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(MoveMachineRequest)
|
in := new(MoveNodeRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(HeadscaleServiceServer).MoveMachine(ctx, in)
|
return srv.(HeadscaleServiceServer).MoveNode(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HeadscaleService_MoveMachine_FullMethodName,
|
FullMethod: HeadscaleService_MoveNode_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HeadscaleServiceServer).MoveMachine(ctx, req.(*MoveMachineRequest))
|
return srv.(HeadscaleServiceServer).MoveNode(ctx, req.(*MoveNodeRequest))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
@ -804,20 +804,20 @@ func _HeadscaleService_DisableRoute_Handler(srv interface{}, ctx context.Context
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HeadscaleService_GetMachineRoutes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HeadscaleService_GetNodeRoutes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(GetMachineRoutesRequest)
|
in := new(GetNodeRoutesRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(HeadscaleServiceServer).GetMachineRoutes(ctx, in)
|
return srv.(HeadscaleServiceServer).GetNodeRoutes(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HeadscaleService_GetMachineRoutes_FullMethodName,
|
FullMethod: HeadscaleService_GetNodeRoutes_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HeadscaleServiceServer).GetMachineRoutes(ctx, req.(*GetMachineRoutesRequest))
|
return srv.(HeadscaleServiceServer).GetNodeRoutes(ctx, req.(*GetNodeRoutesRequest))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
@ -934,40 +934,40 @@ var HeadscaleService_ServiceDesc = grpc.ServiceDesc{
|
||||||
Handler: _HeadscaleService_ListPreAuthKeys_Handler,
|
Handler: _HeadscaleService_ListPreAuthKeys_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "DebugCreateMachine",
|
MethodName: "DebugCreateNode",
|
||||||
Handler: _HeadscaleService_DebugCreateMachine_Handler,
|
Handler: _HeadscaleService_DebugCreateNode_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "GetMachine",
|
MethodName: "GetNode",
|
||||||
Handler: _HeadscaleService_GetMachine_Handler,
|
Handler: _HeadscaleService_GetNode_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "SetTags",
|
MethodName: "SetTags",
|
||||||
Handler: _HeadscaleService_SetTags_Handler,
|
Handler: _HeadscaleService_SetTags_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "RegisterMachine",
|
MethodName: "RegisterNode",
|
||||||
Handler: _HeadscaleService_RegisterMachine_Handler,
|
Handler: _HeadscaleService_RegisterNode_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "DeleteMachine",
|
MethodName: "DeleteNode",
|
||||||
Handler: _HeadscaleService_DeleteMachine_Handler,
|
Handler: _HeadscaleService_DeleteNode_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "ExpireMachine",
|
MethodName: "ExpireNode",
|
||||||
Handler: _HeadscaleService_ExpireMachine_Handler,
|
Handler: _HeadscaleService_ExpireNode_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "RenameMachine",
|
MethodName: "RenameNode",
|
||||||
Handler: _HeadscaleService_RenameMachine_Handler,
|
Handler: _HeadscaleService_RenameNode_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "ListMachines",
|
MethodName: "ListNodes",
|
||||||
Handler: _HeadscaleService_ListMachines_Handler,
|
Handler: _HeadscaleService_ListNodes_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "MoveMachine",
|
MethodName: "MoveNode",
|
||||||
Handler: _HeadscaleService_MoveMachine_Handler,
|
Handler: _HeadscaleService_MoveNode_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "GetRoutes",
|
MethodName: "GetRoutes",
|
||||||
|
@ -982,8 +982,8 @@ var HeadscaleService_ServiceDesc = grpc.ServiceDesc{
|
||||||
Handler: _HeadscaleService_DisableRoute_Handler,
|
Handler: _HeadscaleService_DisableRoute_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "GetMachineRoutes",
|
MethodName: "GetNodeRoutes",
|
||||||
Handler: _HeadscaleService_GetMachineRoutes_Handler,
|
Handler: _HeadscaleService_GetNodeRoutes_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "DeleteRoute",
|
MethodName: "DeleteRoute",
|
||||||
|
|
File diff suppressed because it is too large
Load diff
1608
gen/go/headscale/v1/node.pb.go
Normal file
1608
gen/go/headscale/v1/node.pb.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.29.1
|
// protoc-gen-go v1.31.0
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: headscale/v1/preauthkey.proto
|
// source: headscale/v1/preauthkey.proto
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.29.1
|
// protoc-gen-go v1.31.0
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: headscale/v1/routes.proto
|
// source: headscale/v1/routes.proto
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ type Route struct {
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
Machine *Machine `protobuf:"bytes,2,opt,name=machine,proto3" json:"machine,omitempty"`
|
Node *Node `protobuf:"bytes,2,opt,name=node,proto3" json:"node,omitempty"`
|
||||||
Prefix string `protobuf:"bytes,3,opt,name=prefix,proto3" json:"prefix,omitempty"`
|
Prefix string `protobuf:"bytes,3,opt,name=prefix,proto3" json:"prefix,omitempty"`
|
||||||
Advertised bool `protobuf:"varint,4,opt,name=advertised,proto3" json:"advertised,omitempty"`
|
Advertised bool `protobuf:"varint,4,opt,name=advertised,proto3" json:"advertised,omitempty"`
|
||||||
Enabled bool `protobuf:"varint,5,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
Enabled bool `protobuf:"varint,5,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||||
|
@ -76,9 +76,9 @@ func (x *Route) GetId() uint64 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Route) GetMachine() *Machine {
|
func (x *Route) GetNode() *Node {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Machine
|
return x.Node
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -387,16 +387,16 @@ func (*DisableRouteResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_headscale_v1_routes_proto_rawDescGZIP(), []int{6}
|
return file_headscale_v1_routes_proto_rawDescGZIP(), []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetMachineRoutesRequest struct {
|
type GetNodeRoutesRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
MachineId uint64 `protobuf:"varint,1,opt,name=machine_id,json=machineId,proto3" json:"machine_id,omitempty"`
|
NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetMachineRoutesRequest) Reset() {
|
func (x *GetNodeRoutesRequest) Reset() {
|
||||||
*x = GetMachineRoutesRequest{}
|
*x = GetNodeRoutesRequest{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_headscale_v1_routes_proto_msgTypes[7]
|
mi := &file_headscale_v1_routes_proto_msgTypes[7]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
@ -404,13 +404,13 @@ func (x *GetMachineRoutesRequest) Reset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetMachineRoutesRequest) String() string {
|
func (x *GetNodeRoutesRequest) String() string {
|
||||||
return protoimpl.X.MessageStringOf(x)
|
return protoimpl.X.MessageStringOf(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*GetMachineRoutesRequest) ProtoMessage() {}
|
func (*GetNodeRoutesRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *GetMachineRoutesRequest) ProtoReflect() protoreflect.Message {
|
func (x *GetNodeRoutesRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_headscale_v1_routes_proto_msgTypes[7]
|
mi := &file_headscale_v1_routes_proto_msgTypes[7]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
@ -422,19 +422,19 @@ func (x *GetMachineRoutesRequest) ProtoReflect() protoreflect.Message {
|
||||||
return mi.MessageOf(x)
|
return mi.MessageOf(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: Use GetMachineRoutesRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use GetNodeRoutesRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*GetMachineRoutesRequest) Descriptor() ([]byte, []int) {
|
func (*GetNodeRoutesRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_headscale_v1_routes_proto_rawDescGZIP(), []int{7}
|
return file_headscale_v1_routes_proto_rawDescGZIP(), []int{7}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetMachineRoutesRequest) GetMachineId() uint64 {
|
func (x *GetNodeRoutesRequest) GetNodeId() uint64 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.MachineId
|
return x.NodeId
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetMachineRoutesResponse struct {
|
type GetNodeRoutesResponse struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
@ -442,8 +442,8 @@ type GetMachineRoutesResponse struct {
|
||||||
Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"`
|
Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetMachineRoutesResponse) Reset() {
|
func (x *GetNodeRoutesResponse) Reset() {
|
||||||
*x = GetMachineRoutesResponse{}
|
*x = GetNodeRoutesResponse{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_headscale_v1_routes_proto_msgTypes[8]
|
mi := &file_headscale_v1_routes_proto_msgTypes[8]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
@ -451,13 +451,13 @@ func (x *GetMachineRoutesResponse) Reset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetMachineRoutesResponse) String() string {
|
func (x *GetNodeRoutesResponse) String() string {
|
||||||
return protoimpl.X.MessageStringOf(x)
|
return protoimpl.X.MessageStringOf(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*GetMachineRoutesResponse) ProtoMessage() {}
|
func (*GetNodeRoutesResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *GetMachineRoutesResponse) ProtoReflect() protoreflect.Message {
|
func (x *GetNodeRoutesResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_headscale_v1_routes_proto_msgTypes[8]
|
mi := &file_headscale_v1_routes_proto_msgTypes[8]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
@ -469,12 +469,12 @@ func (x *GetMachineRoutesResponse) ProtoReflect() protoreflect.Message {
|
||||||
return mi.MessageOf(x)
|
return mi.MessageOf(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: Use GetMachineRoutesResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use GetNodeRoutesResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*GetMachineRoutesResponse) Descriptor() ([]byte, []int) {
|
func (*GetNodeRoutesResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_headscale_v1_routes_proto_rawDescGZIP(), []int{8}
|
return file_headscale_v1_routes_proto_rawDescGZIP(), []int{8}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetMachineRoutesResponse) GetRoutes() []*Route {
|
func (x *GetNodeRoutesResponse) GetRoutes() []*Route {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Routes
|
return x.Routes
|
||||||
}
|
}
|
||||||
|
@ -573,62 +573,61 @@ var file_headscale_v1_routes_proto_rawDesc = []byte{
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x68, 0x65, 0x61,
|
0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x68, 0x65, 0x61,
|
||||||
0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||||
0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73,
|
0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73,
|
||||||
0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x68, 0x65, 0x61, 0x64,
|
0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x68, 0x65, 0x61, 0x64,
|
||||||
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xea, 0x02, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
0x6f, 0x74, 0x6f, 0x22, 0xe1, 0x02, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x0e, 0x0a,
|
||||||
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64,
|
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a,
|
||||||
0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65,
|
||||||
0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31,
|
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52,
|
||||||
0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18,
|
||||||
0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28,
|
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1e, 0x0a,
|
||||||
0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, 0x76,
|
0x0a, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||||
0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61,
|
0x08, 0x52, 0x0a, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x12, 0x18, 0x0a,
|
||||||
0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61,
|
0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07,
|
||||||
0x62, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62,
|
0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x70, 0x72,
|
||||||
0x6c, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72,
|
0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x50,
|
||||||
0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x50, 0x72, 0x69, 0x6d, 0x61,
|
0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||||
0x72, 0x79, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74,
|
0x64, 0x5f, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
|
||||||
0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41,
|
||||||
0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a,
|
0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18,
|
||||||
0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28,
|
0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
||||||
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
||||||
0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75,
|
0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a,
|
||||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x65,
|
0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b,
|
||||||
0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
|
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
|
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x64, 0x65,
|
||||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65,
|
0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, 0x6f,
|
||||||
0x64, 0x41, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73,
|
0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x40, 0x0a, 0x11, 0x47,
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x40, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x52, 0x6f,
|
0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||||
0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x06,
|
0x12, 0x2b, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x68,
|
0x32, 0x13, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e,
|
||||||
0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x74,
|
0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x2f, 0x0a,
|
||||||
0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x12, 0x45, 0x6e, 0x61,
|
0x12, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
|
||||||
0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18,
|
||||||
0x19, 0x0a, 0x08, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x22, 0x15,
|
||||||
0x04, 0x52, 0x07, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x45, 0x6e,
|
0x0a, 0x13, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73,
|
||||||
0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x0a, 0x13, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
|
||||||
0x65, 0x22, 0x30, 0x0a, 0x13, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74,
|
0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08,
|
||||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x75, 0x74,
|
0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07,
|
||||||
0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x72, 0x6f, 0x75, 0x74,
|
0x72, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x69, 0x73, 0x61, 0x62,
|
||||||
0x65, 0x49, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f,
|
0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||||
0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x0a, 0x17, 0x47,
|
0x2f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73,
|
||||||
0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52,
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64,
|
||||||
0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68,
|
0x22, 0x44, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||||
0x69, 0x6e, 0x65, 0x49, 0x64, 0x22, 0x47, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68,
|
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x72, 0x6f, 0x75,
|
||||||
0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x68, 0x65, 0x61, 0x64,
|
||||||
0x65, 0x12, 0x2b, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
|
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06,
|
||||||
0x0b, 0x32, 0x13, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31,
|
0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
|
||||||
0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x2f,
|
0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08,
|
||||||
0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71,
|
0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07,
|
||||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64,
|
0x72, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x22,
|
0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x29,
|
||||||
0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65,
|
0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x75, 0x61,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
0x6e, 0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f,
|
||||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x75, 0x61, 0x6e, 0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65,
|
0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76,
|
0x33,
|
||||||
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -652,20 +651,20 @@ var file_headscale_v1_routes_proto_goTypes = []interface{}{
|
||||||
(*EnableRouteResponse)(nil), // 4: headscale.v1.EnableRouteResponse
|
(*EnableRouteResponse)(nil), // 4: headscale.v1.EnableRouteResponse
|
||||||
(*DisableRouteRequest)(nil), // 5: headscale.v1.DisableRouteRequest
|
(*DisableRouteRequest)(nil), // 5: headscale.v1.DisableRouteRequest
|
||||||
(*DisableRouteResponse)(nil), // 6: headscale.v1.DisableRouteResponse
|
(*DisableRouteResponse)(nil), // 6: headscale.v1.DisableRouteResponse
|
||||||
(*GetMachineRoutesRequest)(nil), // 7: headscale.v1.GetMachineRoutesRequest
|
(*GetNodeRoutesRequest)(nil), // 7: headscale.v1.GetNodeRoutesRequest
|
||||||
(*GetMachineRoutesResponse)(nil), // 8: headscale.v1.GetMachineRoutesResponse
|
(*GetNodeRoutesResponse)(nil), // 8: headscale.v1.GetNodeRoutesResponse
|
||||||
(*DeleteRouteRequest)(nil), // 9: headscale.v1.DeleteRouteRequest
|
(*DeleteRouteRequest)(nil), // 9: headscale.v1.DeleteRouteRequest
|
||||||
(*DeleteRouteResponse)(nil), // 10: headscale.v1.DeleteRouteResponse
|
(*DeleteRouteResponse)(nil), // 10: headscale.v1.DeleteRouteResponse
|
||||||
(*Machine)(nil), // 11: headscale.v1.Machine
|
(*Node)(nil), // 11: headscale.v1.Node
|
||||||
(*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp
|
(*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp
|
||||||
}
|
}
|
||||||
var file_headscale_v1_routes_proto_depIdxs = []int32{
|
var file_headscale_v1_routes_proto_depIdxs = []int32{
|
||||||
11, // 0: headscale.v1.Route.machine:type_name -> headscale.v1.Machine
|
11, // 0: headscale.v1.Route.node:type_name -> headscale.v1.Node
|
||||||
12, // 1: headscale.v1.Route.created_at:type_name -> google.protobuf.Timestamp
|
12, // 1: headscale.v1.Route.created_at:type_name -> google.protobuf.Timestamp
|
||||||
12, // 2: headscale.v1.Route.updated_at:type_name -> google.protobuf.Timestamp
|
12, // 2: headscale.v1.Route.updated_at:type_name -> google.protobuf.Timestamp
|
||||||
12, // 3: headscale.v1.Route.deleted_at:type_name -> google.protobuf.Timestamp
|
12, // 3: headscale.v1.Route.deleted_at:type_name -> google.protobuf.Timestamp
|
||||||
0, // 4: headscale.v1.GetRoutesResponse.routes:type_name -> headscale.v1.Route
|
0, // 4: headscale.v1.GetRoutesResponse.routes:type_name -> headscale.v1.Route
|
||||||
0, // 5: headscale.v1.GetMachineRoutesResponse.routes:type_name -> headscale.v1.Route
|
0, // 5: headscale.v1.GetNodeRoutesResponse.routes:type_name -> headscale.v1.Route
|
||||||
6, // [6:6] is the sub-list for method output_type
|
6, // [6:6] is the sub-list for method output_type
|
||||||
6, // [6:6] is the sub-list for method input_type
|
6, // [6:6] is the sub-list for method input_type
|
||||||
6, // [6:6] is the sub-list for extension type_name
|
6, // [6:6] is the sub-list for extension type_name
|
||||||
|
@ -678,7 +677,7 @@ func file_headscale_v1_routes_proto_init() {
|
||||||
if File_headscale_v1_routes_proto != nil {
|
if File_headscale_v1_routes_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
file_headscale_v1_machine_proto_init()
|
file_headscale_v1_node_proto_init()
|
||||||
if !protoimpl.UnsafeEnabled {
|
if !protoimpl.UnsafeEnabled {
|
||||||
file_headscale_v1_routes_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
file_headscale_v1_routes_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Route); i {
|
switch v := v.(*Route); i {
|
||||||
|
@ -765,7 +764,7 @@ func file_headscale_v1_routes_proto_init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_headscale_v1_routes_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
file_headscale_v1_routes_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*GetMachineRoutesRequest); i {
|
switch v := v.(*GetNodeRoutesRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -777,7 +776,7 @@ func file_headscale_v1_routes_proto_init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_headscale_v1_routes_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
file_headscale_v1_routes_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*GetMachineRoutesResponse); i {
|
switch v := v.(*GetNodeRoutesResponse); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
case 1:
|
case 1:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.29.1
|
// protoc-gen-go v1.31.0
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: headscale/v1/user.proto
|
// source: headscale/v1/user.proto
|
||||||
|
|
||||||
|
|
|
@ -101,15 +101,15 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/debug/machine": {
|
"/api/v1/debug/node": {
|
||||||
"post": {
|
"post": {
|
||||||
"summary": "--- Machine start ---",
|
"summary": "--- Node start ---",
|
||||||
"operationId": "HeadscaleService_DebugCreateMachine",
|
"operationId": "HeadscaleService_DebugCreateNode",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/v1DebugCreateMachineResponse"
|
"$ref": "#/definitions/v1DebugCreateNodeResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -125,7 +125,7 @@
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/v1DebugCreateMachineRequest"
|
"$ref": "#/definitions/v1DebugCreateNodeRequest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -134,14 +134,14 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/machine": {
|
"/api/v1/node": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "HeadscaleService_ListMachines",
|
"operationId": "HeadscaleService_ListNodes",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/v1ListMachinesResponse"
|
"$ref": "#/definitions/v1ListNodesResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -164,14 +164,14 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/machine/register": {
|
"/api/v1/node/register": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "HeadscaleService_RegisterMachine",
|
"operationId": "HeadscaleService_RegisterNode",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/v1RegisterMachineResponse"
|
"$ref": "#/definitions/v1RegisterNodeResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -200,14 +200,14 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/machine/{machineId}": {
|
"/api/v1/node/{nodeId}": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "HeadscaleService_GetMachine",
|
"operationId": "HeadscaleService_GetNode",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/v1GetMachineResponse"
|
"$ref": "#/definitions/v1GetNodeResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -219,7 +219,7 @@
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "machineId",
|
"name": "nodeId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -231,12 +231,12 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"operationId": "HeadscaleService_DeleteMachine",
|
"operationId": "HeadscaleService_DeleteNode",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/v1DeleteMachineResponse"
|
"$ref": "#/definitions/v1DeleteNodeResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -248,7 +248,7 @@
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "machineId",
|
"name": "nodeId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -260,14 +260,14 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/machine/{machineId}/expire": {
|
"/api/v1/node/{nodeId}/expire": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "HeadscaleService_ExpireMachine",
|
"operationId": "HeadscaleService_ExpireNode",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/v1ExpireMachineResponse"
|
"$ref": "#/definitions/v1ExpireNodeResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -279,7 +279,7 @@
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "machineId",
|
"name": "nodeId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -291,14 +291,14 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/machine/{machineId}/rename/{newName}": {
|
"/api/v1/node/{nodeId}/rename/{newName}": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "HeadscaleService_RenameMachine",
|
"operationId": "HeadscaleService_RenameNode",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/v1RenameMachineResponse"
|
"$ref": "#/definitions/v1RenameNodeResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -310,7 +310,7 @@
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "machineId",
|
"name": "nodeId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -328,14 +328,14 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/machine/{machineId}/routes": {
|
"/api/v1/node/{nodeId}/routes": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "HeadscaleService_GetMachineRoutes",
|
"operationId": "HeadscaleService_GetNodeRoutes",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/v1GetMachineRoutesResponse"
|
"$ref": "#/definitions/v1GetNodeRoutesResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -347,7 +347,7 @@
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "machineId",
|
"name": "nodeId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -359,7 +359,7 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/machine/{machineId}/tags": {
|
"/api/v1/node/{nodeId}/tags": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "HeadscaleService_SetTags",
|
"operationId": "HeadscaleService_SetTags",
|
||||||
"responses": {
|
"responses": {
|
||||||
|
@ -378,7 +378,7 @@
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "machineId",
|
"name": "nodeId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -406,14 +406,14 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/machine/{machineId}/user": {
|
"/api/v1/node/{nodeId}/user": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "HeadscaleService_MoveMachine",
|
"operationId": "HeadscaleService_MoveNode",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/v1MoveMachineResponse"
|
"$ref": "#/definitions/v1MoveNodeResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -425,7 +425,7 @@
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "machineId",
|
"name": "nodeId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -917,7 +917,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"v1DebugCreateMachineRequest": {
|
"v1DebugCreateNodeRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"user": {
|
"user": {
|
||||||
|
@ -937,15 +937,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"v1DebugCreateMachineResponse": {
|
"v1DebugCreateNodeResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"machine": {
|
"node": {
|
||||||
"$ref": "#/definitions/v1Machine"
|
"$ref": "#/definitions/v1Node"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"v1DeleteMachineResponse": {
|
"v1DeleteNodeResponse": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"v1DeleteRouteResponse": {
|
"v1DeleteRouteResponse": {
|
||||||
|
@ -971,11 +971,11 @@
|
||||||
"v1ExpireApiKeyResponse": {
|
"v1ExpireApiKeyResponse": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"v1ExpireMachineResponse": {
|
"v1ExpireNodeResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"machine": {
|
"node": {
|
||||||
"$ref": "#/definitions/v1Machine"
|
"$ref": "#/definitions/v1Node"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -993,15 +993,15 @@
|
||||||
"v1ExpirePreAuthKeyResponse": {
|
"v1ExpirePreAuthKeyResponse": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"v1GetMachineResponse": {
|
"v1GetNodeResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"machine": {
|
"node": {
|
||||||
"$ref": "#/definitions/v1Machine"
|
"$ref": "#/definitions/v1Node"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"v1GetMachineRoutesResponse": {
|
"v1GetNodeRoutesResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"routes": {
|
"routes": {
|
||||||
|
@ -1042,13 +1042,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"v1ListMachinesResponse": {
|
"v1ListNodesResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"machines": {
|
"nodes": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/v1Machine"
|
"$ref": "#/definitions/v1Node"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1075,7 +1075,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"v1Machine": {
|
"v1MoveNodeResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"node": {
|
||||||
|
"$ref": "#/definitions/v1Node"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1Node": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
|
@ -1151,14 +1159,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"v1MoveMachineResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"machine": {
|
|
||||||
"$ref": "#/definitions/v1Machine"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"v1PreAuthKey": {
|
"v1PreAuthKey": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -1196,14 +1196,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"v1RegisterMachineResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"machine": {
|
|
||||||
"$ref": "#/definitions/v1Machine"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"v1RegisterMethod": {
|
"v1RegisterMethod": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
@ -1214,11 +1206,19 @@
|
||||||
],
|
],
|
||||||
"default": "REGISTER_METHOD_UNSPECIFIED"
|
"default": "REGISTER_METHOD_UNSPECIFIED"
|
||||||
},
|
},
|
||||||
"v1RenameMachineResponse": {
|
"v1RegisterNodeResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"machine": {
|
"node": {
|
||||||
"$ref": "#/definitions/v1Machine"
|
"$ref": "#/definitions/v1Node"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1RenameNodeResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"node": {
|
||||||
|
"$ref": "#/definitions/v1Node"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1237,8 +1237,8 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uint64"
|
"format": "uint64"
|
||||||
},
|
},
|
||||||
"machine": {
|
"node": {
|
||||||
"$ref": "#/definitions/v1Machine"
|
"$ref": "#/definitions/v1Node"
|
||||||
},
|
},
|
||||||
"prefix": {
|
"prefix": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -1269,8 +1269,8 @@
|
||||||
"v1SetTagsResponse": {
|
"v1SetTagsResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"machine": {
|
"node": {
|
||||||
"$ref": "#/definitions/v1Machine"
|
"$ref": "#/definitions/v1Node"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"swagger": "2.0",
|
"swagger": "2.0",
|
||||||
"info": {
|
"info": {
|
||||||
"title": "headscale/v1/machine.proto",
|
"title": "headscale/v1/node.proto",
|
||||||
"version": "version not set"
|
"version": "version not set"
|
||||||
},
|
},
|
||||||
"consumes": [
|
"consumes": [
|
|
@ -220,16 +220,16 @@ func (h *Headscale) redirect(w http.ResponseWriter, req *http.Request) {
|
||||||
http.Redirect(w, req, target, http.StatusFound)
|
http.Redirect(w, req, target, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// expireEphemeralNodes deletes ephemeral machine records that have not been
|
// expireEphemeralNodes deletes ephemeral node records that have not been
|
||||||
// seen for longer than h.cfg.EphemeralNodeInactivityTimeout.
|
// seen for longer than h.cfg.EphemeralNodeInactivityTimeout.
|
||||||
func (h *Headscale) expireEphemeralNodes(milliSeconds int64) {
|
func (h *Headscale) expireEphemeralNodes(milliSeconds int64) {
|
||||||
ticker := time.NewTicker(time.Duration(milliSeconds) * time.Millisecond)
|
ticker := time.NewTicker(time.Duration(milliSeconds) * time.Millisecond)
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
h.db.ExpireEphemeralMachines(h.cfg.EphemeralNodeInactivityTimeout)
|
h.db.ExpireEphemeralNodes(h.cfg.EphemeralNodeInactivityTimeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// expireExpiredMachines expires machines that have an explicit expiry set
|
// expireExpiredMachines expires nodes that have an explicit expiry set
|
||||||
// after that expiry time has passed.
|
// after that expiry time has passed.
|
||||||
func (h *Headscale) expireExpiredMachines(intervalMs int64) {
|
func (h *Headscale) expireExpiredMachines(intervalMs int64) {
|
||||||
interval := time.Duration(intervalMs) * time.Millisecond
|
interval := time.Duration(intervalMs) * time.Millisecond
|
||||||
|
@ -238,7 +238,7 @@ func (h *Headscale) expireExpiredMachines(intervalMs int64) {
|
||||||
lastCheck := time.Unix(0, 0)
|
lastCheck := time.Unix(0, 0)
|
||||||
|
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
lastCheck = h.db.ExpireExpiredMachines(lastCheck)
|
lastCheck = h.db.ExpireExpiredNodes(lastCheck)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,9 @@ func (h *Headscale) handleRegister(
|
||||||
isNoise bool,
|
isNoise bool,
|
||||||
) {
|
) {
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
machine, err := h.db.GetMachineByAnyKey(machineKey, registerRequest.NodeKey, registerRequest.OldNodeKey)
|
node, err := h.db.GetNodeByAnyKey(machineKey, registerRequest.NodeKey, registerRequest.OldNodeKey)
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
// If the machine has AuthKey set, handle registration via PreAuthKeys
|
// If the node has AuthKey set, handle registration via PreAuthKeys
|
||||||
if registerRequest.Auth.AuthKey != "" {
|
if registerRequest.Auth.AuthKey != "" {
|
||||||
h.handleAuthKey(writer, registerRequest, machineKey, isNoise)
|
h.handleAuthKey(writer, registerRequest, machineKey, isNoise)
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ func (h *Headscale) handleRegister(
|
||||||
//
|
//
|
||||||
// TODO(juan): We could use this field to improve our protocol implementation,
|
// TODO(juan): We could use this field to improve our protocol implementation,
|
||||||
// and hold the request until the client closes it, or the interactive
|
// and hold the request until the client closes it, or the interactive
|
||||||
// login is completed (i.e., the user registers the machine).
|
// login is completed (i.e., the user registers the node).
|
||||||
// This is not implemented yet, as it is no strictly required. The only side-effect
|
// This is not implemented yet, as it is no strictly required. The only side-effect
|
||||||
// is that the client will hammer headscale with requests until it gets a
|
// is that the client will hammer headscale with requests until it gets a
|
||||||
// successful RegisterResponse.
|
// successful RegisterResponse.
|
||||||
|
@ -48,19 +48,19 @@ func (h *Headscale) handleRegister(
|
||||||
if _, ok := h.registrationCache.Get(util.NodePublicKeyStripPrefix(registerRequest.NodeKey)); ok {
|
if _, ok := h.registrationCache.Get(util.NodePublicKeyStripPrefix(registerRequest.NodeKey)); ok {
|
||||||
log.Debug().
|
log.Debug().
|
||||||
Caller().
|
Caller().
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Str("machine_key", machineKey.ShortString()).
|
Str("machine_key", machineKey.ShortString()).
|
||||||
Str("node_key", registerRequest.NodeKey.ShortString()).
|
Str("node_key", registerRequest.NodeKey.ShortString()).
|
||||||
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
|
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
|
||||||
Str("follow_up", registerRequest.Followup).
|
Str("follow_up", registerRequest.Followup).
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Msg("Machine is waiting for interactive login")
|
Msg("Node is waiting for interactive login")
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-req.Context().Done():
|
case <-req.Context().Done():
|
||||||
return
|
return
|
||||||
case <-time.After(registrationHoldoff):
|
case <-time.After(registrationHoldoff):
|
||||||
h.handleNewMachine(writer, registerRequest, machineKey, isNoise)
|
h.handleNewNode(writer, registerRequest, machineKey, isNoise)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -69,13 +69,13 @@ func (h *Headscale) handleRegister(
|
||||||
|
|
||||||
log.Info().
|
log.Info().
|
||||||
Caller().
|
Caller().
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Str("machine_key", machineKey.ShortString()).
|
Str("machine_key", machineKey.ShortString()).
|
||||||
Str("node_key", registerRequest.NodeKey.ShortString()).
|
Str("node_key", registerRequest.NodeKey.ShortString()).
|
||||||
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
|
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
|
||||||
Str("follow_up", registerRequest.Followup).
|
Str("follow_up", registerRequest.Followup).
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Msg("New machine not yet in the database")
|
Msg("New node not yet in the database")
|
||||||
|
|
||||||
givenName, err := h.db.GenerateGivenName(
|
givenName, err := h.db.GenerateGivenName(
|
||||||
machineKey.String(),
|
machineKey.String(),
|
||||||
|
@ -92,11 +92,11 @@ func (h *Headscale) handleRegister(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// The machine did not have a key to authenticate, which means
|
// The node did not have a key to authenticate, which means
|
||||||
// that we rely on a method that calls back some how (OpenID or CLI)
|
// that we rely on a method that calls back some how (OpenID or CLI)
|
||||||
// We create the machine and then keep it around until a callback
|
// We create the node and then keep it around until a callback
|
||||||
// happens
|
// happens
|
||||||
newMachine := types.Machine{
|
newNode := types.Node{
|
||||||
MachineKey: util.MachinePublicKeyStripPrefix(machineKey),
|
MachineKey: util.MachinePublicKeyStripPrefix(machineKey),
|
||||||
Hostname: registerRequest.Hostinfo.Hostname,
|
Hostname: registerRequest.Hostinfo.Hostname,
|
||||||
GivenName: givenName,
|
GivenName: givenName,
|
||||||
|
@ -109,41 +109,41 @@ func (h *Headscale) handleRegister(
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Time("expiry", registerRequest.Expiry).
|
Time("expiry", registerRequest.Expiry).
|
||||||
Msg("Non-zero expiry time requested")
|
Msg("Non-zero expiry time requested")
|
||||||
newMachine.Expiry = ®isterRequest.Expiry
|
newNode.Expiry = ®isterRequest.Expiry
|
||||||
}
|
}
|
||||||
|
|
||||||
h.registrationCache.Set(
|
h.registrationCache.Set(
|
||||||
newMachine.NodeKey,
|
newNode.NodeKey,
|
||||||
newMachine,
|
newNode,
|
||||||
registerCacheExpiration,
|
registerCacheExpiration,
|
||||||
)
|
)
|
||||||
|
|
||||||
h.handleNewMachine(writer, registerRequest, machineKey, isNoise)
|
h.handleNewNode(writer, registerRequest, machineKey, isNoise)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// The machine is already in the DB. This could mean one of the following:
|
// The node is already in the DB. This could mean one of the following:
|
||||||
// - The machine is authenticated and ready to /map
|
// - The node is authenticated and ready to /map
|
||||||
// - We are doing a key refresh
|
// - We are doing a key refresh
|
||||||
// - The machine is logged out (or expired) and pending to be authorized. TODO(juan): We need to keep alive the connection here
|
// - The node is logged out (or expired) and pending to be authorized. TODO(juan): We need to keep alive the connection here
|
||||||
if machine != nil {
|
if node != nil {
|
||||||
// (juan): For a while we had a bug where we were not storing the MachineKey for the nodes using the TS2021,
|
// (juan): For a while we had a bug where we were not storing the MachineKey for the nodes using the TS2021,
|
||||||
// due to a misunderstanding of the protocol https://github.com/juanfont/headscale/issues/1054
|
// due to a misunderstanding of the protocol https://github.com/juanfont/headscale/issues/1054
|
||||||
// So if we have a not valid MachineKey (but we were able to fetch the machine with the NodeKeys), we update it.
|
// So if we have a not valid MachineKey (but we were able to fetch the node with the NodeKeys), we update it.
|
||||||
var storedMachineKey key.MachinePublic
|
var storedMachineKey key.MachinePublic
|
||||||
err = storedMachineKey.UnmarshalText(
|
err = storedMachineKey.UnmarshalText(
|
||||||
[]byte(util.MachinePublicKeyEnsurePrefix(machine.MachineKey)),
|
[]byte(util.MachinePublicKeyEnsurePrefix(node.MachineKey)),
|
||||||
)
|
)
|
||||||
if err != nil || storedMachineKey.IsZero() {
|
if err != nil || storedMachineKey.IsZero() {
|
||||||
if err := h.db.MachineSetMachineKey(machine, machineKey); err != nil {
|
if err := h.db.NodeSetMachineKey(node, machineKey); err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Str("func", "RegistrationHandler").
|
Str("func", "RegistrationHandler").
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Error saving machine key to database")
|
Msg("Error saving machine key to database")
|
||||||
|
|
||||||
|
@ -154,34 +154,34 @@ func (h *Headscale) handleRegister(
|
||||||
// If the NodeKey stored in headscale is the same as the key presented in a registration
|
// If the NodeKey stored in headscale is the same as the key presented in a registration
|
||||||
// request, then we have a node that is either:
|
// request, then we have a node that is either:
|
||||||
// - Trying to log out (sending a expiry in the past)
|
// - Trying to log out (sending a expiry in the past)
|
||||||
// - A valid, registered machine, looking for /map
|
// - A valid, registered node, looking for /map
|
||||||
// - Expired machine wanting to reauthenticate
|
// - Expired node wanting to reauthenticate
|
||||||
if machine.NodeKey == util.NodePublicKeyStripPrefix(registerRequest.NodeKey) {
|
if node.NodeKey == util.NodePublicKeyStripPrefix(registerRequest.NodeKey) {
|
||||||
// The client sends an Expiry in the past if the client is requesting to expire the key (aka logout)
|
// The client sends an Expiry in the past if the client is requesting to expire the key (aka logout)
|
||||||
// https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L648
|
// https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L648
|
||||||
if !registerRequest.Expiry.IsZero() &&
|
if !registerRequest.Expiry.IsZero() &&
|
||||||
registerRequest.Expiry.UTC().Before(now) {
|
registerRequest.Expiry.UTC().Before(now) {
|
||||||
h.handleMachineLogOut(writer, *machine, machineKey, isNoise)
|
h.handleNodeLogOut(writer, *node, machineKey, isNoise)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If machine is not expired, and it is register, we have a already accepted this machine,
|
// If node is not expired, and it is register, we have a already accepted this node,
|
||||||
// let it proceed with a valid registration
|
// let it proceed with a valid registration
|
||||||
if !machine.IsExpired() {
|
if !node.IsExpired() {
|
||||||
h.handleMachineWithValidRegistration(writer, *machine, machineKey, isNoise)
|
h.handleNodeWithValidRegistration(writer, *node, machineKey, isNoise)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The NodeKey we have matches OldNodeKey, which means this is a refresh after a key expiration
|
// The NodeKey we have matches OldNodeKey, which means this is a refresh after a key expiration
|
||||||
if machine.NodeKey == util.NodePublicKeyStripPrefix(registerRequest.OldNodeKey) &&
|
if node.NodeKey == util.NodePublicKeyStripPrefix(registerRequest.OldNodeKey) &&
|
||||||
!machine.IsExpired() {
|
!node.IsExpired() {
|
||||||
h.handleMachineKeyRefresh(
|
h.handleNodeKeyRefresh(
|
||||||
writer,
|
writer,
|
||||||
registerRequest,
|
registerRequest,
|
||||||
*machine,
|
*node,
|
||||||
machineKey,
|
machineKey,
|
||||||
isNoise,
|
isNoise,
|
||||||
)
|
)
|
||||||
|
@ -197,20 +197,20 @@ func (h *Headscale) handleRegister(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The machine has expired or it is logged out
|
// The node has expired or it is logged out
|
||||||
h.handleMachineExpiredOrLoggedOut(writer, registerRequest, *machine, machineKey, isNoise)
|
h.handleNodeExpiredOrLoggedOut(writer, registerRequest, *node, machineKey, isNoise)
|
||||||
|
|
||||||
// TODO(juan): RegisterRequest includes an Expiry time, that we could optionally use
|
// TODO(juan): RegisterRequest includes an Expiry time, that we could optionally use
|
||||||
machine.Expiry = &time.Time{}
|
node.Expiry = &time.Time{}
|
||||||
|
|
||||||
// If we are here it means the client needs to be reauthorized,
|
// If we are here it means the client needs to be reauthorized,
|
||||||
// we need to make sure the NodeKey matches the one in the request
|
// we need to make sure the NodeKey matches the one in the request
|
||||||
// TODO(juan): What happens when using fast user switching between two
|
// TODO(juan): What happens when using fast user switching between two
|
||||||
// headscale-managed tailnets?
|
// headscale-managed tailnets?
|
||||||
machine.NodeKey = util.NodePublicKeyStripPrefix(registerRequest.NodeKey)
|
node.NodeKey = util.NodePublicKeyStripPrefix(registerRequest.NodeKey)
|
||||||
h.registrationCache.Set(
|
h.registrationCache.Set(
|
||||||
util.NodePublicKeyStripPrefix(registerRequest.NodeKey),
|
util.NodePublicKeyStripPrefix(registerRequest.NodeKey),
|
||||||
*machine,
|
*node,
|
||||||
registerCacheExpiration,
|
registerCacheExpiration,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ func (h *Headscale) handleAuthKey(
|
||||||
) {
|
) {
|
||||||
log.Debug().
|
log.Debug().
|
||||||
Caller().
|
Caller().
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Msgf("Processing auth key for %s", registerRequest.Hostinfo.Hostname)
|
Msgf("Processing auth key for %s", registerRequest.Hostinfo.Hostname)
|
||||||
resp := tailcfg.RegisterResponse{}
|
resp := tailcfg.RegisterResponse{}
|
||||||
|
@ -241,7 +241,7 @@ func (h *Headscale) handleAuthKey(
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Failed authentication via AuthKey")
|
Msg("Failed authentication via AuthKey")
|
||||||
resp.MachineAuthorized = false
|
resp.MachineAuthorized = false
|
||||||
|
@ -251,11 +251,11 @@ func (h *Headscale) handleAuthKey(
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Cannot encode message")
|
Msg("Cannot encode message")
|
||||||
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
||||||
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
|
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
|
||||||
Inc()
|
Inc()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -275,14 +275,14 @@ func (h *Headscale) handleAuthKey(
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Msg("Failed authentication via AuthKey")
|
Msg("Failed authentication via AuthKey")
|
||||||
|
|
||||||
if pak != nil {
|
if pak != nil {
|
||||||
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
|
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
|
||||||
Inc()
|
Inc()
|
||||||
} else {
|
} else {
|
||||||
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", "unknown").Inc()
|
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", "unknown").Inc()
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -291,33 +291,33 @@ func (h *Headscale) handleAuthKey(
|
||||||
log.Debug().
|
log.Debug().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Msg("Authentication key was valid, proceeding to acquire IP addresses")
|
Msg("Authentication key was valid, proceeding to acquire IP addresses")
|
||||||
|
|
||||||
nodeKey := util.NodePublicKeyStripPrefix(registerRequest.NodeKey)
|
nodeKey := util.NodePublicKeyStripPrefix(registerRequest.NodeKey)
|
||||||
|
|
||||||
// retrieve machine information if it exist
|
// retrieve node information if it exist
|
||||||
// The error is not important, because if it does not
|
// The error is not important, because if it does not
|
||||||
// exist, then this is a new machine and we will move
|
// exist, then this is a new node and we will move
|
||||||
// on to registration.
|
// on to registration.
|
||||||
machine, _ := h.db.GetMachineByAnyKey(machineKey, registerRequest.NodeKey, registerRequest.OldNodeKey)
|
node, _ := h.db.GetNodeByAnyKey(machineKey, registerRequest.NodeKey, registerRequest.OldNodeKey)
|
||||||
if machine != nil {
|
if node != nil {
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("machine was already registered before, refreshing with new auth key")
|
Msg("node was already registered before, refreshing with new auth key")
|
||||||
|
|
||||||
machine.NodeKey = nodeKey
|
node.NodeKey = nodeKey
|
||||||
machine.AuthKeyID = uint(pak.ID)
|
node.AuthKeyID = uint(pak.ID)
|
||||||
err := h.db.MachineSetExpiry(machine, registerRequest.Expiry)
|
err := h.db.NodeSetExpiry(node, registerRequest.Expiry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Failed to refresh machine")
|
Msg("Failed to refresh node")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -325,16 +325,16 @@ func (h *Headscale) handleAuthKey(
|
||||||
aclTags := pak.Proto().AclTags
|
aclTags := pak.Proto().AclTags
|
||||||
if len(aclTags) > 0 {
|
if len(aclTags) > 0 {
|
||||||
// This conditional preserves the existing behaviour, although SaaS would reset the tags on auth-key login
|
// This conditional preserves the existing behaviour, although SaaS would reset the tags on auth-key login
|
||||||
err = h.db.SetTags(machine, aclTags)
|
err = h.db.SetTags(node, aclTags)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Strs("aclTags", aclTags).
|
Strs("aclTags", aclTags).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Failed to set tags after refreshing machine")
|
Msg("Failed to set tags after refreshing node")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ func (h *Headscale) handleAuthKey(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
machineToRegister := types.Machine{
|
nodeToRegister := types.Node{
|
||||||
Hostname: registerRequest.Hostinfo.Hostname,
|
Hostname: registerRequest.Hostinfo.Hostname,
|
||||||
GivenName: givenName,
|
GivenName: givenName,
|
||||||
UserID: pak.User.ID,
|
UserID: pak.User.ID,
|
||||||
|
@ -368,16 +368,16 @@ func (h *Headscale) handleAuthKey(
|
||||||
ForcedTags: pak.Proto().AclTags,
|
ForcedTags: pak.Proto().AclTags,
|
||||||
}
|
}
|
||||||
|
|
||||||
machine, err = h.db.RegisterMachine(
|
node, err = h.db.RegisterNode(
|
||||||
machineToRegister,
|
nodeToRegister,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("could not register machine")
|
Msg("could not register node")
|
||||||
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
|
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
|
||||||
Inc()
|
Inc()
|
||||||
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ func (h *Headscale) handleAuthKey(
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Failed to use pre-auth key")
|
Msg("Failed to use pre-auth key")
|
||||||
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
|
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
|
||||||
Inc()
|
Inc()
|
||||||
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
||||||
|
|
||||||
|
@ -410,16 +410,16 @@ func (h *Headscale) handleAuthKey(
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Cannot encode message")
|
Msg("Cannot encode message")
|
||||||
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
|
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
|
||||||
Inc()
|
Inc()
|
||||||
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "success", pak.User.Name).
|
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "success", pak.User.Name).
|
||||||
Inc()
|
Inc()
|
||||||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
|
@ -434,14 +434,14 @@ func (h *Headscale) handleAuthKey(
|
||||||
|
|
||||||
log.Info().
|
log.Info().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Str("ips", strings.Join(machine.IPAddresses.StringSlice(), ", ")).
|
Str("ips", strings.Join(node.IPAddresses.StringSlice(), ", ")).
|
||||||
Msg("Successfully authenticated via AuthKey")
|
Msg("Successfully authenticated via AuthKey")
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleNewMachine exposes for both legacy and Noise the functionality to get a URL
|
// handleNewNode exposes for both legacy and Noise the functionality to get a URL
|
||||||
// for authorizing the machine. This url is then showed to the user by the local Tailscale client.
|
// for authorizing the node. This url is then showed to the user by the local Tailscale client.
|
||||||
func (h *Headscale) handleNewMachine(
|
func (h *Headscale) handleNewNode(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
registerRequest tailcfg.RegisterRequest,
|
registerRequest tailcfg.RegisterRequest,
|
||||||
machineKey key.MachinePublic,
|
machineKey key.MachinePublic,
|
||||||
|
@ -449,11 +449,11 @@ func (h *Headscale) handleNewMachine(
|
||||||
) {
|
) {
|
||||||
resp := tailcfg.RegisterResponse{}
|
resp := tailcfg.RegisterResponse{}
|
||||||
|
|
||||||
// The machine registration is new, redirect the client to the registration URL
|
// The node registration is new, redirect the client to the registration URL
|
||||||
log.Debug().
|
log.Debug().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Msg("The node seems to be new, sending auth url")
|
Msg("The node seems to be new, sending auth url")
|
||||||
|
|
||||||
if h.oauth2Config != nil {
|
if h.oauth2Config != nil {
|
||||||
|
@ -495,13 +495,13 @@ func (h *Headscale) handleNewMachine(
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("AuthURL", resp.AuthURL).
|
Str("AuthURL", resp.AuthURL).
|
||||||
Str("machine", registerRequest.Hostinfo.Hostname).
|
Str("node", registerRequest.Hostinfo.Hostname).
|
||||||
Msg("Successfully sent auth url")
|
Msg("Successfully sent auth url")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headscale) handleMachineLogOut(
|
func (h *Headscale) handleNodeLogOut(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
machine types.Machine,
|
node types.Node,
|
||||||
machineKey key.MachinePublic,
|
machineKey key.MachinePublic,
|
||||||
isNoise bool,
|
isNoise bool,
|
||||||
) {
|
) {
|
||||||
|
@ -509,17 +509,17 @@ func (h *Headscale) handleMachineLogOut(
|
||||||
|
|
||||||
log.Info().
|
log.Info().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("Client requested logout")
|
Msg("Client requested logout")
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
err := h.db.MachineSetExpiry(&machine, now)
|
err := h.db.NodeSetExpiry(&node, now)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Failed to expire machine")
|
Msg("Failed to expire node")
|
||||||
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -528,7 +528,7 @@ func (h *Headscale) handleMachineLogOut(
|
||||||
resp.AuthURL = ""
|
resp.AuthURL = ""
|
||||||
resp.MachineAuthorized = false
|
resp.MachineAuthorized = false
|
||||||
resp.NodeKeyExpired = true
|
resp.NodeKeyExpired = true
|
||||||
resp.User = *machine.User.TailscaleUser()
|
resp.User = *node.User.TailscaleUser()
|
||||||
respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey)
|
respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
|
@ -554,13 +554,13 @@ func (h *Headscale) handleMachineLogOut(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if machine.IsEphemeral() {
|
if node.IsEphemeral() {
|
||||||
err = h.db.DeleteMachine(&machine)
|
err = h.db.DeleteNode(&node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("Cannot delete ephemeral machine from the database")
|
Msg("Cannot delete ephemeral node from the database")
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -569,29 +569,29 @@ func (h *Headscale) handleMachineLogOut(
|
||||||
log.Info().
|
log.Info().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("Successfully logged out")
|
Msg("Successfully logged out")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headscale) handleMachineWithValidRegistration(
|
func (h *Headscale) handleNodeWithValidRegistration(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
machine types.Machine,
|
node types.Node,
|
||||||
machineKey key.MachinePublic,
|
machineKey key.MachinePublic,
|
||||||
isNoise bool,
|
isNoise bool,
|
||||||
) {
|
) {
|
||||||
resp := tailcfg.RegisterResponse{}
|
resp := tailcfg.RegisterResponse{}
|
||||||
|
|
||||||
// The machine registration is valid, respond with redirect to /map
|
// The node registration is valid, respond with redirect to /map
|
||||||
log.Debug().
|
log.Debug().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("Client is registered and we have the current NodeKey. All clear to /map")
|
Msg("Client is registered and we have the current NodeKey. All clear to /map")
|
||||||
|
|
||||||
resp.AuthURL = ""
|
resp.AuthURL = ""
|
||||||
resp.MachineAuthorized = true
|
resp.MachineAuthorized = true
|
||||||
resp.User = *machine.User.TailscaleUser()
|
resp.User = *node.User.TailscaleUser()
|
||||||
resp.Login = *machine.User.TailscaleLogin()
|
resp.Login = *node.User.TailscaleLogin()
|
||||||
|
|
||||||
respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey)
|
respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -600,13 +600,13 @@ func (h *Headscale) handleMachineWithValidRegistration(
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Cannot encode message")
|
Msg("Cannot encode message")
|
||||||
machineRegistrations.WithLabelValues("update", "web", "error", machine.User.Name).
|
nodeRegistrations.WithLabelValues("update", "web", "error", node.User.Name).
|
||||||
Inc()
|
Inc()
|
||||||
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
machineRegistrations.WithLabelValues("update", "web", "success", machine.User.Name).
|
nodeRegistrations.WithLabelValues("update", "web", "success", node.User.Name).
|
||||||
Inc()
|
Inc()
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
@ -623,14 +623,14 @@ func (h *Headscale) handleMachineWithValidRegistration(
|
||||||
log.Info().
|
log.Info().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("Machine successfully authorized")
|
Msg("Node successfully authorized")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headscale) handleMachineKeyRefresh(
|
func (h *Headscale) handleNodeKeyRefresh(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
registerRequest tailcfg.RegisterRequest,
|
registerRequest tailcfg.RegisterRequest,
|
||||||
machine types.Machine,
|
node types.Node,
|
||||||
machineKey key.MachinePublic,
|
machineKey key.MachinePublic,
|
||||||
isNoise bool,
|
isNoise bool,
|
||||||
) {
|
) {
|
||||||
|
@ -639,10 +639,10 @@ func (h *Headscale) handleMachineKeyRefresh(
|
||||||
log.Info().
|
log.Info().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("We have the OldNodeKey in the database. This is a key refresh")
|
Msg("We have the OldNodeKey in the database. This is a key refresh")
|
||||||
|
|
||||||
err := h.db.MachineSetNodeKey(&machine, registerRequest.NodeKey)
|
err := h.db.NodeSetNodeKey(&node, registerRequest.NodeKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
|
@ -654,7 +654,7 @@ func (h *Headscale) handleMachineKeyRefresh(
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.AuthURL = ""
|
resp.AuthURL = ""
|
||||||
resp.User = *machine.User.TailscaleUser()
|
resp.User = *node.User.TailscaleUser()
|
||||||
respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey)
|
respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
|
@ -683,14 +683,14 @@ func (h *Headscale) handleMachineKeyRefresh(
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("node_key", registerRequest.NodeKey.ShortString()).
|
Str("node_key", registerRequest.NodeKey.ShortString()).
|
||||||
Str("old_node_key", registerRequest.OldNodeKey.ShortString()).
|
Str("old_node_key", registerRequest.OldNodeKey.ShortString()).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("Node key successfully refreshed")
|
Msg("Node key successfully refreshed")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headscale) handleMachineExpiredOrLoggedOut(
|
func (h *Headscale) handleNodeExpiredOrLoggedOut(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
registerRequest tailcfg.RegisterRequest,
|
registerRequest tailcfg.RegisterRequest,
|
||||||
machine types.Machine,
|
node types.Node,
|
||||||
machineKey key.MachinePublic,
|
machineKey key.MachinePublic,
|
||||||
isNoise bool,
|
isNoise bool,
|
||||||
) {
|
) {
|
||||||
|
@ -706,11 +706,11 @@ func (h *Headscale) handleMachineExpiredOrLoggedOut(
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Str("machine_key", machineKey.ShortString()).
|
Str("machine_key", machineKey.ShortString()).
|
||||||
Str("node_key", registerRequest.NodeKey.ShortString()).
|
Str("node_key", registerRequest.NodeKey.ShortString()).
|
||||||
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
|
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
|
||||||
Msg("Machine registration has expired or logged out. Sending a auth url to register")
|
Msg("Node registration has expired or logged out. Sending a auth url to register")
|
||||||
|
|
||||||
if h.oauth2Config != nil {
|
if h.oauth2Config != nil {
|
||||||
resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s",
|
resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s",
|
||||||
|
@ -729,13 +729,13 @@ func (h *Headscale) handleMachineExpiredOrLoggedOut(
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Cannot encode message")
|
Msg("Cannot encode message")
|
||||||
machineRegistrations.WithLabelValues("reauth", "web", "error", machine.User.Name).
|
nodeRegistrations.WithLabelValues("reauth", "web", "error", node.User.Name).
|
||||||
Inc()
|
Inc()
|
||||||
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
machineRegistrations.WithLabelValues("reauth", "web", "success", machine.User.Name).
|
nodeRegistrations.WithLabelValues("reauth", "web", "success", node.User.Name).
|
||||||
Inc()
|
Inc()
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
@ -755,6 +755,6 @@ func (h *Headscale) handleMachineExpiredOrLoggedOut(
|
||||||
Str("machine_key", machineKey.ShortString()).
|
Str("machine_key", machineKey.ShortString()).
|
||||||
Str("node_key", registerRequest.NodeKey.ShortString()).
|
Str("node_key", registerRequest.NodeKey.ShortString()).
|
||||||
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
|
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("Machine logged out. Sent AuthURL for reauthentication")
|
Msg("Node logged out. Sent AuthURL for reauthentication")
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ func (h *Headscale) RegistrationHandler(
|
||||||
Caller().
|
Caller().
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Cannot parse machine key")
|
Msg("Cannot parse machine key")
|
||||||
machineRegistrations.WithLabelValues("unknown", "web", "error", "unknown").Inc()
|
nodeRegistrations.WithLabelValues("unknown", "web", "error", "unknown").Inc()
|
||||||
http.Error(writer, "Cannot parse machine key", http.StatusBadRequest)
|
http.Error(writer, "Cannot parse machine key", http.StatusBadRequest)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -51,7 +51,7 @@ func (h *Headscale) RegistrationHandler(
|
||||||
Caller().
|
Caller().
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Cannot decode message")
|
Msg("Cannot decode message")
|
||||||
machineRegistrations.WithLabelValues("unknown", "web", "error", "unknown").Inc()
|
nodeRegistrations.WithLabelValues("unknown", "web", "error", "unknown").Inc()
|
||||||
http.Error(writer, "Cannot decode message", http.StatusBadRequest)
|
http.Error(writer, "Cannot decode message", http.StatusBadRequest)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// // NoiseRegistrationHandler handles the actual registration process of a machine.
|
// // NoiseRegistrationHandler handles the actual registration process of a node.
|
||||||
func (ns *noiseServer) NoiseRegistrationHandler(
|
func (ns *noiseServer) NoiseRegistrationHandler(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
|
@ -33,7 +33,7 @@ func (ns *noiseServer) NoiseRegistrationHandler(
|
||||||
Caller().
|
Caller().
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Cannot parse RegisterRequest")
|
Msg("Cannot parse RegisterRequest")
|
||||||
machineRegistrations.WithLabelValues("unknown", "web", "error", "unknown").Inc()
|
nodeRegistrations.WithLabelValues("unknown", "web", "error", "unknown").Inc()
|
||||||
http.Error(writer, "Internal error", http.StatusInternalServerError)
|
http.Error(writer, "Internal error", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -17,8 +17,8 @@ import (
|
||||||
|
|
||||||
var ErrCouldNotAllocateIP = errors.New("could not find any suitable IP")
|
var ErrCouldNotAllocateIP = errors.New("could not find any suitable IP")
|
||||||
|
|
||||||
func (hsdb *HSDatabase) getAvailableIPs() (types.MachineAddresses, error) {
|
func (hsdb *HSDatabase) getAvailableIPs() (types.NodeAddresses, error) {
|
||||||
var ips types.MachineAddresses
|
var ips types.NodeAddresses
|
||||||
var err error
|
var err error
|
||||||
for _, ipPrefix := range hsdb.ipPrefixes {
|
for _, ipPrefix := range hsdb.ipPrefixes {
|
||||||
var ip *netip.Addr
|
var ip *netip.Addr
|
||||||
|
@ -69,11 +69,11 @@ func (hsdb *HSDatabase) getUsedIPs() (*netipx.IPSet, error) {
|
||||||
// but this was quick to get running and it should be enough
|
// but this was quick to get running and it should be enough
|
||||||
// to begin experimenting with a dual stack tailnet.
|
// to begin experimenting with a dual stack tailnet.
|
||||||
var addressesSlices []string
|
var addressesSlices []string
|
||||||
hsdb.db.Model(&types.Machine{}).Pluck("ip_addresses", &addressesSlices)
|
hsdb.db.Model(&types.Node{}).Pluck("ip_addresses", &addressesSlices)
|
||||||
|
|
||||||
var ips netipx.IPSetBuilder
|
var ips netipx.IPSetBuilder
|
||||||
for _, slice := range addressesSlices {
|
for _, slice := range addressesSlices {
|
||||||
var machineAddresses types.MachineAddresses
|
var machineAddresses types.NodeAddresses
|
||||||
err := machineAddresses.Scan(slice)
|
err := machineAddresses.Scan(slice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &netipx.IPSet{}, fmt.Errorf(
|
return &netipx.IPSet{}, fmt.Errorf(
|
||||||
|
|
|
@ -30,21 +30,21 @@ func (s *Suite) TestGetUsedIps(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "testmachine")
|
_, err = db.GetNode("test", "testnode")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
IPAddresses: ips,
|
IPAddresses: ips,
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
usedIps, err := db.getUsedIPs()
|
usedIps, err := db.getUsedIPs()
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ func (s *Suite) TestGetUsedIps(c *check.C) {
|
||||||
c.Assert(usedIps.Equal(expectedIPSet), check.Equals, true)
|
c.Assert(usedIps.Equal(expectedIPSet), check.Equals, true)
|
||||||
c.Assert(usedIps.Contains(expected), check.Equals, true)
|
c.Assert(usedIps.Contains(expected), check.Equals, true)
|
||||||
|
|
||||||
machine1, err := db.GetMachineByID(0)
|
node1, err := db.GetNodeByID(0)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
c.Assert(len(machine1.IPAddresses), check.Equals, 1)
|
c.Assert(len(node1.IPAddresses), check.Equals, 1)
|
||||||
c.Assert(machine1.IPAddresses[0], check.Equals, expected)
|
c.Assert(node1.IPAddresses[0], check.Equals, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestGetMultiIp(c *check.C) {
|
func (s *Suite) TestGetMultiIp(c *check.C) {
|
||||||
|
@ -78,21 +78,21 @@ func (s *Suite) TestGetMultiIp(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "testmachine")
|
_, err = db.GetNode("test", "testnode")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: uint64(index),
|
ID: uint64(index),
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
IPAddresses: ips,
|
IPAddresses: ips,
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
db.ipAllocationMutex.Unlock()
|
db.ipAllocationMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -119,20 +119,20 @@ func (s *Suite) TestGetMultiIp(c *check.C) {
|
||||||
c.Assert(usedIps.Contains(expected300), check.Equals, true)
|
c.Assert(usedIps.Contains(expected300), check.Equals, true)
|
||||||
|
|
||||||
// Check that we can read back the IPs
|
// Check that we can read back the IPs
|
||||||
machine1, err := db.GetMachineByID(1)
|
node1, err := db.GetNodeByID(1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(machine1.IPAddresses), check.Equals, 1)
|
c.Assert(len(node1.IPAddresses), check.Equals, 1)
|
||||||
c.Assert(
|
c.Assert(
|
||||||
machine1.IPAddresses[0],
|
node1.IPAddresses[0],
|
||||||
check.Equals,
|
check.Equals,
|
||||||
netip.MustParseAddr("10.27.0.1"),
|
netip.MustParseAddr("10.27.0.1"),
|
||||||
)
|
)
|
||||||
|
|
||||||
machine50, err := db.GetMachineByID(50)
|
node50, err := db.GetNodeByID(50)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(machine50.IPAddresses), check.Equals, 1)
|
c.Assert(len(node50.IPAddresses), check.Equals, 1)
|
||||||
c.Assert(
|
c.Assert(
|
||||||
machine50.IPAddresses[0],
|
node50.IPAddresses[0],
|
||||||
check.Equals,
|
check.Equals,
|
||||||
netip.MustParseAddr("10.27.0.50"),
|
netip.MustParseAddr("10.27.0.50"),
|
||||||
)
|
)
|
||||||
|
@ -153,7 +153,7 @@ func (s *Suite) TestGetMultiIp(c *check.C) {
|
||||||
c.Assert(nextIP2[0].String(), check.Equals, expectedNextIP.String())
|
c.Assert(nextIP2[0].String(), check.Equals, expectedNextIP.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestGetAvailableIpMachineWithoutIP(c *check.C) {
|
func (s *Suite) TestGetAvailableIpNodeWithoutIP(c *check.C) {
|
||||||
ips, err := db.getAvailableIPs()
|
ips, err := db.getAvailableIPs()
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
@ -168,20 +168,20 @@ func (s *Suite) TestGetAvailableIpMachineWithoutIP(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "testmachine")
|
_, err = db.GetNode("test", "testnode")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
ips2, err := db.getAvailableIPs()
|
ips2, err := db.getAvailableIPs()
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
|
@ -78,49 +78,53 @@ func NewHeadscaleDatabase(
|
||||||
|
|
||||||
_ = dbConn.Migrator().RenameTable("namespaces", "users")
|
_ = dbConn.Migrator().RenameTable("namespaces", "users")
|
||||||
|
|
||||||
|
// the big rename from Machine to Node
|
||||||
|
_ = dbConn.Migrator().RenameTable("machines", "nodes")
|
||||||
|
_ = dbConn.Migrator().RenameColumn(&types.Route{}, "machine_id", "node_id")
|
||||||
|
|
||||||
err = dbConn.AutoMigrate(types.User{})
|
err = dbConn.AutoMigrate(types.User{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = dbConn.Migrator().RenameColumn(&types.Machine{}, "namespace_id", "user_id")
|
_ = dbConn.Migrator().RenameColumn(&types.Node{}, "namespace_id", "user_id")
|
||||||
_ = dbConn.Migrator().RenameColumn(&types.PreAuthKey{}, "namespace_id", "user_id")
|
_ = dbConn.Migrator().RenameColumn(&types.PreAuthKey{}, "namespace_id", "user_id")
|
||||||
|
|
||||||
_ = dbConn.Migrator().RenameColumn(&types.Machine{}, "ip_address", "ip_addresses")
|
_ = dbConn.Migrator().RenameColumn(&types.Node{}, "ip_address", "ip_addresses")
|
||||||
_ = dbConn.Migrator().RenameColumn(&types.Machine{}, "name", "hostname")
|
_ = dbConn.Migrator().RenameColumn(&types.Node{}, "name", "hostname")
|
||||||
|
|
||||||
// GivenName is used as the primary source of DNS names, make sure
|
// GivenName is used as the primary source of DNS names, make sure
|
||||||
// the field is populated and normalized if it was not when the
|
// the field is populated and normalized if it was not when the
|
||||||
// machine was registered.
|
// node was registered.
|
||||||
_ = dbConn.Migrator().RenameColumn(&types.Machine{}, "nickname", "given_name")
|
_ = dbConn.Migrator().RenameColumn(&types.Node{}, "nickname", "given_name")
|
||||||
|
|
||||||
// If the Machine table has a column for registered,
|
// If the MacNodehine table has a column for registered,
|
||||||
// find all occourences of "false" and drop them. Then
|
// find all occourences of "false" and drop them. Then
|
||||||
// remove the column.
|
// remove the column.
|
||||||
if dbConn.Migrator().HasColumn(&types.Machine{}, "registered") {
|
if dbConn.Migrator().HasColumn(&types.Node{}, "registered") {
|
||||||
log.Info().
|
log.Info().
|
||||||
Msg(`Database has legacy "registered" column in machine, removing...`)
|
Msg(`Database has legacy "registered" column in node, removing...`)
|
||||||
|
|
||||||
machines := types.Machines{}
|
nodes := types.Nodes{}
|
||||||
if err := dbConn.Not("registered").Find(&machines).Error; err != nil {
|
if err := dbConn.Not("registered").Find(&nodes).Error; err != nil {
|
||||||
log.Error().Err(err).Msg("Error accessing db")
|
log.Error().Err(err).Msg("Error accessing db")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, machine := range machines {
|
for _, node := range nodes {
|
||||||
log.Info().
|
log.Info().
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Str("machine_key", machine.MachineKey).
|
Str("machine_key", node.MachineKey).
|
||||||
Msg("Deleting unregistered machine")
|
Msg("Deleting unregistered node")
|
||||||
if err := dbConn.Delete(&types.Machine{}, machine.ID).Error; err != nil {
|
if err := dbConn.Delete(&types.Node{}, node.ID).Error; err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Str("machine_key", machine.MachineKey).
|
Str("machine_key", node.MachineKey).
|
||||||
Msg("Error deleting unregistered machine")
|
Msg("Error deleting unregistered node")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := dbConn.Migrator().DropColumn(&types.Machine{}, "registered")
|
err := dbConn.Migrator().DropColumn(&types.Node{}, "registered")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Error dropping registered column")
|
log.Error().Err(err).Msg("Error dropping registered column")
|
||||||
}
|
}
|
||||||
|
@ -131,21 +135,21 @@ func NewHeadscaleDatabase(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if dbConn.Migrator().HasColumn(&types.Machine{}, "enabled_routes") {
|
if dbConn.Migrator().HasColumn(&types.Node{}, "enabled_routes") {
|
||||||
log.Info().Msgf("Database has legacy enabled_routes column in machine, migrating...")
|
log.Info().Msgf("Database has legacy enabled_routes column in node, migrating...")
|
||||||
|
|
||||||
type MachineAux struct {
|
type NodeAux struct {
|
||||||
ID uint64
|
ID uint64
|
||||||
EnabledRoutes types.IPPrefixes
|
EnabledRoutes types.IPPrefixes
|
||||||
}
|
}
|
||||||
|
|
||||||
machinesAux := []MachineAux{}
|
nodesAux := []NodeAux{}
|
||||||
err := dbConn.Table("machines").Select("id, enabled_routes").Scan(&machinesAux).Error
|
err := dbConn.Table("nodes").Select("id, enabled_routes").Scan(&nodesAux).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("Error accessing db")
|
log.Fatal().Err(err).Msg("Error accessing db")
|
||||||
}
|
}
|
||||||
for _, machine := range machinesAux {
|
for _, node := range nodesAux {
|
||||||
for _, prefix := range machine.EnabledRoutes {
|
for _, prefix := range node.EnabledRoutes {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
|
@ -155,8 +159,8 @@ func NewHeadscaleDatabase(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = dbConn.Preload("Machine").
|
err = dbConn.Preload("Node").
|
||||||
Where("machine_id = ? AND prefix = ?", machine.ID, types.IPPrefix(prefix)).
|
Where("node_id = ? AND prefix = ?", node.ID, types.IPPrefix(prefix)).
|
||||||
First(&types.Route{}).
|
First(&types.Route{}).
|
||||||
Error
|
Error
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -168,7 +172,7 @@ func NewHeadscaleDatabase(
|
||||||
}
|
}
|
||||||
|
|
||||||
route := types.Route{
|
route := types.Route{
|
||||||
MachineID: machine.ID,
|
NodeID: node.ID,
|
||||||
Advertised: true,
|
Advertised: true,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Prefix: types.IPPrefix(prefix),
|
Prefix: types.IPPrefix(prefix),
|
||||||
|
@ -177,50 +181,50 @@ func NewHeadscaleDatabase(
|
||||||
log.Error().Err(err).Msg("Error creating route")
|
log.Error().Err(err).Msg("Error creating route")
|
||||||
} else {
|
} else {
|
||||||
log.Info().
|
log.Info().
|
||||||
Uint64("machine_id", route.MachineID).
|
Uint64("node_id", route.NodeID).
|
||||||
Str("prefix", prefix.String()).
|
Str("prefix", prefix.String()).
|
||||||
Msg("Route migrated")
|
Msg("Route migrated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = dbConn.Migrator().DropColumn(&types.Machine{}, "enabled_routes")
|
err = dbConn.Migrator().DropColumn(&types.Node{}, "enabled_routes")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Error dropping enabled_routes column")
|
log.Error().Err(err).Msg("Error dropping enabled_routes column")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = dbConn.AutoMigrate(&types.Machine{})
|
err = dbConn.AutoMigrate(&types.Node{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if dbConn.Migrator().HasColumn(&types.Machine{}, "given_name") {
|
if dbConn.Migrator().HasColumn(&types.Node{}, "given_name") {
|
||||||
machines := types.Machines{}
|
nodes := types.Nodes{}
|
||||||
if err := dbConn.Find(&machines).Error; err != nil {
|
if err := dbConn.Find(&nodes).Error; err != nil {
|
||||||
log.Error().Err(err).Msg("Error accessing db")
|
log.Error().Err(err).Msg("Error accessing db")
|
||||||
}
|
}
|
||||||
|
|
||||||
for item, machine := range machines {
|
for item, node := range nodes {
|
||||||
if machine.GivenName == "" {
|
if node.GivenName == "" {
|
||||||
normalizedHostname, err := util.NormalizeToFQDNRulesConfigFromViper(
|
normalizedHostname, err := util.NormalizeToFQDNRulesConfigFromViper(
|
||||||
machine.Hostname,
|
node.Hostname,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Str("hostname", machine.Hostname).
|
Str("hostname", node.Hostname).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Failed to normalize machine hostname in DB migration")
|
Msg("Failed to normalize node hostname in DB migration")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.RenameMachine(machines[item], normalizedHostname)
|
err = db.RenameNode(nodes[item], normalizedHostname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Str("hostname", machine.Hostname).
|
Str("hostname", node.Hostname).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Failed to save normalized machine name in DB migration")
|
Msg("Failed to save normalized node name in DB migration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,887 +0,0 @@
|
||||||
package db
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/netip"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/juanfont/headscale/hscontrol/types"
|
|
||||||
"github.com/juanfont/headscale/hscontrol/util"
|
|
||||||
"github.com/patrickmn/go-cache"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"tailscale.com/tailcfg"
|
|
||||||
"tailscale.com/types/key"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
MachineGivenNameHashLength = 8
|
|
||||||
MachineGivenNameTrimSize = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrMachineNotFound = errors.New("machine not found")
|
|
||||||
ErrMachineRouteIsNotAvailable = errors.New("route is not available on machine")
|
|
||||||
ErrMachineNotFoundRegistrationCache = errors.New(
|
|
||||||
"machine not found in registration cache",
|
|
||||||
)
|
|
||||||
ErrCouldNotConvertMachineInterface = errors.New("failed to convert machine interface")
|
|
||||||
ErrDifferentRegisteredUser = errors.New(
|
|
||||||
"machine was previously registered with a different user",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// ListPeers returns all peers of machine, regardless of any Policy or if the node is expired.
|
|
||||||
func (hsdb *HSDatabase) ListPeers(machine *types.Machine) (types.Machines, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
return hsdb.listPeers(machine)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) listPeers(machine *types.Machine) (types.Machines, error) {
|
|
||||||
log.Trace().
|
|
||||||
Caller().
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Msg("Finding direct peers")
|
|
||||||
|
|
||||||
machines := types.Machines{}
|
|
||||||
if err := hsdb.db.
|
|
||||||
Preload("AuthKey").
|
|
||||||
Preload("AuthKey.User").
|
|
||||||
Preload("User").
|
|
||||||
Preload("Routes").
|
|
||||||
Where("node_key <> ?",
|
|
||||||
machine.NodeKey).Find(&machines).Error; err != nil {
|
|
||||||
return types.Machines{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(machines, func(i, j int) bool { return machines[i].ID < machines[j].ID })
|
|
||||||
|
|
||||||
log.Trace().
|
|
||||||
Caller().
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Msgf("Found peers: %s", machines.String())
|
|
||||||
|
|
||||||
return machines, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) ListMachines() ([]types.Machine, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
return hsdb.listMachines()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) listMachines() ([]types.Machine, error) {
|
|
||||||
machines := []types.Machine{}
|
|
||||||
if err := hsdb.db.
|
|
||||||
Preload("AuthKey").
|
|
||||||
Preload("AuthKey.User").
|
|
||||||
Preload("User").
|
|
||||||
Preload("Routes").
|
|
||||||
Find(&machines).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return machines, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) ListMachinesByGivenName(givenName string) (types.Machines, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
return hsdb.listMachinesByGivenName(givenName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) listMachinesByGivenName(givenName string) (types.Machines, error) {
|
|
||||||
machines := types.Machines{}
|
|
||||||
if err := hsdb.db.
|
|
||||||
Preload("AuthKey").
|
|
||||||
Preload("AuthKey.User").
|
|
||||||
Preload("User").
|
|
||||||
Preload("Routes").
|
|
||||||
Where("given_name = ?", givenName).Find(&machines).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return machines, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMachine finds a Machine by name and user and returns the Machine struct.
|
|
||||||
func (hsdb *HSDatabase) GetMachine(user string, name string) (*types.Machine, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
machines, err := hsdb.ListMachinesByUser(user)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range machines {
|
|
||||||
if m.Hostname == name {
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, ErrMachineNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMachineByGivenName finds a Machine by given name and user and returns the Machine struct.
|
|
||||||
func (hsdb *HSDatabase) GetMachineByGivenName(
|
|
||||||
user string,
|
|
||||||
givenName string,
|
|
||||||
) (*types.Machine, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
machine := types.Machine{}
|
|
||||||
if err := hsdb.db.
|
|
||||||
Preload("AuthKey").
|
|
||||||
Preload("AuthKey.User").
|
|
||||||
Preload("User").
|
|
||||||
Preload("Routes").
|
|
||||||
Where("given_name = ?", givenName).First(&machine).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, ErrMachineNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMachineByID finds a Machine by ID and returns the Machine struct.
|
|
||||||
func (hsdb *HSDatabase) GetMachineByID(id uint64) (*types.Machine, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
mach := types.Machine{}
|
|
||||||
if result := hsdb.db.
|
|
||||||
Preload("AuthKey").
|
|
||||||
Preload("AuthKey.User").
|
|
||||||
Preload("User").
|
|
||||||
Preload("Routes").
|
|
||||||
Find(&types.Machine{ID: id}).First(&mach); result.Error != nil {
|
|
||||||
return nil, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return &mach, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMachineByMachineKey finds a Machine by its MachineKey and returns the Machine struct.
|
|
||||||
func (hsdb *HSDatabase) GetMachineByMachineKey(
|
|
||||||
machineKey key.MachinePublic,
|
|
||||||
) (*types.Machine, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
mach := types.Machine{}
|
|
||||||
if result := hsdb.db.
|
|
||||||
Preload("AuthKey").
|
|
||||||
Preload("AuthKey.User").
|
|
||||||
Preload("User").
|
|
||||||
Preload("Routes").
|
|
||||||
First(&mach, "machine_key = ?", util.MachinePublicKeyStripPrefix(machineKey)); result.Error != nil {
|
|
||||||
return nil, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return &mach, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMachineByNodeKey finds a Machine by its current NodeKey.
|
|
||||||
func (hsdb *HSDatabase) GetMachineByNodeKey(
|
|
||||||
nodeKey key.NodePublic,
|
|
||||||
) (*types.Machine, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
machine := types.Machine{}
|
|
||||||
if result := hsdb.db.
|
|
||||||
Preload("AuthKey").
|
|
||||||
Preload("AuthKey.User").
|
|
||||||
Preload("User").
|
|
||||||
Preload("Routes").
|
|
||||||
First(&machine, "node_key = ?",
|
|
||||||
util.NodePublicKeyStripPrefix(nodeKey)); result.Error != nil {
|
|
||||||
return nil, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return &machine, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMachineByAnyNodeKey finds a Machine by its MachineKey, its current NodeKey or the old one, and returns the Machine struct.
|
|
||||||
func (hsdb *HSDatabase) GetMachineByAnyKey(
|
|
||||||
machineKey key.MachinePublic, nodeKey key.NodePublic, oldNodeKey key.NodePublic,
|
|
||||||
) (*types.Machine, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
machine := types.Machine{}
|
|
||||||
if result := hsdb.db.
|
|
||||||
Preload("AuthKey").
|
|
||||||
Preload("AuthKey.User").
|
|
||||||
Preload("User").
|
|
||||||
Preload("Routes").
|
|
||||||
First(&machine, "machine_key = ? OR node_key = ? OR node_key = ?",
|
|
||||||
util.MachinePublicKeyStripPrefix(machineKey),
|
|
||||||
util.NodePublicKeyStripPrefix(nodeKey),
|
|
||||||
util.NodePublicKeyStripPrefix(oldNodeKey)); result.Error != nil {
|
|
||||||
return nil, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return &machine, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) MachineReloadFromDatabase(machine *types.Machine) error {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
if result := hsdb.db.Find(machine).First(&machine); result.Error != nil {
|
|
||||||
return result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTags takes a Machine struct pointer and update the forced tags.
|
|
||||||
func (hsdb *HSDatabase) SetTags(
|
|
||||||
machine *types.Machine,
|
|
||||||
tags []string,
|
|
||||||
) error {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
newTags := []string{}
|
|
||||||
for _, tag := range tags {
|
|
||||||
if !util.StringOrPrefixListContains(newTags, tag) {
|
|
||||||
newTags = append(newTags, tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := hsdb.db.Model(machine).Updates(types.Machine{
|
|
||||||
ForcedTags: newTags,
|
|
||||||
}).Error; err != nil {
|
|
||||||
return fmt.Errorf("failed to update tags for machine in the database: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
|
||||||
Type: types.StatePeerChanged,
|
|
||||||
Changed: types.Machines{machine},
|
|
||||||
}, machine.MachineKey)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenameMachine takes a Machine struct and a new GivenName for the machines
|
|
||||||
// and renames it.
|
|
||||||
func (hsdb *HSDatabase) RenameMachine(machine *types.Machine, newName string) error {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
err := util.CheckForFQDNRules(
|
|
||||||
newName,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Str("func", "RenameMachine").
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Str("newName", newName).
|
|
||||||
Err(err).
|
|
||||||
Msg("failed to rename machine")
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
machine.GivenName = newName
|
|
||||||
|
|
||||||
if err := hsdb.db.Model(machine).Updates(types.Machine{
|
|
||||||
GivenName: newName,
|
|
||||||
}).Error; err != nil {
|
|
||||||
return fmt.Errorf("failed to rename machine in the database: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
|
||||||
Type: types.StatePeerChanged,
|
|
||||||
Changed: types.Machines{machine},
|
|
||||||
}, machine.MachineKey)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MachineSetExpiry takes a Machine struct and a new expiry time.
|
|
||||||
func (hsdb *HSDatabase) MachineSetExpiry(machine *types.Machine, expiry time.Time) error {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
return hsdb.machineSetExpiry(machine, expiry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) machineSetExpiry(machine *types.Machine, expiry time.Time) error {
|
|
||||||
if err := hsdb.db.Model(machine).Updates(types.Machine{
|
|
||||||
Expiry: &expiry,
|
|
||||||
}).Error; err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"failed to refresh machine (update expiration) in the database: %w",
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
|
||||||
Type: types.StatePeerChanged,
|
|
||||||
Changed: types.Machines{machine},
|
|
||||||
}, machine.MachineKey)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteMachine deletes a Machine from the database.
|
|
||||||
func (hsdb *HSDatabase) DeleteMachine(machine *types.Machine) error {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
return hsdb.deleteMachine(machine)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) deleteMachine(machine *types.Machine) error {
|
|
||||||
err := hsdb.deleteMachineRoutes(machine)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unscoped causes the machine to be fully removed from the database.
|
|
||||||
if err := hsdb.db.Unscoped().Delete(&machine).Error; err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
hsdb.notifier.NotifyAll(types.StateUpdate{
|
|
||||||
Type: types.StatePeerRemoved,
|
|
||||||
Removed: []tailcfg.NodeID{tailcfg.NodeID(machine.ID)},
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateLastSeen sets a machine's last seen field indicating that we
|
|
||||||
// have recently communicating with this machine.
|
|
||||||
// This is mostly used to indicate if a machine is online and is not
|
|
||||||
// extremely important to make sure is fully correct and to avoid
|
|
||||||
// holding up the hot path, does not contain any locks and isnt
|
|
||||||
// concurrency safe. But that should be ok.
|
|
||||||
func (hsdb *HSDatabase) UpdateLastSeen(machine *types.Machine) error {
|
|
||||||
return hsdb.db.Model(machine).Updates(types.Machine{
|
|
||||||
LastSeen: machine.LastSeen,
|
|
||||||
}).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) RegisterMachineFromAuthCallback(
|
|
||||||
cache *cache.Cache,
|
|
||||||
nodeKeyStr string,
|
|
||||||
userName string,
|
|
||||||
machineExpiry *time.Time,
|
|
||||||
registrationMethod string,
|
|
||||||
) (*types.Machine, error) {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
nodeKey := key.NodePublic{}
|
|
||||||
err := nodeKey.UnmarshalText([]byte(nodeKeyStr))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug().
|
|
||||||
Str("nodeKey", nodeKey.ShortString()).
|
|
||||||
Str("userName", userName).
|
|
||||||
Str("registrationMethod", registrationMethod).
|
|
||||||
Str("expiresAt", fmt.Sprintf("%v", machineExpiry)).
|
|
||||||
Msg("Registering machine from API/CLI or auth callback")
|
|
||||||
|
|
||||||
if machineInterface, ok := cache.Get(util.NodePublicKeyStripPrefix(nodeKey)); ok {
|
|
||||||
if registrationMachine, ok := machineInterface.(types.Machine); ok {
|
|
||||||
user, err := hsdb.getUser(userName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"failed to find user in register machine from auth callback, %w",
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Registration of expired machine with different user
|
|
||||||
if registrationMachine.ID != 0 &&
|
|
||||||
registrationMachine.UserID != user.ID {
|
|
||||||
return nil, ErrDifferentRegisteredUser
|
|
||||||
}
|
|
||||||
|
|
||||||
registrationMachine.UserID = user.ID
|
|
||||||
registrationMachine.RegisterMethod = registrationMethod
|
|
||||||
|
|
||||||
if machineExpiry != nil {
|
|
||||||
registrationMachine.Expiry = machineExpiry
|
|
||||||
}
|
|
||||||
|
|
||||||
machine, err := hsdb.registerMachine(
|
|
||||||
registrationMachine,
|
|
||||||
)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
cache.Delete(nodeKeyStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return machine, err
|
|
||||||
} else {
|
|
||||||
return nil, ErrCouldNotConvertMachineInterface
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, ErrMachineNotFoundRegistrationCache
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterMachine is executed from the CLI to register a new Machine using its MachineKey.
|
|
||||||
func (hsdb *HSDatabase) RegisterMachine(machine types.Machine) (*types.Machine, error) {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
return hsdb.registerMachine(machine)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) registerMachine(machine types.Machine) (*types.Machine, error) {
|
|
||||||
log.Debug().
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Str("machine_key", machine.MachineKey).
|
|
||||||
Str("node_key", machine.NodeKey).
|
|
||||||
Str("user", machine.User.Name).
|
|
||||||
Msg("Registering machine")
|
|
||||||
|
|
||||||
// If the machine exists and we had already IPs for it, we just save it
|
|
||||||
// so we store the machine.Expire and machine.Nodekey that has been set when
|
|
||||||
// adding it to the registrationCache
|
|
||||||
if len(machine.IPAddresses) > 0 {
|
|
||||||
if err := hsdb.db.Save(&machine).Error; err != nil {
|
|
||||||
return nil, fmt.Errorf("failed register existing machine in the database: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Trace().
|
|
||||||
Caller().
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Str("machine_key", machine.MachineKey).
|
|
||||||
Str("node_key", machine.NodeKey).
|
|
||||||
Str("user", machine.User.Name).
|
|
||||||
Msg("Machine authorized again")
|
|
||||||
|
|
||||||
return &machine, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
hsdb.ipAllocationMutex.Lock()
|
|
||||||
defer hsdb.ipAllocationMutex.Unlock()
|
|
||||||
|
|
||||||
ips, err := hsdb.getAvailableIPs()
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Msg("Could not find IP for the new machine")
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
machine.IPAddresses = ips
|
|
||||||
|
|
||||||
if err := hsdb.db.Save(&machine).Error; err != nil {
|
|
||||||
return nil, fmt.Errorf("failed register(save) machine in the database: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Trace().
|
|
||||||
Caller().
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Str("ip", strings.Join(ips.StringSlice(), ",")).
|
|
||||||
Msg("Machine registered with the database")
|
|
||||||
|
|
||||||
return &machine, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MachineSetNodeKey sets the node key of a machine and saves it to the database.
|
|
||||||
func (hsdb *HSDatabase) MachineSetNodeKey(machine *types.Machine, nodeKey key.NodePublic) error {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
if err := hsdb.db.Model(machine).Updates(types.Machine{
|
|
||||||
NodeKey: util.NodePublicKeyStripPrefix(nodeKey),
|
|
||||||
}).Error; err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MachineSetMachineKey sets the machine key of a machine and saves it to the database.
|
|
||||||
func (hsdb *HSDatabase) MachineSetMachineKey(
|
|
||||||
machine *types.Machine,
|
|
||||||
machineKey key.MachinePublic,
|
|
||||||
) error {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
if err := hsdb.db.Model(machine).Updates(types.Machine{
|
|
||||||
MachineKey: util.MachinePublicKeyStripPrefix(machineKey),
|
|
||||||
}).Error; err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MachineSave saves a machine object to the database, prefer to use a specific save method rather
|
|
||||||
// than this. It is intended to be used when we are changing or.
|
|
||||||
func (hsdb *HSDatabase) MachineSave(machine *types.Machine) error {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
if err := hsdb.db.Save(machine).Error; err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAdvertisedRoutes returns the routes that are be advertised by the given machine.
|
|
||||||
func (hsdb *HSDatabase) GetAdvertisedRoutes(machine *types.Machine) ([]netip.Prefix, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
return hsdb.getAdvertisedRoutes(machine)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) getAdvertisedRoutes(machine *types.Machine) ([]netip.Prefix, error) {
|
|
||||||
routes := types.Routes{}
|
|
||||||
|
|
||||||
err := hsdb.db.
|
|
||||||
Preload("Machine").
|
|
||||||
Where("machine_id = ? AND advertised = ?", machine.ID, true).Find(&routes).Error
|
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Msg("Could not get advertised routes for machine")
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
prefixes := []netip.Prefix{}
|
|
||||||
for _, route := range routes {
|
|
||||||
prefixes = append(prefixes, netip.Prefix(route.Prefix))
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefixes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetEnabledRoutes returns the routes that are enabled for the machine.
|
|
||||||
func (hsdb *HSDatabase) GetEnabledRoutes(machine *types.Machine) ([]netip.Prefix, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
return hsdb.getEnabledRoutes(machine)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) getEnabledRoutes(machine *types.Machine) ([]netip.Prefix, error) {
|
|
||||||
routes := types.Routes{}
|
|
||||||
|
|
||||||
err := hsdb.db.
|
|
||||||
Preload("Machine").
|
|
||||||
Where("machine_id = ? AND advertised = ? AND enabled = ?", machine.ID, true, true).
|
|
||||||
Find(&routes).Error
|
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Msg("Could not get enabled routes for machine")
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
prefixes := []netip.Prefix{}
|
|
||||||
for _, route := range routes {
|
|
||||||
prefixes = append(prefixes, netip.Prefix(route.Prefix))
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefixes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) IsRoutesEnabled(machine *types.Machine, routeStr string) bool {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
route, err := netip.ParsePrefix(routeStr)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
enabledRoutes, err := hsdb.getEnabledRoutes(machine)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Could not get enabled routes")
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, enabledRoute := range enabledRoutes {
|
|
||||||
if route == enabledRoute {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func OnlineMachineMap(peers types.Machines) map[tailcfg.NodeID]bool {
|
|
||||||
ret := make(map[tailcfg.NodeID]bool)
|
|
||||||
|
|
||||||
for _, peer := range peers {
|
|
||||||
ret[tailcfg.NodeID(peer.ID)] = peer.IsOnline()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) ListOnlineMachines(
|
|
||||||
machine *types.Machine,
|
|
||||||
) (map[tailcfg.NodeID]bool, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
peers, err := hsdb.listPeers(machine)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return OnlineMachineMap(peers), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// enableRoutes enables new routes based on a list of new routes.
|
|
||||||
func (hsdb *HSDatabase) enableRoutes(machine *types.Machine, routeStrs ...string) error {
|
|
||||||
newRoutes := make([]netip.Prefix, len(routeStrs))
|
|
||||||
for index, routeStr := range routeStrs {
|
|
||||||
route, err := netip.ParsePrefix(routeStr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newRoutes[index] = route
|
|
||||||
}
|
|
||||||
|
|
||||||
advertisedRoutes, err := hsdb.getAdvertisedRoutes(machine)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, newRoute := range newRoutes {
|
|
||||||
if !util.StringOrPrefixListContains(advertisedRoutes, newRoute) {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"route (%s) is not available on node %s: %w",
|
|
||||||
machine.Hostname,
|
|
||||||
newRoute, ErrMachineRouteIsNotAvailable,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Separate loop so we don't leave things in a half-updated state
|
|
||||||
for _, prefix := range newRoutes {
|
|
||||||
route := types.Route{}
|
|
||||||
err := hsdb.db.Preload("Machine").
|
|
||||||
Where("machine_id = ? AND prefix = ?", machine.ID, types.IPPrefix(prefix)).
|
|
||||||
First(&route).Error
|
|
||||||
if err == nil {
|
|
||||||
route.Enabled = true
|
|
||||||
|
|
||||||
// Mark already as primary if there is only this node offering this subnet
|
|
||||||
// (and is not an exit route)
|
|
||||||
if !route.IsExitRoute() {
|
|
||||||
route.IsPrimary = hsdb.isUniquePrefix(route)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hsdb.db.Save(&route).Error
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to enable route: %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("failed to find route: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
|
||||||
Type: types.StatePeerChanged,
|
|
||||||
Changed: types.Machines{machine},
|
|
||||||
}, machine.MachineKey)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateGivenName(suppliedName string, randomSuffix bool) (string, error) {
|
|
||||||
normalizedHostname, err := util.NormalizeToFQDNRulesConfigFromViper(
|
|
||||||
suppliedName,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if randomSuffix {
|
|
||||||
// Trim if a hostname will be longer than 63 chars after adding the hash.
|
|
||||||
trimmedHostnameLength := util.LabelHostnameLength - MachineGivenNameHashLength - MachineGivenNameTrimSize
|
|
||||||
if len(normalizedHostname) > trimmedHostnameLength {
|
|
||||||
normalizedHostname = normalizedHostname[:trimmedHostnameLength]
|
|
||||||
}
|
|
||||||
|
|
||||||
suffix, err := util.GenerateRandomStringDNSSafe(MachineGivenNameHashLength)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
normalizedHostname += "-" + suffix
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalizedHostname, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) GenerateGivenName(machineKey string, suppliedName string) (string, error) {
|
|
||||||
hsdb.mu.RLock()
|
|
||||||
defer hsdb.mu.RUnlock()
|
|
||||||
|
|
||||||
givenName, err := generateGivenName(suppliedName, false)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tailscale rules (may differ) https://tailscale.com/kb/1098/machine-names/
|
|
||||||
machines, err := hsdb.listMachinesByGivenName(givenName)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, machine := range machines {
|
|
||||||
if machine.MachineKey != machineKey && machine.GivenName == givenName {
|
|
||||||
postfixedName, err := generateGivenName(suppliedName, true)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
givenName = postfixedName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return givenName, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) ExpireEphemeralMachines(inactivityThreshhold time.Duration) {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
users, err := hsdb.listUsers()
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Error listing users")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range users {
|
|
||||||
machines, err := hsdb.listMachinesByUser(user.Name)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Err(err).
|
|
||||||
Str("user", user.Name).
|
|
||||||
Msg("Error listing machines in user")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
expired := make([]tailcfg.NodeID, 0)
|
|
||||||
for idx, machine := range machines {
|
|
||||||
if machine.IsEphemeral() && machine.LastSeen != nil &&
|
|
||||||
time.Now().
|
|
||||||
After(machine.LastSeen.Add(inactivityThreshhold)) {
|
|
||||||
expired = append(expired, tailcfg.NodeID(machine.ID))
|
|
||||||
|
|
||||||
log.Info().
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Msg("Ephemeral client removed from database")
|
|
||||||
|
|
||||||
err = hsdb.deleteMachine(machines[idx])
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Err(err).
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Msg("🤮 Cannot delete ephemeral machine from the database")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(expired) > 0 {
|
|
||||||
hsdb.notifier.NotifyAll(types.StateUpdate{
|
|
||||||
Type: types.StatePeerRemoved,
|
|
||||||
Removed: expired,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hsdb *HSDatabase) ExpireExpiredMachines(lastCheck time.Time) time.Time {
|
|
||||||
hsdb.mu.Lock()
|
|
||||||
defer hsdb.mu.Unlock()
|
|
||||||
|
|
||||||
// use the time of the start of the function to ensure we
|
|
||||||
// dont miss some machines by returning it _after_ we have
|
|
||||||
// checked everything.
|
|
||||||
started := time.Now()
|
|
||||||
|
|
||||||
users, err := hsdb.listUsers()
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Error listing users")
|
|
||||||
|
|
||||||
return time.Unix(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range users {
|
|
||||||
machines, err := hsdb.listMachinesByUser(user.Name)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Err(err).
|
|
||||||
Str("user", user.Name).
|
|
||||||
Msg("Error listing machines in user")
|
|
||||||
|
|
||||||
return time.Unix(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
expired := make([]tailcfg.NodeID, 0)
|
|
||||||
for index, machine := range machines {
|
|
||||||
if machine.IsExpired() &&
|
|
||||||
machine.Expiry.After(lastCheck) {
|
|
||||||
expired = append(expired, tailcfg.NodeID(machine.ID))
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
err := hsdb.machineSetExpiry(machines[index], now)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Err(err).
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Str("name", machine.GivenName).
|
|
||||||
Msg("🤮 Cannot expire machine")
|
|
||||||
} else {
|
|
||||||
log.Info().
|
|
||||||
Str("machine", machine.Hostname).
|
|
||||||
Str("name", machine.GivenName).
|
|
||||||
Msg("Machine successfully expired")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(expired) > 0 {
|
|
||||||
hsdb.notifier.NotifyAll(types.StateUpdate{
|
|
||||||
Type: types.StatePeerRemoved,
|
|
||||||
Removed: expired,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return started
|
|
||||||
}
|
|
887
hscontrol/db/node.go
Normal file
887
hscontrol/db/node.go
Normal file
|
@ -0,0 +1,887 @@
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/juanfont/headscale/hscontrol/types"
|
||||||
|
"github.com/juanfont/headscale/hscontrol/util"
|
||||||
|
"github.com/patrickmn/go-cache"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
|
"tailscale.com/types/key"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NodeGivenNameHashLength = 8
|
||||||
|
NodeGivenNameTrimSize = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNodeNotFound = errors.New("node not found")
|
||||||
|
ErrNodeRouteIsNotAvailable = errors.New("route is not available on node")
|
||||||
|
ErrNodeNotFoundRegistrationCache = errors.New(
|
||||||
|
"node not found in registration cache",
|
||||||
|
)
|
||||||
|
ErrCouldNotConvertNodeInterface = errors.New("failed to convert node interface")
|
||||||
|
ErrDifferentRegisteredUser = errors.New(
|
||||||
|
"node was previously registered with a different user",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListPeers returns all peers of node, regardless of any Policy or if the node is expired.
|
||||||
|
func (hsdb *HSDatabase) ListPeers(node *types.Node) (types.Nodes, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
return hsdb.listPeers(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) listPeers(node *types.Node) (types.Nodes, error) {
|
||||||
|
log.Trace().
|
||||||
|
Caller().
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Msg("Finding direct peers")
|
||||||
|
|
||||||
|
nodes := types.Nodes{}
|
||||||
|
if err := hsdb.db.
|
||||||
|
Preload("AuthKey").
|
||||||
|
Preload("AuthKey.User").
|
||||||
|
Preload("User").
|
||||||
|
Preload("Routes").
|
||||||
|
Where("node_key <> ?",
|
||||||
|
node.NodeKey).Find(&nodes).Error; err != nil {
|
||||||
|
return types.Nodes{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(nodes, func(i, j int) bool { return nodes[i].ID < nodes[j].ID })
|
||||||
|
|
||||||
|
log.Trace().
|
||||||
|
Caller().
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Msgf("Found peers: %s", nodes.String())
|
||||||
|
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) ListNodes() ([]types.Node, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
return hsdb.listNodes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) listNodes() ([]types.Node, error) {
|
||||||
|
nodes := []types.Node{}
|
||||||
|
if err := hsdb.db.
|
||||||
|
Preload("AuthKey").
|
||||||
|
Preload("AuthKey.User").
|
||||||
|
Preload("User").
|
||||||
|
Preload("Routes").
|
||||||
|
Find(&nodes).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) ListNodesByGivenName(givenName string) (types.Nodes, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
return hsdb.listNodesByGivenName(givenName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) listNodesByGivenName(givenName string) (types.Nodes, error) {
|
||||||
|
nodes := types.Nodes{}
|
||||||
|
if err := hsdb.db.
|
||||||
|
Preload("AuthKey").
|
||||||
|
Preload("AuthKey.User").
|
||||||
|
Preload("User").
|
||||||
|
Preload("Routes").
|
||||||
|
Where("given_name = ?", givenName).Find(&nodes).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNode finds a Node by name and user and returns the Node struct.
|
||||||
|
func (hsdb *HSDatabase) GetNode(user string, name string) (*types.Node, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
nodes, err := hsdb.ListNodesByUser(user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range nodes {
|
||||||
|
if m.Hostname == name {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrNodeNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodeByGivenName finds a Node by given name and user and returns the Node struct.
|
||||||
|
func (hsdb *HSDatabase) GetNodeByGivenName(
|
||||||
|
user string,
|
||||||
|
givenName string,
|
||||||
|
) (*types.Node, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
node := types.Node{}
|
||||||
|
if err := hsdb.db.
|
||||||
|
Preload("AuthKey").
|
||||||
|
Preload("AuthKey.User").
|
||||||
|
Preload("User").
|
||||||
|
Preload("Routes").
|
||||||
|
Where("given_name = ?", givenName).First(&node).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrNodeNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodeByID finds a Node by ID and returns the Node struct.
|
||||||
|
func (hsdb *HSDatabase) GetNodeByID(id uint64) (*types.Node, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
mach := types.Node{}
|
||||||
|
if result := hsdb.db.
|
||||||
|
Preload("AuthKey").
|
||||||
|
Preload("AuthKey.User").
|
||||||
|
Preload("User").
|
||||||
|
Preload("Routes").
|
||||||
|
Find(&types.Node{ID: id}).First(&mach); result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return &mach, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodeByMachineKey finds a Node by its MachineKey and returns the Node struct.
|
||||||
|
func (hsdb *HSDatabase) GetNodeByMachineKey(
|
||||||
|
machineKey key.MachinePublic,
|
||||||
|
) (*types.Node, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
mach := types.Node{}
|
||||||
|
if result := hsdb.db.
|
||||||
|
Preload("AuthKey").
|
||||||
|
Preload("AuthKey.User").
|
||||||
|
Preload("User").
|
||||||
|
Preload("Routes").
|
||||||
|
First(&mach, "machine_key = ?", util.MachinePublicKeyStripPrefix(machineKey)); result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return &mach, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodeByNodeKey finds a Node by its current NodeKey.
|
||||||
|
func (hsdb *HSDatabase) GetNodeByNodeKey(
|
||||||
|
nodeKey key.NodePublic,
|
||||||
|
) (*types.Node, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
node := types.Node{}
|
||||||
|
if result := hsdb.db.
|
||||||
|
Preload("AuthKey").
|
||||||
|
Preload("AuthKey.User").
|
||||||
|
Preload("User").
|
||||||
|
Preload("Routes").
|
||||||
|
First(&node, "node_key = ?",
|
||||||
|
util.NodePublicKeyStripPrefix(nodeKey)); result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return &node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodeByAnyKey finds a Node by its MachineKey, its current NodeKey or the old one, and returns the Node struct.
|
||||||
|
func (hsdb *HSDatabase) GetNodeByAnyKey(
|
||||||
|
machineKey key.MachinePublic, nodeKey key.NodePublic, oldNodeKey key.NodePublic,
|
||||||
|
) (*types.Node, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
node := types.Node{}
|
||||||
|
if result := hsdb.db.
|
||||||
|
Preload("AuthKey").
|
||||||
|
Preload("AuthKey.User").
|
||||||
|
Preload("User").
|
||||||
|
Preload("Routes").
|
||||||
|
First(&node, "machine_key = ? OR node_key = ? OR node_key = ?",
|
||||||
|
util.MachinePublicKeyStripPrefix(machineKey),
|
||||||
|
util.NodePublicKeyStripPrefix(nodeKey),
|
||||||
|
util.NodePublicKeyStripPrefix(oldNodeKey)); result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return &node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) NodeReloadFromDatabase(node *types.Node) error {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
if result := hsdb.db.Find(node).First(&node); result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTags takes a Node struct pointer and update the forced tags.
|
||||||
|
func (hsdb *HSDatabase) SetTags(
|
||||||
|
node *types.Node,
|
||||||
|
tags []string,
|
||||||
|
) error {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
newTags := []string{}
|
||||||
|
for _, tag := range tags {
|
||||||
|
if !util.StringOrPrefixListContains(newTags, tag) {
|
||||||
|
newTags = append(newTags, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hsdb.db.Model(node).Updates(types.Node{
|
||||||
|
ForcedTags: newTags,
|
||||||
|
}).Error; err != nil {
|
||||||
|
return fmt.Errorf("failed to update tags for node in the database: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
||||||
|
Type: types.StatePeerChanged,
|
||||||
|
Changed: types.Nodes{node},
|
||||||
|
}, node.MachineKey)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenameNode takes a Node struct and a new GivenName for the nodes
|
||||||
|
// and renames it.
|
||||||
|
func (hsdb *HSDatabase) RenameNode(node *types.Node, newName string) error {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
err := util.CheckForFQDNRules(
|
||||||
|
newName,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().
|
||||||
|
Caller().
|
||||||
|
Str("func", "RenameNode").
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Str("newName", newName).
|
||||||
|
Err(err).
|
||||||
|
Msg("failed to rename node")
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
node.GivenName = newName
|
||||||
|
|
||||||
|
if err := hsdb.db.Model(node).Updates(types.Node{
|
||||||
|
GivenName: newName,
|
||||||
|
}).Error; err != nil {
|
||||||
|
return fmt.Errorf("failed to rename node in the database: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
||||||
|
Type: types.StatePeerChanged,
|
||||||
|
Changed: types.Nodes{node},
|
||||||
|
}, node.MachineKey)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeSetExpiry takes a Node struct and a new expiry time.
|
||||||
|
func (hsdb *HSDatabase) NodeSetExpiry(node *types.Node, expiry time.Time) error {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
return hsdb.nodeSetExpiry(node, expiry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) nodeSetExpiry(node *types.Node, expiry time.Time) error {
|
||||||
|
if err := hsdb.db.Model(node).Updates(types.Node{
|
||||||
|
Expiry: &expiry,
|
||||||
|
}).Error; err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"failed to refresh node (update expiration) in the database: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
||||||
|
Type: types.StatePeerChanged,
|
||||||
|
Changed: types.Nodes{node},
|
||||||
|
}, node.MachineKey)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteNode deletes a Node from the database.
|
||||||
|
func (hsdb *HSDatabase) DeleteNode(node *types.Node) error {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
return hsdb.deleteNode(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) deleteNode(node *types.Node) error {
|
||||||
|
err := hsdb.deleteNodeRoutes(node)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unscoped causes the node to be fully removed from the database.
|
||||||
|
if err := hsdb.db.Unscoped().Delete(&node).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hsdb.notifier.NotifyAll(types.StateUpdate{
|
||||||
|
Type: types.StatePeerRemoved,
|
||||||
|
Removed: []tailcfg.NodeID{tailcfg.NodeID(node.ID)},
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateLastSeen sets a node's last seen field indicating that we
|
||||||
|
// have recently communicating with this node.
|
||||||
|
// This is mostly used to indicate if a node is online and is not
|
||||||
|
// extremely important to make sure is fully correct and to avoid
|
||||||
|
// holding up the hot path, does not contain any locks and isnt
|
||||||
|
// concurrency safe. But that should be ok.
|
||||||
|
func (hsdb *HSDatabase) UpdateLastSeen(node *types.Node) error {
|
||||||
|
return hsdb.db.Model(node).Updates(types.Node{
|
||||||
|
LastSeen: node.LastSeen,
|
||||||
|
}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) RegisterNodeFromAuthCallback(
|
||||||
|
cache *cache.Cache,
|
||||||
|
nodeKeyStr string,
|
||||||
|
userName string,
|
||||||
|
nodeExpiry *time.Time,
|
||||||
|
registrationMethod string,
|
||||||
|
) (*types.Node, error) {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
nodeKey := key.NodePublic{}
|
||||||
|
err := nodeKey.UnmarshalText([]byte(nodeKeyStr))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().
|
||||||
|
Str("nodeKey", nodeKey.ShortString()).
|
||||||
|
Str("userName", userName).
|
||||||
|
Str("registrationMethod", registrationMethod).
|
||||||
|
Str("expiresAt", fmt.Sprintf("%v", nodeExpiry)).
|
||||||
|
Msg("Registering node from API/CLI or auth callback")
|
||||||
|
|
||||||
|
if nodeInterface, ok := cache.Get(util.NodePublicKeyStripPrefix(nodeKey)); ok {
|
||||||
|
if registrationNode, ok := nodeInterface.(types.Node); ok {
|
||||||
|
user, err := hsdb.getUser(userName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"failed to find user in register node from auth callback, %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registration of expired node with different user
|
||||||
|
if registrationNode.ID != 0 &&
|
||||||
|
registrationNode.UserID != user.ID {
|
||||||
|
return nil, ErrDifferentRegisteredUser
|
||||||
|
}
|
||||||
|
|
||||||
|
registrationNode.UserID = user.ID
|
||||||
|
registrationNode.RegisterMethod = registrationMethod
|
||||||
|
|
||||||
|
if nodeExpiry != nil {
|
||||||
|
registrationNode.Expiry = nodeExpiry
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err := hsdb.registerNode(
|
||||||
|
registrationNode,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
cache.Delete(nodeKeyStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node, err
|
||||||
|
} else {
|
||||||
|
return nil, ErrCouldNotConvertNodeInterface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrNodeNotFoundRegistrationCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterNode is executed from the CLI to register a new Node using its MachineKey.
|
||||||
|
func (hsdb *HSDatabase) RegisterNode(node types.Node) (*types.Node, error) {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
return hsdb.registerNode(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) registerNode(node types.Node) (*types.Node, error) {
|
||||||
|
log.Debug().
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Str("machine_key", node.MachineKey).
|
||||||
|
Str("node_key", node.NodeKey).
|
||||||
|
Str("user", node.User.Name).
|
||||||
|
Msg("Registering node")
|
||||||
|
|
||||||
|
// If the node exists and we had already IPs for it, we just save it
|
||||||
|
// so we store the node.Expire and node.Nodekey that has been set when
|
||||||
|
// adding it to the registrationCache
|
||||||
|
if len(node.IPAddresses) > 0 {
|
||||||
|
if err := hsdb.db.Save(&node).Error; err != nil {
|
||||||
|
return nil, fmt.Errorf("failed register existing node in the database: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace().
|
||||||
|
Caller().
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Str("machine_key", node.MachineKey).
|
||||||
|
Str("node_key", node.NodeKey).
|
||||||
|
Str("user", node.User.Name).
|
||||||
|
Msg("Node authorized again")
|
||||||
|
|
||||||
|
return &node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hsdb.ipAllocationMutex.Lock()
|
||||||
|
defer hsdb.ipAllocationMutex.Unlock()
|
||||||
|
|
||||||
|
ips, err := hsdb.getAvailableIPs()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().
|
||||||
|
Caller().
|
||||||
|
Err(err).
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Msg("Could not find IP for the new node")
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
node.IPAddresses = ips
|
||||||
|
|
||||||
|
if err := hsdb.db.Save(&node).Error; err != nil {
|
||||||
|
return nil, fmt.Errorf("failed register(save) node in the database: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace().
|
||||||
|
Caller().
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Str("ip", strings.Join(ips.StringSlice(), ",")).
|
||||||
|
Msg("Node registered with the database")
|
||||||
|
|
||||||
|
return &node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeSetNodeKey sets the node key of a node and saves it to the database.
|
||||||
|
func (hsdb *HSDatabase) NodeSetNodeKey(node *types.Node, nodeKey key.NodePublic) error {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
if err := hsdb.db.Model(node).Updates(types.Node{
|
||||||
|
NodeKey: util.NodePublicKeyStripPrefix(nodeKey),
|
||||||
|
}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeSetMachineKey sets the node key of a node and saves it to the database.
|
||||||
|
func (hsdb *HSDatabase) NodeSetMachineKey(
|
||||||
|
node *types.Node,
|
||||||
|
machineKey key.MachinePublic,
|
||||||
|
) error {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
if err := hsdb.db.Model(node).Updates(types.Node{
|
||||||
|
MachineKey: util.MachinePublicKeyStripPrefix(machineKey),
|
||||||
|
}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeSave saves a node object to the database, prefer to use a specific save method rather
|
||||||
|
// than this. It is intended to be used when we are changing or.
|
||||||
|
func (hsdb *HSDatabase) NodeSave(node *types.Node) error {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
if err := hsdb.db.Save(node).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAdvertisedRoutes returns the routes that are be advertised by the given node.
|
||||||
|
func (hsdb *HSDatabase) GetAdvertisedRoutes(node *types.Node) ([]netip.Prefix, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
return hsdb.getAdvertisedRoutes(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) getAdvertisedRoutes(node *types.Node) ([]netip.Prefix, error) {
|
||||||
|
routes := types.Routes{}
|
||||||
|
|
||||||
|
err := hsdb.db.
|
||||||
|
Preload("Node").
|
||||||
|
Where("node_id = ? AND advertised = ?", node.ID, true).Find(&routes).Error
|
||||||
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
log.Error().
|
||||||
|
Caller().
|
||||||
|
Err(err).
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Msg("Could not get advertised routes for node")
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixes := []netip.Prefix{}
|
||||||
|
for _, route := range routes {
|
||||||
|
prefixes = append(prefixes, netip.Prefix(route.Prefix))
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefixes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEnabledRoutes returns the routes that are enabled for the node.
|
||||||
|
func (hsdb *HSDatabase) GetEnabledRoutes(node *types.Node) ([]netip.Prefix, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
return hsdb.getEnabledRoutes(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) getEnabledRoutes(node *types.Node) ([]netip.Prefix, error) {
|
||||||
|
routes := types.Routes{}
|
||||||
|
|
||||||
|
err := hsdb.db.
|
||||||
|
Preload("Node").
|
||||||
|
Where("node_id = ? AND advertised = ? AND enabled = ?", node.ID, true, true).
|
||||||
|
Find(&routes).Error
|
||||||
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
log.Error().
|
||||||
|
Caller().
|
||||||
|
Err(err).
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Msg("Could not get enabled routes for node")
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixes := []netip.Prefix{}
|
||||||
|
for _, route := range routes {
|
||||||
|
prefixes = append(prefixes, netip.Prefix(route.Prefix))
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefixes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) IsRoutesEnabled(node *types.Node, routeStr string) bool {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
route, err := netip.ParsePrefix(routeStr)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
enabledRoutes, err := hsdb.getEnabledRoutes(node)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("Could not get enabled routes")
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, enabledRoute := range enabledRoutes {
|
||||||
|
if route == enabledRoute {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func OnlineNodeMap(peers types.Nodes) map[tailcfg.NodeID]bool {
|
||||||
|
ret := make(map[tailcfg.NodeID]bool)
|
||||||
|
|
||||||
|
for _, peer := range peers {
|
||||||
|
ret[tailcfg.NodeID(peer.ID)] = peer.IsOnline()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) ListOnlineNodes(
|
||||||
|
node *types.Node,
|
||||||
|
) (map[tailcfg.NodeID]bool, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
peers, err := hsdb.listPeers(node)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return OnlineNodeMap(peers), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// enableRoutes enables new routes based on a list of new routes.
|
||||||
|
func (hsdb *HSDatabase) enableRoutes(node *types.Node, routeStrs ...string) error {
|
||||||
|
newRoutes := make([]netip.Prefix, len(routeStrs))
|
||||||
|
for index, routeStr := range routeStrs {
|
||||||
|
route, err := netip.ParsePrefix(routeStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoutes[index] = route
|
||||||
|
}
|
||||||
|
|
||||||
|
advertisedRoutes, err := hsdb.getAdvertisedRoutes(node)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, newRoute := range newRoutes {
|
||||||
|
if !util.StringOrPrefixListContains(advertisedRoutes, newRoute) {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"route (%s) is not available on node %s: %w",
|
||||||
|
node.Hostname,
|
||||||
|
newRoute, ErrNodeRouteIsNotAvailable,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate loop so we don't leave things in a half-updated state
|
||||||
|
for _, prefix := range newRoutes {
|
||||||
|
route := types.Route{}
|
||||||
|
err := hsdb.db.Preload("Node").
|
||||||
|
Where("node_id = ? AND prefix = ?", node.ID, types.IPPrefix(prefix)).
|
||||||
|
First(&route).Error
|
||||||
|
if err == nil {
|
||||||
|
route.Enabled = true
|
||||||
|
|
||||||
|
// Mark already as primary if there is only this node offering this subnet
|
||||||
|
// (and is not an exit route)
|
||||||
|
if !route.IsExitRoute() {
|
||||||
|
route.IsPrimary = hsdb.isUniquePrefix(route)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = hsdb.db.Save(&route).Error
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to enable route: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("failed to find route: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
||||||
|
Type: types.StatePeerChanged,
|
||||||
|
Changed: types.Nodes{node},
|
||||||
|
}, node.MachineKey)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateGivenName(suppliedName string, randomSuffix bool) (string, error) {
|
||||||
|
normalizedHostname, err := util.NormalizeToFQDNRulesConfigFromViper(
|
||||||
|
suppliedName,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if randomSuffix {
|
||||||
|
// Trim if a hostname will be longer than 63 chars after adding the hash.
|
||||||
|
trimmedHostnameLength := util.LabelHostnameLength - NodeGivenNameHashLength - NodeGivenNameTrimSize
|
||||||
|
if len(normalizedHostname) > trimmedHostnameLength {
|
||||||
|
normalizedHostname = normalizedHostname[:trimmedHostnameLength]
|
||||||
|
}
|
||||||
|
|
||||||
|
suffix, err := util.GenerateRandomStringDNSSafe(NodeGivenNameHashLength)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizedHostname += "-" + suffix
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedHostname, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) GenerateGivenName(machineKey string, suppliedName string) (string, error) {
|
||||||
|
hsdb.mu.RLock()
|
||||||
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
|
givenName, err := generateGivenName(suppliedName, false)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tailscale rules (may differ) https://tailscale.com/kb/1098/machine-names/
|
||||||
|
nodes, err := hsdb.listNodesByGivenName(givenName)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.MachineKey != machineKey && node.GivenName == givenName {
|
||||||
|
postfixedName, err := generateGivenName(suppliedName, true)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
givenName = postfixedName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return givenName, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) ExpireEphemeralNodes(inactivityThreshhold time.Duration) {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
users, err := hsdb.listUsers()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("Error listing users")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
nodes, err := hsdb.listNodesByUser(user.Name)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().
|
||||||
|
Err(err).
|
||||||
|
Str("user", user.Name).
|
||||||
|
Msg("Error listing nodes in user")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
expired := make([]tailcfg.NodeID, 0)
|
||||||
|
for idx, node := range nodes {
|
||||||
|
if node.IsEphemeral() && node.LastSeen != nil &&
|
||||||
|
time.Now().
|
||||||
|
After(node.LastSeen.Add(inactivityThreshhold)) {
|
||||||
|
expired = append(expired, tailcfg.NodeID(node.ID))
|
||||||
|
|
||||||
|
log.Info().
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Msg("Ephemeral client removed from database")
|
||||||
|
|
||||||
|
err = hsdb.deleteNode(nodes[idx])
|
||||||
|
if err != nil {
|
||||||
|
log.Error().
|
||||||
|
Err(err).
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Msg("🤮 Cannot delete ephemeral node from the database")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expired) > 0 {
|
||||||
|
hsdb.notifier.NotifyAll(types.StateUpdate{
|
||||||
|
Type: types.StatePeerRemoved,
|
||||||
|
Removed: expired,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hsdb *HSDatabase) ExpireExpiredNodes(lastCheck time.Time) time.Time {
|
||||||
|
hsdb.mu.Lock()
|
||||||
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
// use the time of the start of the function to ensure we
|
||||||
|
// dont miss some nodes by returning it _after_ we have
|
||||||
|
// checked everything.
|
||||||
|
started := time.Now()
|
||||||
|
|
||||||
|
users, err := hsdb.listUsers()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("Error listing users")
|
||||||
|
|
||||||
|
return time.Unix(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
nodes, err := hsdb.listNodesByUser(user.Name)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().
|
||||||
|
Err(err).
|
||||||
|
Str("user", user.Name).
|
||||||
|
Msg("Error listing nodes in user")
|
||||||
|
|
||||||
|
return time.Unix(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
expired := make([]tailcfg.NodeID, 0)
|
||||||
|
for index, node := range nodes {
|
||||||
|
if node.IsExpired() &&
|
||||||
|
node.Expiry.After(lastCheck) {
|
||||||
|
expired = append(expired, tailcfg.NodeID(node.ID))
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
err := hsdb.nodeSetExpiry(nodes[index], now)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().
|
||||||
|
Err(err).
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Str("name", node.GivenName).
|
||||||
|
Msg("🤮 Cannot expire node")
|
||||||
|
} else {
|
||||||
|
log.Info().
|
||||||
|
Str("node", node.Hostname).
|
||||||
|
Str("name", node.GivenName).
|
||||||
|
Msg("Node successfully expired")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expired) > 0 {
|
||||||
|
hsdb.notifier.NotifyAll(types.StateUpdate{
|
||||||
|
Type: types.StatePeerRemoved,
|
||||||
|
Removed: expired,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return started
|
||||||
|
}
|
|
@ -15,95 +15,95 @@ import (
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Suite) TestGetMachine(c *check.C) {
|
func (s *Suite) TestGetNode(c *check.C) {
|
||||||
user, err := db.CreateUser("test")
|
user, err := db.CreateUser("test")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "testmachine")
|
_, err = db.GetNode("test", "testnode")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
machine := &types.Machine{
|
node := &types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(machine)
|
db.db.Save(node)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "testmachine")
|
_, err = db.GetNode("test", "testnode")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestGetMachineByID(c *check.C) {
|
func (s *Suite) TestGetNodeByID(c *check.C) {
|
||||||
user, err := db.CreateUser("test")
|
user, err := db.CreateUser("test")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachineByID(0)
|
_, err = db.GetNodeByID(0)
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
_, err = db.GetMachineByID(0)
|
_, err = db.GetNodeByID(0)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestGetMachineByNodeKey(c *check.C) {
|
func (s *Suite) TestGetNodeByNodeKey(c *check.C) {
|
||||||
user, err := db.CreateUser("test")
|
user, err := db.CreateUser("test")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachineByID(0)
|
_, err = db.GetNodeByID(0)
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
nodeKey := key.NewNode()
|
nodeKey := key.NewNode()
|
||||||
machineKey := key.NewMachine()
|
machineKey := key.NewMachine()
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: util.MachinePublicKeyStripPrefix(machineKey.Public()),
|
MachineKey: util.MachinePublicKeyStripPrefix(machineKey.Public()),
|
||||||
NodeKey: util.NodePublicKeyStripPrefix(nodeKey.Public()),
|
NodeKey: util.NodePublicKeyStripPrefix(nodeKey.Public()),
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
_, err = db.GetMachineByNodeKey(nodeKey.Public())
|
_, err = db.GetNodeByNodeKey(nodeKey.Public())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestGetMachineByAnyNodeKey(c *check.C) {
|
func (s *Suite) TestGetNodeByAnyNodeKey(c *check.C) {
|
||||||
user, err := db.CreateUser("test")
|
user, err := db.CreateUser("test")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachineByID(0)
|
_, err = db.GetNodeByID(0)
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
nodeKey := key.NewNode()
|
nodeKey := key.NewNode()
|
||||||
|
@ -111,41 +111,41 @@ func (s *Suite) TestGetMachineByAnyNodeKey(c *check.C) {
|
||||||
|
|
||||||
machineKey := key.NewMachine()
|
machineKey := key.NewMachine()
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: util.MachinePublicKeyStripPrefix(machineKey.Public()),
|
MachineKey: util.MachinePublicKeyStripPrefix(machineKey.Public()),
|
||||||
NodeKey: util.NodePublicKeyStripPrefix(nodeKey.Public()),
|
NodeKey: util.NodePublicKeyStripPrefix(nodeKey.Public()),
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
_, err = db.GetMachineByAnyKey(machineKey.Public(), nodeKey.Public(), oldNodeKey.Public())
|
_, err = db.GetNodeByAnyKey(machineKey.Public(), nodeKey.Public(), oldNodeKey.Public())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestHardDeleteMachine(c *check.C) {
|
func (s *Suite) TestHardDeleteNode(c *check.C) {
|
||||||
user, err := db.CreateUser("test")
|
user, err := db.CreateUser("test")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine3",
|
Hostname: "testnode3",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(1),
|
AuthKeyID: uint(1),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
err = db.DeleteMachine(&machine)
|
err = db.DeleteNode(&node)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine(user.Name, "testmachine3")
|
_, err = db.GetNode(user.Name, "testnode3")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,33 +156,33 @@ func (s *Suite) TestListPeers(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachineByID(0)
|
_, err = db.GetNodeByID(0)
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
for index := 0; index <= 10; index++ {
|
for index := 0; index <= 10; index++ {
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: uint64(index),
|
ID: uint64(index),
|
||||||
MachineKey: "foo" + strconv.Itoa(index),
|
MachineKey: "foo" + strconv.Itoa(index),
|
||||||
NodeKey: "bar" + strconv.Itoa(index),
|
NodeKey: "bar" + strconv.Itoa(index),
|
||||||
DiscoKey: "faa" + strconv.Itoa(index),
|
DiscoKey: "faa" + strconv.Itoa(index),
|
||||||
Hostname: "testmachine" + strconv.Itoa(index),
|
Hostname: "testnode" + strconv.Itoa(index),
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
}
|
}
|
||||||
|
|
||||||
machine0ByID, err := db.GetMachineByID(0)
|
node0ByID, err := db.GetNodeByID(0)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
peersOfMachine0, err := db.ListPeers(machine0ByID)
|
peersOfNode0, err := db.ListPeers(node0ByID)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
c.Assert(len(peersOfMachine0), check.Equals, 9)
|
c.Assert(len(peersOfNode0), check.Equals, 9)
|
||||||
c.Assert(peersOfMachine0[0].Hostname, check.Equals, "testmachine2")
|
c.Assert(peersOfNode0[0].Hostname, check.Equals, "testnode2")
|
||||||
c.Assert(peersOfMachine0[5].Hostname, check.Equals, "testmachine7")
|
c.Assert(peersOfNode0[5].Hostname, check.Equals, "testnode7")
|
||||||
c.Assert(peersOfMachine0[8].Hostname, check.Equals, "testmachine10")
|
c.Assert(peersOfNode0[8].Hostname, check.Equals, "testnode10")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
|
func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
|
||||||
|
@ -201,24 +201,24 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
|
||||||
stor = append(stor, base{user, pak})
|
stor = append(stor, base{user, pak})
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := db.GetMachineByID(0)
|
_, err := db.GetNodeByID(0)
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
for index := 0; index <= 10; index++ {
|
for index := 0; index <= 10; index++ {
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: uint64(index),
|
ID: uint64(index),
|
||||||
MachineKey: "foo" + strconv.Itoa(index),
|
MachineKey: "foo" + strconv.Itoa(index),
|
||||||
NodeKey: "bar" + strconv.Itoa(index),
|
NodeKey: "bar" + strconv.Itoa(index),
|
||||||
DiscoKey: "faa" + strconv.Itoa(index),
|
DiscoKey: "faa" + strconv.Itoa(index),
|
||||||
IPAddresses: types.MachineAddresses{
|
IPAddresses: types.NodeAddresses{
|
||||||
netip.MustParseAddr(fmt.Sprintf("100.64.0.%v", strconv.Itoa(index+1))),
|
netip.MustParseAddr(fmt.Sprintf("100.64.0.%v", strconv.Itoa(index+1))),
|
||||||
},
|
},
|
||||||
Hostname: "testmachine" + strconv.Itoa(index),
|
Hostname: "testnode" + strconv.Itoa(index),
|
||||||
UserID: stor[index%2].user.ID,
|
UserID: stor[index%2].user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(stor[index%2].key.ID),
|
AuthKeyID: uint(stor[index%2].key.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
}
|
}
|
||||||
|
|
||||||
aclPolicy := &policy.ACLPolicy{
|
aclPolicy := &policy.ACLPolicy{
|
||||||
|
@ -242,80 +242,80 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
|
||||||
Tests: []policy.ACLTest{},
|
Tests: []policy.ACLTest{},
|
||||||
}
|
}
|
||||||
|
|
||||||
adminMachine, err := db.GetMachineByID(1)
|
adminNode, err := db.GetNodeByID(1)
|
||||||
c.Logf("Machine(%v), user: %v", adminMachine.Hostname, adminMachine.User)
|
c.Logf("Node(%v), user: %v", adminNode.Hostname, adminNode.User)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
testMachine, err := db.GetMachineByID(2)
|
testNode, err := db.GetNodeByID(2)
|
||||||
c.Logf("Machine(%v), user: %v", testMachine.Hostname, testMachine.User)
|
c.Logf("Node(%v), user: %v", testNode.Hostname, testNode.User)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
adminPeers, err := db.ListPeers(adminMachine)
|
adminPeers, err := db.ListPeers(adminNode)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
testPeers, err := db.ListPeers(testMachine)
|
testPeers, err := db.ListPeers(testNode)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
adminRules, _, err := policy.GenerateFilterAndSSHRules(aclPolicy, adminMachine, adminPeers)
|
adminRules, _, err := policy.GenerateFilterAndSSHRules(aclPolicy, adminNode, adminPeers)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
testRules, _, err := policy.GenerateFilterAndSSHRules(aclPolicy, testMachine, testPeers)
|
testRules, _, err := policy.GenerateFilterAndSSHRules(aclPolicy, testNode, testPeers)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
peersOfAdminMachine := policy.FilterMachinesByACL(adminMachine, adminPeers, adminRules)
|
peersOfAdminNode := policy.FilterNodesByACL(adminNode, adminPeers, adminRules)
|
||||||
peersOfTestMachine := policy.FilterMachinesByACL(testMachine, testPeers, testRules)
|
peersOfTestNode := policy.FilterNodesByACL(testNode, testPeers, testRules)
|
||||||
|
|
||||||
c.Log(peersOfTestMachine)
|
c.Log(peersOfTestNode)
|
||||||
c.Assert(len(peersOfTestMachine), check.Equals, 9)
|
c.Assert(len(peersOfTestNode), check.Equals, 9)
|
||||||
c.Assert(peersOfTestMachine[0].Hostname, check.Equals, "testmachine1")
|
c.Assert(peersOfTestNode[0].Hostname, check.Equals, "testnode1")
|
||||||
c.Assert(peersOfTestMachine[1].Hostname, check.Equals, "testmachine3")
|
c.Assert(peersOfTestNode[1].Hostname, check.Equals, "testnode3")
|
||||||
c.Assert(peersOfTestMachine[3].Hostname, check.Equals, "testmachine5")
|
c.Assert(peersOfTestNode[3].Hostname, check.Equals, "testnode5")
|
||||||
|
|
||||||
c.Log(peersOfAdminMachine)
|
c.Log(peersOfAdminNode)
|
||||||
c.Assert(len(peersOfAdminMachine), check.Equals, 9)
|
c.Assert(len(peersOfAdminNode), check.Equals, 9)
|
||||||
c.Assert(peersOfAdminMachine[0].Hostname, check.Equals, "testmachine2")
|
c.Assert(peersOfAdminNode[0].Hostname, check.Equals, "testnode2")
|
||||||
c.Assert(peersOfAdminMachine[2].Hostname, check.Equals, "testmachine4")
|
c.Assert(peersOfAdminNode[2].Hostname, check.Equals, "testnode4")
|
||||||
c.Assert(peersOfAdminMachine[5].Hostname, check.Equals, "testmachine7")
|
c.Assert(peersOfAdminNode[5].Hostname, check.Equals, "testnode7")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestExpireMachine(c *check.C) {
|
func (s *Suite) TestExpireNode(c *check.C) {
|
||||||
user, err := db.CreateUser("test")
|
user, err := db.CreateUser("test")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "testmachine")
|
_, err = db.GetNode("test", "testnode")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
machine := &types.Machine{
|
node := &types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
Expiry: &time.Time{},
|
Expiry: &time.Time{},
|
||||||
}
|
}
|
||||||
db.db.Save(machine)
|
db.db.Save(node)
|
||||||
|
|
||||||
machineFromDB, err := db.GetMachine("test", "testmachine")
|
nodeFromDB, err := db.GetNode("test", "testnode")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(machineFromDB, check.NotNil)
|
c.Assert(nodeFromDB, check.NotNil)
|
||||||
|
|
||||||
c.Assert(machineFromDB.IsExpired(), check.Equals, false)
|
c.Assert(nodeFromDB.IsExpired(), check.Equals, false)
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
err = db.MachineSetExpiry(machineFromDB, now)
|
err = db.NodeSetExpiry(nodeFromDB, now)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
c.Assert(machineFromDB.IsExpired(), check.Equals, true)
|
c.Assert(nodeFromDB.IsExpired(), check.Equals, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestSerdeAddressStrignSlice(c *check.C) {
|
func (s *Suite) TestSerdeAddressStrignSlice(c *check.C) {
|
||||||
input := types.MachineAddresses([]netip.Addr{
|
input := types.NodeAddresses([]netip.Addr{
|
||||||
netip.MustParseAddr("192.0.2.1"),
|
netip.MustParseAddr("192.0.2.1"),
|
||||||
netip.MustParseAddr("2001:db8::1"),
|
netip.MustParseAddr("2001:db8::1"),
|
||||||
})
|
})
|
||||||
|
@ -325,7 +325,7 @@ func (s *Suite) TestSerdeAddressStrignSlice(c *check.C) {
|
||||||
c.Assert(serial, check.Equals, "192.0.2.1,2001:db8::1")
|
c.Assert(serial, check.Equals, "192.0.2.1,2001:db8::1")
|
||||||
}
|
}
|
||||||
|
|
||||||
var deserialized types.MachineAddresses
|
var deserialized types.NodeAddresses
|
||||||
err = deserialized.Scan(serialized)
|
err = deserialized.Scan(serialized)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
@ -342,12 +342,12 @@ func (s *Suite) TestGenerateGivenName(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user1.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user1.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("user-1", "testmachine")
|
_, err = db.GetNode("user-1", "testnode")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
machine := &types.Machine{
|
node := &types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "machine-key-1",
|
MachineKey: "node-key-1",
|
||||||
NodeKey: "node-key-1",
|
NodeKey: "node-key-1",
|
||||||
DiscoKey: "disco-key-1",
|
DiscoKey: "disco-key-1",
|
||||||
Hostname: "hostname-1",
|
Hostname: "hostname-1",
|
||||||
|
@ -356,27 +356,27 @@ func (s *Suite) TestGenerateGivenName(c *check.C) {
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(machine)
|
db.db.Save(node)
|
||||||
|
|
||||||
givenName, err := db.GenerateGivenName("machine-key-2", "hostname-2")
|
givenName, err := db.GenerateGivenName("node-key-2", "hostname-2")
|
||||||
comment := check.Commentf("Same user, unique machines, unique hostnames, no conflict")
|
comment := check.Commentf("Same user, unique nodes, unique hostnames, no conflict")
|
||||||
c.Assert(err, check.IsNil, comment)
|
c.Assert(err, check.IsNil, comment)
|
||||||
c.Assert(givenName, check.Equals, "hostname-2", comment)
|
c.Assert(givenName, check.Equals, "hostname-2", comment)
|
||||||
|
|
||||||
givenName, err = db.GenerateGivenName("machine-key-1", "hostname-1")
|
givenName, err = db.GenerateGivenName("node-key-1", "hostname-1")
|
||||||
comment = check.Commentf("Same user, same machine, same hostname, no conflict")
|
comment = check.Commentf("Same user, same node, same hostname, no conflict")
|
||||||
c.Assert(err, check.IsNil, comment)
|
c.Assert(err, check.IsNil, comment)
|
||||||
c.Assert(givenName, check.Equals, "hostname-1", comment)
|
c.Assert(givenName, check.Equals, "hostname-1", comment)
|
||||||
|
|
||||||
givenName, err = db.GenerateGivenName("machine-key-2", "hostname-1")
|
givenName, err = db.GenerateGivenName("node-key-2", "hostname-1")
|
||||||
comment = check.Commentf("Same user, unique machines, same hostname, conflict")
|
comment = check.Commentf("Same user, unique nodes, same hostname, conflict")
|
||||||
c.Assert(err, check.IsNil, comment)
|
c.Assert(err, check.IsNil, comment)
|
||||||
c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", MachineGivenNameHashLength), comment)
|
c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", NodeGivenNameHashLength), comment)
|
||||||
|
|
||||||
givenName, err = db.GenerateGivenName("machine-key-2", "hostname-1")
|
givenName, err = db.GenerateGivenName("node-key-2", "hostname-1")
|
||||||
comment = check.Commentf("Unique users, unique machines, same hostname, conflict")
|
comment = check.Commentf("Unique users, unique nodes, same hostname, conflict")
|
||||||
c.Assert(err, check.IsNil, comment)
|
c.Assert(err, check.IsNil, comment)
|
||||||
c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", MachineGivenNameHashLength), comment)
|
c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", NodeGivenNameHashLength), comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestSetTags(c *check.C) {
|
func (s *Suite) TestSetTags(c *check.C) {
|
||||||
|
@ -386,37 +386,37 @@ func (s *Suite) TestSetTags(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "testmachine")
|
_, err = db.GetNode("test", "testnode")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
machine := &types.Machine{
|
node := &types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(machine)
|
db.db.Save(node)
|
||||||
|
|
||||||
// assign simple tags
|
// assign simple tags
|
||||||
sTags := []string{"tag:test", "tag:foo"}
|
sTags := []string{"tag:test", "tag:foo"}
|
||||||
err = db.SetTags(machine, sTags)
|
err = db.SetTags(node, sTags)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
machine, err = db.GetMachine("test", "testmachine")
|
node, err = db.GetNode("test", "testnode")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(machine.ForcedTags, check.DeepEquals, types.StringList(sTags))
|
c.Assert(node.ForcedTags, check.DeepEquals, types.StringList(sTags))
|
||||||
|
|
||||||
// assign duplicat tags, expect no errors but no doubles in DB
|
// assign duplicat tags, expect no errors but no doubles in DB
|
||||||
eTags := []string{"tag:bar", "tag:test", "tag:unknown", "tag:test"}
|
eTags := []string{"tag:bar", "tag:test", "tag:unknown", "tag:test"}
|
||||||
err = db.SetTags(machine, eTags)
|
err = db.SetTags(node, eTags)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
machine, err = db.GetMachine("test", "testmachine")
|
node, err = db.GetNode("test", "testnode")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(
|
c.Assert(
|
||||||
machine.ForcedTags,
|
node.ForcedTags,
|
||||||
check.DeepEquals,
|
check.DeepEquals,
|
||||||
types.StringList([]string{"tag:bar", "tag:test", "tag:unknown"}),
|
types.StringList([]string{"tag:bar", "tag:test", "tag:unknown"}),
|
||||||
)
|
)
|
||||||
|
@ -434,16 +434,16 @@ func TestHeadscale_generateGivenName(t *testing.T) {
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "simple machine name generation",
|
name: "simple node name generation",
|
||||||
args: args{
|
args: args{
|
||||||
suppliedName: "testmachine",
|
suppliedName: "testnode",
|
||||||
randomSuffix: false,
|
randomSuffix: false,
|
||||||
},
|
},
|
||||||
want: regexp.MustCompile("^testmachine$"),
|
want: regexp.MustCompile("^testnode$"),
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "machine name with 53 chars",
|
name: "node name with 53 chars",
|
||||||
args: args{
|
args: args{
|
||||||
suppliedName: "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaachine",
|
suppliedName: "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaachine",
|
||||||
randomSuffix: false,
|
randomSuffix: false,
|
||||||
|
@ -452,48 +452,48 @@ func TestHeadscale_generateGivenName(t *testing.T) {
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "machine name with 63 chars",
|
name: "node name with 63 chars",
|
||||||
args: args{
|
args: args{
|
||||||
suppliedName: "machineeee12345678901234567890123456789012345678901234567890123",
|
suppliedName: "nodeeeeeee12345678901234567890123456789012345678901234567890123",
|
||||||
randomSuffix: false,
|
randomSuffix: false,
|
||||||
},
|
},
|
||||||
want: regexp.MustCompile("^machineeee12345678901234567890123456789012345678901234567890123$"),
|
want: regexp.MustCompile("^nodeeeeeee12345678901234567890123456789012345678901234567890123$"),
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "machine name with 64 chars",
|
name: "node name with 64 chars",
|
||||||
args: args{
|
args: args{
|
||||||
suppliedName: "machineeee123456789012345678901234567890123456789012345678901234",
|
suppliedName: "nodeeeeeee123456789012345678901234567890123456789012345678901234",
|
||||||
randomSuffix: false,
|
randomSuffix: false,
|
||||||
},
|
},
|
||||||
want: nil,
|
want: nil,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "machine name with 73 chars",
|
name: "node name with 73 chars",
|
||||||
args: args{
|
args: args{
|
||||||
suppliedName: "machineeee123456789012345678901234567890123456789012345678901234567890123",
|
suppliedName: "nodeeeeeee123456789012345678901234567890123456789012345678901234567890123",
|
||||||
randomSuffix: false,
|
randomSuffix: false,
|
||||||
},
|
},
|
||||||
want: nil,
|
want: nil,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "machine name with random suffix",
|
name: "node name with random suffix",
|
||||||
args: args{
|
args: args{
|
||||||
suppliedName: "test",
|
suppliedName: "test",
|
||||||
randomSuffix: true,
|
randomSuffix: true,
|
||||||
},
|
},
|
||||||
want: regexp.MustCompile(fmt.Sprintf("^test-[a-z0-9]{%d}$", MachineGivenNameHashLength)),
|
want: regexp.MustCompile(fmt.Sprintf("^test-[a-z0-9]{%d}$", NodeGivenNameHashLength)),
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "machine name with 63 chars with random suffix",
|
name: "node name with 63 chars with random suffix",
|
||||||
args: args{
|
args: args{
|
||||||
suppliedName: "machineeee12345678901234567890123456789012345678901234567890123",
|
suppliedName: "nodeeee12345678901234567890123456789012345678901234567890123",
|
||||||
randomSuffix: true,
|
randomSuffix: true,
|
||||||
},
|
},
|
||||||
want: regexp.MustCompile(fmt.Sprintf("^machineeee1234567890123456789012345678901234567890123-[a-z0-9]{%d}$", MachineGivenNameHashLength)),
|
want: regexp.MustCompile(fmt.Sprintf("^nodeeee1234567890123456789012345678901234567890123456-[a-z0-9]{%d}$", NodeGivenNameHashLength)),
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -572,7 +572,7 @@ func (s *Suite) TestAutoApproveRoutes(c *check.C) {
|
||||||
// Check if a subprefix of an autoapproved route is approved
|
// Check if a subprefix of an autoapproved route is approved
|
||||||
route2 := netip.MustParsePrefix("10.11.0.0/24")
|
route2 := netip.MustParsePrefix("10.11.0.0/24")
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: util.NodePublicKeyStripPrefix(nodeKey.Public()),
|
NodeKey: util.NodePublicKeyStripPrefix(nodeKey.Public()),
|
||||||
|
@ -588,18 +588,18 @@ func (s *Suite) TestAutoApproveRoutes(c *check.C) {
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")},
|
||||||
}
|
}
|
||||||
|
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
err = db.SaveMachineRoutes(&machine)
|
err = db.SaveNodeRoutes(&node)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
machine0ByID, err := db.GetMachineByID(0)
|
node0ByID, err := db.GetNodeByID(0)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.EnableAutoApprovedRoutes(pol, machine0ByID)
|
err = db.EnableAutoApprovedRoutes(pol, node0ByID)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enabledRoutes, err := db.GetEnabledRoutes(machine0ByID)
|
enabledRoutes, err := db.GetEnabledRoutes(node0ByID)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(enabledRoutes, check.HasLen, 4)
|
c.Assert(enabledRoutes, check.HasLen, 4)
|
||||||
}
|
}
|
|
@ -203,15 +203,15 @@ func (hsdb *HSDatabase) ValidatePreAuthKey(k string) (*types.PreAuthKey, error)
|
||||||
return &pak, nil
|
return &pak, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
machines := types.Machines{}
|
nodes := types.Nodes{}
|
||||||
if err := hsdb.db.
|
if err := hsdb.db.
|
||||||
Preload("AuthKey").
|
Preload("AuthKey").
|
||||||
Where(&types.Machine{AuthKeyID: uint(pak.ID)}).
|
Where(&types.Node{AuthKeyID: uint(pak.ID)}).
|
||||||
Find(&machines).Error; err != nil {
|
Find(&nodes).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(machines) != 0 || pak.Used {
|
if len(nodes) != 0 || pak.Used {
|
||||||
return nil, ErrSingleUseAuthKeyHasBeenUsed
|
return nil, ErrSingleUseAuthKeyHasBeenUsed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ func (*Suite) TestAlreadyUsedKey(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
|
@ -85,7 +85,7 @@ func (*Suite) TestAlreadyUsedKey(c *check.C) {
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
key, err := db.ValidatePreAuthKey(pak.Key)
|
key, err := db.ValidatePreAuthKey(pak.Key)
|
||||||
c.Assert(err, check.Equals, ErrSingleUseAuthKeyHasBeenUsed)
|
c.Assert(err, check.Equals, ErrSingleUseAuthKeyHasBeenUsed)
|
||||||
|
@ -99,7 +99,7 @@ func (*Suite) TestReusableBeingUsedKey(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, true, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, true, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
|
@ -109,7 +109,7 @@ func (*Suite) TestReusableBeingUsedKey(c *check.C) {
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
key, err := db.ValidatePreAuthKey(pak.Key)
|
key, err := db.ValidatePreAuthKey(pak.Key)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
@ -136,7 +136,7 @@ func (*Suite) TestEphemeralKey(c *check.C) {
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
now := time.Now().Add(-time.Second * 30)
|
now := time.Now().Add(-time.Second * 30)
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
|
@ -147,19 +147,19 @@ func (*Suite) TestEphemeralKey(c *check.C) {
|
||||||
LastSeen: &now,
|
LastSeen: &now,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
_, err = db.ValidatePreAuthKey(pak.Key)
|
_, err = db.ValidatePreAuthKey(pak.Key)
|
||||||
// Ephemeral keys are by definition reusable
|
// Ephemeral keys are by definition reusable
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test7", "testest")
|
_, err = db.GetNode("test7", "testest")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
db.ExpireEphemeralMachines(time.Second * 20)
|
db.ExpireEphemeralNodes(time.Second * 20)
|
||||||
|
|
||||||
// The machine record should have been deleted
|
// The machine record should have been deleted
|
||||||
_, err = db.GetMachine("test7", "testest")
|
_, err = db.GetNode("test7", "testest")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ func (hsdb *HSDatabase) GetRoutes() (types.Routes, error) {
|
||||||
|
|
||||||
func (hsdb *HSDatabase) getRoutes() (types.Routes, error) {
|
func (hsdb *HSDatabase) getRoutes() (types.Routes, error) {
|
||||||
var routes types.Routes
|
var routes types.Routes
|
||||||
err := hsdb.db.Preload("Machine").Find(&routes).Error
|
err := hsdb.db.Preload("Node").Find(&routes).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -29,18 +29,18 @@ func (hsdb *HSDatabase) getRoutes() (types.Routes, error) {
|
||||||
return routes, nil
|
return routes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hsdb *HSDatabase) GetMachineAdvertisedRoutes(machine *types.Machine) (types.Routes, error) {
|
func (hsdb *HSDatabase) GetNodeAdvertisedRoutes(node *types.Node) (types.Routes, error) {
|
||||||
hsdb.mu.RLock()
|
hsdb.mu.RLock()
|
||||||
defer hsdb.mu.RUnlock()
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
return hsdb.getMachineAdvertisedRoutes(machine)
|
return hsdb.getNodeAdvertisedRoutes(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hsdb *HSDatabase) getMachineAdvertisedRoutes(machine *types.Machine) (types.Routes, error) {
|
func (hsdb *HSDatabase) getNodeAdvertisedRoutes(node *types.Node) (types.Routes, error) {
|
||||||
var routes types.Routes
|
var routes types.Routes
|
||||||
err := hsdb.db.
|
err := hsdb.db.
|
||||||
Preload("Machine").
|
Preload("Node").
|
||||||
Where("machine_id = ? AND advertised = true", machine.ID).
|
Where("node_id = ? AND advertised = true", node.ID).
|
||||||
Find(&routes).Error
|
Find(&routes).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -49,18 +49,18 @@ func (hsdb *HSDatabase) getMachineAdvertisedRoutes(machine *types.Machine) (type
|
||||||
return routes, nil
|
return routes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hsdb *HSDatabase) GetMachineRoutes(m *types.Machine) (types.Routes, error) {
|
func (hsdb *HSDatabase) GetNodeRoutes(node *types.Node) (types.Routes, error) {
|
||||||
hsdb.mu.RLock()
|
hsdb.mu.RLock()
|
||||||
defer hsdb.mu.RUnlock()
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
return hsdb.getMachineRoutes(m)
|
return hsdb.getNodeRoutes(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hsdb *HSDatabase) getMachineRoutes(m *types.Machine) (types.Routes, error) {
|
func (hsdb *HSDatabase) getNodeRoutes(node *types.Node) (types.Routes, error) {
|
||||||
var routes types.Routes
|
var routes types.Routes
|
||||||
err := hsdb.db.
|
err := hsdb.db.
|
||||||
Preload("Machine").
|
Preload("Node").
|
||||||
Where("machine_id = ?", m.ID).
|
Where("node_id = ?", node.ID).
|
||||||
Find(&routes).Error
|
Find(&routes).Error
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -78,7 +78,7 @@ func (hsdb *HSDatabase) GetRoute(id uint64) (*types.Route, error) {
|
||||||
|
|
||||||
func (hsdb *HSDatabase) getRoute(id uint64) (*types.Route, error) {
|
func (hsdb *HSDatabase) getRoute(id uint64) (*types.Route, error) {
|
||||||
var route types.Route
|
var route types.Route
|
||||||
err := hsdb.db.Preload("Machine").First(&route, id).Error
|
err := hsdb.db.Preload("Node").First(&route, id).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -104,13 +104,13 @@ func (hsdb *HSDatabase) enableRoute(id uint64) error {
|
||||||
// https://github.com/juanfont/headscale/issues/804#issuecomment-1399314002
|
// https://github.com/juanfont/headscale/issues/804#issuecomment-1399314002
|
||||||
if route.IsExitRoute() {
|
if route.IsExitRoute() {
|
||||||
return hsdb.enableRoutes(
|
return hsdb.enableRoutes(
|
||||||
&route.Machine,
|
&route.Node,
|
||||||
types.ExitRouteV4.String(),
|
types.ExitRouteV4.String(),
|
||||||
types.ExitRouteV6.String(),
|
types.ExitRouteV6.String(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return hsdb.enableRoutes(&route.Machine, netip.Prefix(route.Prefix).String())
|
return hsdb.enableRoutes(&route.Node, netip.Prefix(route.Prefix).String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hsdb *HSDatabase) DisableRoute(id uint64) error {
|
func (hsdb *HSDatabase) DisableRoute(id uint64) error {
|
||||||
|
@ -136,7 +136,7 @@ func (hsdb *HSDatabase) DisableRoute(id uint64) error {
|
||||||
return hsdb.handlePrimarySubnetFailover()
|
return hsdb.handlePrimarySubnetFailover()
|
||||||
}
|
}
|
||||||
|
|
||||||
routes, err := hsdb.getMachineRoutes(&route.Machine)
|
routes, err := hsdb.getNodeRoutes(&route.Node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ func (hsdb *HSDatabase) DeleteRoute(id uint64) error {
|
||||||
return hsdb.handlePrimarySubnetFailover()
|
return hsdb.handlePrimarySubnetFailover()
|
||||||
}
|
}
|
||||||
|
|
||||||
routes, err := hsdb.getMachineRoutes(&route.Machine)
|
routes, err := hsdb.getNodeRoutes(&route.Node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -194,8 +194,8 @@ func (hsdb *HSDatabase) DeleteRoute(id uint64) error {
|
||||||
return hsdb.handlePrimarySubnetFailover()
|
return hsdb.handlePrimarySubnetFailover()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hsdb *HSDatabase) deleteMachineRoutes(m *types.Machine) error {
|
func (hsdb *HSDatabase) deleteNodeRoutes(node *types.Node) error {
|
||||||
routes, err := hsdb.getMachineRoutes(m)
|
routes, err := hsdb.getNodeRoutes(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -209,14 +209,14 @@ func (hsdb *HSDatabase) deleteMachineRoutes(m *types.Machine) error {
|
||||||
return hsdb.handlePrimarySubnetFailover()
|
return hsdb.handlePrimarySubnetFailover()
|
||||||
}
|
}
|
||||||
|
|
||||||
// isUniquePrefix returns if there is another machine providing the same route already.
|
// isUniquePrefix returns if there is another node providing the same route already.
|
||||||
func (hsdb *HSDatabase) isUniquePrefix(route types.Route) bool {
|
func (hsdb *HSDatabase) isUniquePrefix(route types.Route) bool {
|
||||||
var count int64
|
var count int64
|
||||||
hsdb.db.
|
hsdb.db.
|
||||||
Model(&types.Route{}).
|
Model(&types.Route{}).
|
||||||
Where("prefix = ? AND machine_id != ? AND advertised = ? AND enabled = ?",
|
Where("prefix = ? AND node_id != ? AND advertised = ? AND enabled = ?",
|
||||||
route.Prefix,
|
route.Prefix,
|
||||||
route.MachineID,
|
route.NodeID,
|
||||||
true, true).Count(&count)
|
true, true).Count(&count)
|
||||||
|
|
||||||
return count == 0
|
return count == 0
|
||||||
|
@ -225,7 +225,7 @@ func (hsdb *HSDatabase) isUniquePrefix(route types.Route) bool {
|
||||||
func (hsdb *HSDatabase) getPrimaryRoute(prefix netip.Prefix) (*types.Route, error) {
|
func (hsdb *HSDatabase) getPrimaryRoute(prefix netip.Prefix) (*types.Route, error) {
|
||||||
var route types.Route
|
var route types.Route
|
||||||
err := hsdb.db.
|
err := hsdb.db.
|
||||||
Preload("Machine").
|
Preload("Node").
|
||||||
Where("prefix = ? AND advertised = ? AND enabled = ? AND is_primary = ?", types.IPPrefix(prefix), true, true, true).
|
Where("prefix = ? AND advertised = ? AND enabled = ? AND is_primary = ?", types.IPPrefix(prefix), true, true, true).
|
||||||
First(&route).Error
|
First(&route).Error
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
@ -239,16 +239,16 @@ func (hsdb *HSDatabase) getPrimaryRoute(prefix netip.Prefix) (*types.Route, erro
|
||||||
return &route, nil
|
return &route, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getMachinePrimaryRoutes returns the routes that are enabled and marked as primary (for subnet failover)
|
// getNodePrimaryRoutes returns the routes that are enabled and marked as primary (for subnet failover)
|
||||||
// Exit nodes are not considered for this, as they are never marked as Primary.
|
// Exit nodes are not considered for this, as they are never marked as Primary.
|
||||||
func (hsdb *HSDatabase) GetMachinePrimaryRoutes(machine *types.Machine) (types.Routes, error) {
|
func (hsdb *HSDatabase) GetNodePrimaryRoutes(node *types.Node) (types.Routes, error) {
|
||||||
hsdb.mu.RLock()
|
hsdb.mu.RLock()
|
||||||
defer hsdb.mu.RUnlock()
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
var routes types.Routes
|
var routes types.Routes
|
||||||
err := hsdb.db.
|
err := hsdb.db.
|
||||||
Preload("Machine").
|
Preload("Node").
|
||||||
Where("machine_id = ? AND advertised = ? AND enabled = ? AND is_primary = ?", machine.ID, true, true, true).
|
Where("node_id = ? AND advertised = ? AND enabled = ? AND is_primary = ?", node.ID, true, true, true).
|
||||||
Find(&routes).Error
|
Find(&routes).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -257,29 +257,29 @@ func (hsdb *HSDatabase) GetMachinePrimaryRoutes(machine *types.Machine) (types.R
|
||||||
return routes, nil
|
return routes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveMachineRoutes takes a machine and updates the database with
|
// SaveNodeRoutes takes a node and updates the database with
|
||||||
// the new routes.
|
// the new routes.
|
||||||
func (hsdb *HSDatabase) SaveMachineRoutes(machine *types.Machine) error {
|
func (hsdb *HSDatabase) SaveNodeRoutes(node *types.Node) error {
|
||||||
hsdb.mu.Lock()
|
hsdb.mu.Lock()
|
||||||
defer hsdb.mu.Unlock()
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
return hsdb.saveMachineRoutes(machine)
|
return hsdb.saveNodeRoutes(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hsdb *HSDatabase) saveMachineRoutes(machine *types.Machine) error {
|
func (hsdb *HSDatabase) saveNodeRoutes(node *types.Node) error {
|
||||||
currentRoutes := types.Routes{}
|
currentRoutes := types.Routes{}
|
||||||
err := hsdb.db.Where("machine_id = ?", machine.ID).Find(¤tRoutes).Error
|
err := hsdb.db.Where("node_id = ?", node.ID).Find(¤tRoutes).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
advertisedRoutes := map[netip.Prefix]bool{}
|
advertisedRoutes := map[netip.Prefix]bool{}
|
||||||
for _, prefix := range machine.HostInfo.RoutableIPs {
|
for _, prefix := range node.HostInfo.RoutableIPs {
|
||||||
advertisedRoutes[prefix] = false
|
advertisedRoutes[prefix] = false
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Interface("advertisedRoutes", advertisedRoutes).
|
Interface("advertisedRoutes", advertisedRoutes).
|
||||||
Interface("currentRoutes", currentRoutes).
|
Interface("currentRoutes", currentRoutes).
|
||||||
Msg("updating routes")
|
Msg("updating routes")
|
||||||
|
@ -307,7 +307,7 @@ func (hsdb *HSDatabase) saveMachineRoutes(machine *types.Machine) error {
|
||||||
for prefix, exists := range advertisedRoutes {
|
for prefix, exists := range advertisedRoutes {
|
||||||
if !exists {
|
if !exists {
|
||||||
route := types.Route{
|
route := types.Route{
|
||||||
MachineID: machine.ID,
|
NodeID: node.ID,
|
||||||
Prefix: types.IPPrefix(prefix),
|
Prefix: types.IPPrefix(prefix),
|
||||||
Advertised: true,
|
Advertised: true,
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
|
@ -333,27 +333,27 @@ func (hsdb *HSDatabase) handlePrimarySubnetFailover() error {
|
||||||
// first, get all the enabled routes
|
// first, get all the enabled routes
|
||||||
var routes types.Routes
|
var routes types.Routes
|
||||||
err := hsdb.db.
|
err := hsdb.db.
|
||||||
Preload("Machine").
|
Preload("Node").
|
||||||
Where("advertised = ? AND enabled = ?", true, true).
|
Where("advertised = ? AND enabled = ?", true, true).
|
||||||
Find(&routes).Error
|
Find(&routes).Error
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
log.Error().Err(err).Msg("error getting routes")
|
log.Error().Err(err).Msg("error getting routes")
|
||||||
}
|
}
|
||||||
|
|
||||||
changedMachines := make(types.Machines, 0)
|
changedNodes := make(types.Nodes, 0)
|
||||||
for pos, route := range routes {
|
for pos, route := range routes {
|
||||||
if route.IsExitRoute() {
|
if route.IsExitRoute() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
machine := &route.Machine
|
node := &route.Node
|
||||||
|
|
||||||
if !route.IsPrimary {
|
if !route.IsPrimary {
|
||||||
_, err := hsdb.getPrimaryRoute(netip.Prefix(route.Prefix))
|
_, err := hsdb.getPrimaryRoute(netip.Prefix(route.Prefix))
|
||||||
if hsdb.isUniquePrefix(route) || errors.Is(err, gorm.ErrRecordNotFound) {
|
if hsdb.isUniquePrefix(route) || errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
log.Info().
|
log.Info().
|
||||||
Str("prefix", netip.Prefix(route.Prefix).String()).
|
Str("prefix", netip.Prefix(route.Prefix).String()).
|
||||||
Str("machine", route.Machine.GivenName).
|
Str("node", route.Node.GivenName).
|
||||||
Msg("Setting primary route")
|
Msg("Setting primary route")
|
||||||
routes[pos].IsPrimary = true
|
routes[pos].IsPrimary = true
|
||||||
err := hsdb.db.Save(&routes[pos]).Error
|
err := hsdb.db.Save(&routes[pos]).Error
|
||||||
|
@ -363,30 +363,30 @@ func (hsdb *HSDatabase) handlePrimarySubnetFailover() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
changedMachines = append(changedMachines, machine)
|
changedNodes = append(changedNodes, node)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if route.IsPrimary {
|
if route.IsPrimary {
|
||||||
if route.Machine.IsOnline() {
|
if route.Node.IsOnline() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// machine offline, find a new primary
|
// node offline, find a new primary
|
||||||
log.Info().
|
log.Info().
|
||||||
Str("machine", route.Machine.Hostname).
|
Str("node", route.Node.Hostname).
|
||||||
Str("prefix", netip.Prefix(route.Prefix).String()).
|
Str("prefix", netip.Prefix(route.Prefix).String()).
|
||||||
Msgf("machine offline, finding a new primary subnet")
|
Msgf("node offline, finding a new primary subnet")
|
||||||
|
|
||||||
// find a new primary route
|
// find a new primary route
|
||||||
var newPrimaryRoutes types.Routes
|
var newPrimaryRoutes types.Routes
|
||||||
err := hsdb.db.
|
err := hsdb.db.
|
||||||
Preload("Machine").
|
Preload("Node").
|
||||||
Where("prefix = ? AND machine_id != ? AND advertised = ? AND enabled = ?",
|
Where("prefix = ? AND node_id != ? AND advertised = ? AND enabled = ?",
|
||||||
route.Prefix,
|
route.Prefix,
|
||||||
route.MachineID,
|
route.NodeID,
|
||||||
true, true).
|
true, true).
|
||||||
Find(&newPrimaryRoutes).Error
|
Find(&newPrimaryRoutes).Error
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
@ -397,7 +397,7 @@ func (hsdb *HSDatabase) handlePrimarySubnetFailover() error {
|
||||||
|
|
||||||
var newPrimaryRoute *types.Route
|
var newPrimaryRoute *types.Route
|
||||||
for pos, r := range newPrimaryRoutes {
|
for pos, r := range newPrimaryRoutes {
|
||||||
if r.Machine.IsOnline() {
|
if r.Node.IsOnline() {
|
||||||
newPrimaryRoute = &newPrimaryRoutes[pos]
|
newPrimaryRoute = &newPrimaryRoutes[pos]
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -406,7 +406,7 @@ func (hsdb *HSDatabase) handlePrimarySubnetFailover() error {
|
||||||
|
|
||||||
if newPrimaryRoute == nil {
|
if newPrimaryRoute == nil {
|
||||||
log.Warn().
|
log.Warn().
|
||||||
Str("machine", route.Machine.Hostname).
|
Str("node", route.Node.Hostname).
|
||||||
Str("prefix", netip.Prefix(route.Prefix).String()).
|
Str("prefix", netip.Prefix(route.Prefix).String()).
|
||||||
Msgf("no alternative primary route found")
|
Msgf("no alternative primary route found")
|
||||||
|
|
||||||
|
@ -414,9 +414,9 @@ func (hsdb *HSDatabase) handlePrimarySubnetFailover() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().
|
log.Info().
|
||||||
Str("old_machine", route.Machine.Hostname).
|
Str("old_node", route.Node.Hostname).
|
||||||
Str("prefix", netip.Prefix(route.Prefix).String()).
|
Str("prefix", netip.Prefix(route.Prefix).String()).
|
||||||
Str("new_machine", newPrimaryRoute.Machine.Hostname).
|
Str("new_node", newPrimaryRoute.Node.Hostname).
|
||||||
Msgf("found new primary route")
|
Msgf("found new primary route")
|
||||||
|
|
||||||
// disable the old primary route
|
// disable the old primary route
|
||||||
|
@ -437,39 +437,39 @@ func (hsdb *HSDatabase) handlePrimarySubnetFailover() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
changedMachines = append(changedMachines, machine)
|
changedNodes = append(changedNodes, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(changedMachines) > 0 {
|
if len(changedNodes) > 0 {
|
||||||
hsdb.notifier.NotifyAll(types.StateUpdate{
|
hsdb.notifier.NotifyAll(types.StateUpdate{
|
||||||
Type: types.StatePeerChanged,
|
Type: types.StatePeerChanged,
|
||||||
Changed: changedMachines,
|
Changed: changedNodes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableAutoApprovedRoutes enables any routes advertised by a machine that match the ACL autoApprovers policy.
|
// EnableAutoApprovedRoutes enables any routes advertised by a node that match the ACL autoApprovers policy.
|
||||||
func (hsdb *HSDatabase) EnableAutoApprovedRoutes(
|
func (hsdb *HSDatabase) EnableAutoApprovedRoutes(
|
||||||
aclPolicy *policy.ACLPolicy,
|
aclPolicy *policy.ACLPolicy,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
) error {
|
) error {
|
||||||
hsdb.mu.Lock()
|
hsdb.mu.Lock()
|
||||||
defer hsdb.mu.Unlock()
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
if len(machine.IPAddresses) == 0 {
|
if len(node.IPAddresses) == 0 {
|
||||||
return nil // This machine has no IPAddresses, so can't possibly match any autoApprovers ACLs
|
return nil // This node has no IPAddresses, so can't possibly match any autoApprovers ACLs
|
||||||
}
|
}
|
||||||
|
|
||||||
routes, err := hsdb.getMachineAdvertisedRoutes(machine)
|
routes, err := hsdb.getNodeAdvertisedRoutes(node)
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
Err(err).
|
Err(err).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("Could not get advertised routes for machine")
|
Msg("Could not get advertised routes for node")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -487,18 +487,18 @@ func (hsdb *HSDatabase) EnableAutoApprovedRoutes(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).
|
log.Err(err).
|
||||||
Str("advertisedRoute", advertisedRoute.String()).
|
Str("advertisedRoute", advertisedRoute.String()).
|
||||||
Uint64("machineId", machine.ID).
|
Uint64("nodeId", node.ID).
|
||||||
Msg("Failed to resolve autoApprovers for advertised route")
|
Msg("Failed to resolve autoApprovers for advertised route")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, approvedAlias := range routeApprovers {
|
for _, approvedAlias := range routeApprovers {
|
||||||
if approvedAlias == machine.User.Name {
|
if approvedAlias == node.User.Name {
|
||||||
approvedRoutes = append(approvedRoutes, advertisedRoute)
|
approvedRoutes = append(approvedRoutes, advertisedRoute)
|
||||||
} else {
|
} else {
|
||||||
// TODO(kradalby): figure out how to get this to depend on less stuff
|
// TODO(kradalby): figure out how to get this to depend on less stuff
|
||||||
approvedIps, err := aclPolicy.ExpandAlias(types.Machines{machine}, approvedAlias)
|
approvedIps, err := aclPolicy.ExpandAlias(types.Nodes{node}, approvedAlias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).
|
log.Err(err).
|
||||||
Str("alias", approvedAlias).
|
Str("alias", approvedAlias).
|
||||||
|
@ -507,8 +507,8 @@ func (hsdb *HSDatabase) EnableAutoApprovedRoutes(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// approvedIPs should contain all of machine's IPs if it matches the rule, so check for first
|
// approvedIPs should contain all of node's IPs if it matches the rule, so check for first
|
||||||
if approvedIps.Contains(machine.IPAddresses[0]) {
|
if approvedIps.Contains(node.IPAddresses[0]) {
|
||||||
approvedRoutes = append(approvedRoutes, advertisedRoute)
|
approvedRoutes = append(approvedRoutes, advertisedRoute)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -520,7 +520,7 @@ func (hsdb *HSDatabase) EnableAutoApprovedRoutes(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).
|
log.Err(err).
|
||||||
Str("approvedRoute", approvedRoute.String()).
|
Str("approvedRoute", approvedRoute.String()).
|
||||||
Uint64("machineId", machine.ID).
|
Uint64("nodeId", node.ID).
|
||||||
Msg("Failed to enable approved route")
|
Msg("Failed to enable approved route")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -17,7 +17,7 @@ func (s *Suite) TestGetRoutes(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "test_get_route_machine")
|
_, err = db.GetNode("test", "test_get_route_node")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
route, err := netip.ParsePrefix("10.0.0.0/24")
|
route, err := netip.ParsePrefix("10.0.0.0/24")
|
||||||
|
@ -27,30 +27,30 @@ func (s *Suite) TestGetRoutes(c *check.C) {
|
||||||
RoutableIPs: []netip.Prefix{route},
|
RoutableIPs: []netip.Prefix{route},
|
||||||
}
|
}
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "test_get_route_machine",
|
Hostname: "test_get_route_node",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
HostInfo: types.HostInfo(hostInfo),
|
HostInfo: types.HostInfo(hostInfo),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
err = db.SaveMachineRoutes(&machine)
|
err = db.SaveNodeRoutes(&node)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
advertisedRoutes, err := db.GetAdvertisedRoutes(&machine)
|
advertisedRoutes, err := db.GetAdvertisedRoutes(&node)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(advertisedRoutes), check.Equals, 1)
|
c.Assert(len(advertisedRoutes), check.Equals, 1)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine, "192.168.0.0/24")
|
err = db.enableRoutes(&node, "192.168.0.0/24")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine, "10.0.0.0/24")
|
err = db.enableRoutes(&node, "10.0.0.0/24")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ func (s *Suite) TestGetEnableRoutes(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "test_enable_route_machine")
|
_, err = db.GetNode("test", "test_enable_route_node")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
route, err := netip.ParsePrefix(
|
route, err := netip.ParsePrefix(
|
||||||
|
@ -78,53 +78,53 @@ func (s *Suite) TestGetEnableRoutes(c *check.C) {
|
||||||
RoutableIPs: []netip.Prefix{route, route2},
|
RoutableIPs: []netip.Prefix{route, route2},
|
||||||
}
|
}
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "test_enable_route_machine",
|
Hostname: "test_enable_route_node",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
HostInfo: types.HostInfo(hostInfo),
|
HostInfo: types.HostInfo(hostInfo),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
err = db.SaveMachineRoutes(&machine)
|
err = db.SaveNodeRoutes(&node)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
availableRoutes, err := db.GetAdvertisedRoutes(&machine)
|
availableRoutes, err := db.GetAdvertisedRoutes(&node)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(availableRoutes), check.Equals, 2)
|
c.Assert(len(availableRoutes), check.Equals, 2)
|
||||||
|
|
||||||
noEnabledRoutes, err := db.GetEnabledRoutes(&machine)
|
noEnabledRoutes, err := db.GetEnabledRoutes(&node)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(noEnabledRoutes), check.Equals, 0)
|
c.Assert(len(noEnabledRoutes), check.Equals, 0)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine, "192.168.0.0/24")
|
err = db.enableRoutes(&node, "192.168.0.0/24")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine, "10.0.0.0/24")
|
err = db.enableRoutes(&node, "10.0.0.0/24")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enabledRoutes, err := db.GetEnabledRoutes(&machine)
|
enabledRoutes, err := db.GetEnabledRoutes(&node)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(enabledRoutes), check.Equals, 1)
|
c.Assert(len(enabledRoutes), check.Equals, 1)
|
||||||
|
|
||||||
// Adding it twice will just let it pass through
|
// Adding it twice will just let it pass through
|
||||||
err = db.enableRoutes(&machine, "10.0.0.0/24")
|
err = db.enableRoutes(&node, "10.0.0.0/24")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enableRoutesAfterDoubleApply, err := db.GetEnabledRoutes(&machine)
|
enableRoutesAfterDoubleApply, err := db.GetEnabledRoutes(&node)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(enableRoutesAfterDoubleApply), check.Equals, 1)
|
c.Assert(len(enableRoutesAfterDoubleApply), check.Equals, 1)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine, "150.0.10.0/25")
|
err = db.enableRoutes(&node, "150.0.10.0/25")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enabledRoutesWithAdditionalRoute, err := db.GetEnabledRoutes(&machine)
|
enabledRoutesWithAdditionalRoute, err := db.GetEnabledRoutes(&node)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(enabledRoutesWithAdditionalRoute), check.Equals, 2)
|
c.Assert(len(enabledRoutesWithAdditionalRoute), check.Equals, 2)
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ func (s *Suite) TestIsUniquePrefix(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "test_enable_route_machine")
|
_, err = db.GetNode("test", "test_enable_route_node")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
route, err := netip.ParsePrefix(
|
route, err := netip.ParsePrefix(
|
||||||
|
@ -152,63 +152,63 @@ func (s *Suite) TestIsUniquePrefix(c *check.C) {
|
||||||
hostInfo1 := tailcfg.Hostinfo{
|
hostInfo1 := tailcfg.Hostinfo{
|
||||||
RoutableIPs: []netip.Prefix{route, route2},
|
RoutableIPs: []netip.Prefix{route, route2},
|
||||||
}
|
}
|
||||||
machine1 := types.Machine{
|
node1 := types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "test_enable_route_machine",
|
Hostname: "test_enable_route_node",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
HostInfo: types.HostInfo(hostInfo1),
|
HostInfo: types.HostInfo(hostInfo1),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine1)
|
db.db.Save(&node1)
|
||||||
|
|
||||||
err = db.SaveMachineRoutes(&machine1)
|
err = db.SaveNodeRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine1, route.String())
|
err = db.enableRoutes(&node1, route.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine1, route2.String())
|
err = db.enableRoutes(&node1, route2.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
hostInfo2 := tailcfg.Hostinfo{
|
hostInfo2 := tailcfg.Hostinfo{
|
||||||
RoutableIPs: []netip.Prefix{route2},
|
RoutableIPs: []netip.Prefix{route2},
|
||||||
}
|
}
|
||||||
machine2 := types.Machine{
|
node2 := types.Node{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "test_enable_route_machine",
|
Hostname: "test_enable_route_node",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
HostInfo: types.HostInfo(hostInfo2),
|
HostInfo: types.HostInfo(hostInfo2),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine2)
|
db.db.Save(&node2)
|
||||||
|
|
||||||
err = db.SaveMachineRoutes(&machine2)
|
err = db.SaveNodeRoutes(&node2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine2, route2.String())
|
err = db.enableRoutes(&node2, route2.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enabledRoutes1, err := db.GetEnabledRoutes(&machine1)
|
enabledRoutes1, err := db.GetEnabledRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(enabledRoutes1), check.Equals, 2)
|
c.Assert(len(enabledRoutes1), check.Equals, 2)
|
||||||
|
|
||||||
enabledRoutes2, err := db.GetEnabledRoutes(&machine2)
|
enabledRoutes2, err := db.GetEnabledRoutes(&node2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(enabledRoutes2), check.Equals, 1)
|
c.Assert(len(enabledRoutes2), check.Equals, 1)
|
||||||
|
|
||||||
routes, err := db.GetMachinePrimaryRoutes(&machine1)
|
routes, err := db.GetNodePrimaryRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(routes), check.Equals, 2)
|
c.Assert(len(routes), check.Equals, 2)
|
||||||
|
|
||||||
routes, err = db.GetMachinePrimaryRoutes(&machine2)
|
routes, err = db.GetNodePrimaryRoutes(&node2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(routes), check.Equals, 0)
|
c.Assert(len(routes), check.Equals, 0)
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ func (s *Suite) TestSubnetFailover(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "test_enable_route_machine")
|
_, err = db.GetNode("test", "test_enable_route_node")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
prefix, err := netip.ParsePrefix(
|
prefix, err := netip.ParsePrefix(
|
||||||
|
@ -238,119 +238,119 @@ func (s *Suite) TestSubnetFailover(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
machine1 := types.Machine{
|
node1 := types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "test_enable_route_machine",
|
Hostname: "test_enable_route_node",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
HostInfo: types.HostInfo(hostInfo1),
|
HostInfo: types.HostInfo(hostInfo1),
|
||||||
LastSeen: &now,
|
LastSeen: &now,
|
||||||
}
|
}
|
||||||
db.db.Save(&machine1)
|
db.db.Save(&node1)
|
||||||
|
|
||||||
err = db.SaveMachineRoutes(&machine1)
|
err = db.SaveNodeRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine1, prefix.String())
|
err = db.enableRoutes(&node1, prefix.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine1, prefix2.String())
|
err = db.enableRoutes(&node1, prefix2.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.HandlePrimarySubnetFailover()
|
err = db.HandlePrimarySubnetFailover()
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enabledRoutes1, err := db.GetEnabledRoutes(&machine1)
|
enabledRoutes1, err := db.GetEnabledRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(enabledRoutes1), check.Equals, 2)
|
c.Assert(len(enabledRoutes1), check.Equals, 2)
|
||||||
|
|
||||||
route, err := db.getPrimaryRoute(prefix)
|
route, err := db.getPrimaryRoute(prefix)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(route.MachineID, check.Equals, machine1.ID)
|
c.Assert(route.NodeID, check.Equals, node1.ID)
|
||||||
|
|
||||||
hostInfo2 := tailcfg.Hostinfo{
|
hostInfo2 := tailcfg.Hostinfo{
|
||||||
RoutableIPs: []netip.Prefix{prefix2},
|
RoutableIPs: []netip.Prefix{prefix2},
|
||||||
}
|
}
|
||||||
machine2 := types.Machine{
|
node2 := types.Node{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "test_enable_route_machine",
|
Hostname: "test_enable_route_node",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
HostInfo: types.HostInfo(hostInfo2),
|
HostInfo: types.HostInfo(hostInfo2),
|
||||||
LastSeen: &now,
|
LastSeen: &now,
|
||||||
}
|
}
|
||||||
db.db.Save(&machine2)
|
db.db.Save(&node2)
|
||||||
|
|
||||||
err = db.SaveMachineRoutes(&machine2)
|
err = db.saveNodeRoutes(&node2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine2, prefix2.String())
|
err = db.enableRoutes(&node2, prefix2.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.HandlePrimarySubnetFailover()
|
err = db.HandlePrimarySubnetFailover()
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enabledRoutes1, err = db.GetEnabledRoutes(&machine1)
|
enabledRoutes1, err = db.GetEnabledRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(enabledRoutes1), check.Equals, 2)
|
c.Assert(len(enabledRoutes1), check.Equals, 2)
|
||||||
|
|
||||||
enabledRoutes2, err := db.GetEnabledRoutes(&machine2)
|
enabledRoutes2, err := db.GetEnabledRoutes(&node2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(enabledRoutes2), check.Equals, 1)
|
c.Assert(len(enabledRoutes2), check.Equals, 1)
|
||||||
|
|
||||||
routes, err := db.GetMachinePrimaryRoutes(&machine1)
|
routes, err := db.GetNodePrimaryRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(routes), check.Equals, 2)
|
c.Assert(len(routes), check.Equals, 2)
|
||||||
|
|
||||||
routes, err = db.GetMachinePrimaryRoutes(&machine2)
|
routes, err = db.GetNodePrimaryRoutes(&node2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(routes), check.Equals, 0)
|
c.Assert(len(routes), check.Equals, 0)
|
||||||
|
|
||||||
// lets make machine1 lastseen 10 mins ago
|
// lets make node1 lastseen 10 mins ago
|
||||||
before := now.Add(-10 * time.Minute)
|
before := now.Add(-10 * time.Minute)
|
||||||
machine1.LastSeen = &before
|
node1.LastSeen = &before
|
||||||
err = db.db.Save(&machine1).Error
|
err = db.db.Save(&node1).Error
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.HandlePrimarySubnetFailover()
|
err = db.HandlePrimarySubnetFailover()
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
routes, err = db.GetMachinePrimaryRoutes(&machine1)
|
routes, err = db.GetNodePrimaryRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(routes), check.Equals, 1)
|
c.Assert(len(routes), check.Equals, 1)
|
||||||
|
|
||||||
routes, err = db.GetMachinePrimaryRoutes(&machine2)
|
routes, err = db.GetNodePrimaryRoutes(&node2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(routes), check.Equals, 1)
|
c.Assert(len(routes), check.Equals, 1)
|
||||||
|
|
||||||
machine2.HostInfo = types.HostInfo(tailcfg.Hostinfo{
|
node2.HostInfo = types.HostInfo(tailcfg.Hostinfo{
|
||||||
RoutableIPs: []netip.Prefix{prefix, prefix2},
|
RoutableIPs: []netip.Prefix{prefix, prefix2},
|
||||||
})
|
})
|
||||||
err = db.db.Save(&machine2).Error
|
err = db.db.Save(&node2).Error
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.SaveMachineRoutes(&machine2)
|
err = db.SaveNodeRoutes(&node2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine2, prefix.String())
|
err = db.enableRoutes(&node2, prefix.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.HandlePrimarySubnetFailover()
|
err = db.HandlePrimarySubnetFailover()
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
routes, err = db.GetMachinePrimaryRoutes(&machine1)
|
routes, err = db.GetNodePrimaryRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(routes), check.Equals, 0)
|
c.Assert(len(routes), check.Equals, 0)
|
||||||
|
|
||||||
routes, err = db.GetMachinePrimaryRoutes(&machine2)
|
routes, err = db.GetNodePrimaryRoutes(&node2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(routes), check.Equals, 2)
|
c.Assert(len(routes), check.Equals, 2)
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ func (s *Suite) TestDeleteRoutes(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
_, err = db.GetMachine("test", "test_enable_route_machine")
|
_, err = db.GetNode("test", "test_enable_route_node")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
prefix, err := netip.ParsePrefix(
|
prefix, err := netip.ParsePrefix(
|
||||||
|
@ -380,36 +380,36 @@ func (s *Suite) TestDeleteRoutes(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
machine1 := types.Machine{
|
node1 := types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "test_enable_route_machine",
|
Hostname: "test_enable_route_node",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
HostInfo: types.HostInfo(hostInfo1),
|
HostInfo: types.HostInfo(hostInfo1),
|
||||||
LastSeen: &now,
|
LastSeen: &now,
|
||||||
}
|
}
|
||||||
db.db.Save(&machine1)
|
db.db.Save(&node1)
|
||||||
|
|
||||||
err = db.SaveMachineRoutes(&machine1)
|
err = db.SaveNodeRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine1, prefix.String())
|
err = db.enableRoutes(&node1, prefix.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.enableRoutes(&machine1, prefix2.String())
|
err = db.enableRoutes(&node1, prefix2.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
routes, err := db.GetMachineRoutes(&machine1)
|
routes, err := db.GetNodeRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = db.DeleteRoute(uint64(routes[0].ID))
|
err = db.DeleteRoute(uint64(routes[0].ID))
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enabledRoutes1, err := db.GetEnabledRoutes(&machine1)
|
enabledRoutes1, err := db.GetEnabledRoutes(&node1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(enabledRoutes1), check.Equals, 1)
|
c.Assert(len(enabledRoutes1), check.Equals, 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ func (hsdb *HSDatabase) CreateUser(name string) (*types.User, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DestroyUser destroys a User. Returns error if the User does
|
// DestroyUser destroys a User. Returns error if the User does
|
||||||
// not exist or if there are machines associated with it.
|
// not exist or if there are nodes associated with it.
|
||||||
func (hsdb *HSDatabase) DestroyUser(name string) error {
|
func (hsdb *HSDatabase) DestroyUser(name string) error {
|
||||||
hsdb.mu.Lock()
|
hsdb.mu.Lock()
|
||||||
defer hsdb.mu.Unlock()
|
defer hsdb.mu.Unlock()
|
||||||
|
@ -53,11 +53,11 @@ func (hsdb *HSDatabase) DestroyUser(name string) error {
|
||||||
return ErrUserNotFound
|
return ErrUserNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
machines, err := hsdb.listMachinesByUser(name)
|
nodes, err := hsdb.listNodesByUser(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(machines) > 0 {
|
if len(nodes) > 0 {
|
||||||
return ErrUserStillHasNodes
|
return ErrUserStillHasNodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,15 +148,15 @@ func (hsdb *HSDatabase) listUsers() ([]types.User, error) {
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListMachinesByUser gets all the nodes in a given user.
|
// ListNodesByUser gets all the nodes in a given user.
|
||||||
func (hsdb *HSDatabase) ListMachinesByUser(name string) (types.Machines, error) {
|
func (hsdb *HSDatabase) ListNodesByUser(name string) (types.Nodes, error) {
|
||||||
hsdb.mu.RLock()
|
hsdb.mu.RLock()
|
||||||
defer hsdb.mu.RUnlock()
|
defer hsdb.mu.RUnlock()
|
||||||
|
|
||||||
return hsdb.listMachinesByUser(name)
|
return hsdb.listNodesByUser(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hsdb *HSDatabase) listMachinesByUser(name string) (types.Machines, error) {
|
func (hsdb *HSDatabase) listNodesByUser(name string) (types.Nodes, error) {
|
||||||
err := util.CheckForFQDNRules(name)
|
err := util.CheckForFQDNRules(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -166,16 +166,16 @@ func (hsdb *HSDatabase) listMachinesByUser(name string) (types.Machines, error)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
machines := types.Machines{}
|
nodes := types.Nodes{}
|
||||||
if err := hsdb.db.Preload("AuthKey").Preload("AuthKey.User").Preload("User").Where(&types.Machine{UserID: user.ID}).Find(&machines).Error; err != nil {
|
if err := hsdb.db.Preload("AuthKey").Preload("AuthKey.User").Preload("User").Where(&types.Node{UserID: user.ID}).Find(&nodes).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return machines, nil
|
return nodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssignMachineToUser assigns a Machine to a user.
|
// AssignNodeToUser assigns a Node to a user.
|
||||||
func (hsdb *HSDatabase) AssignMachineToUser(machine *types.Machine, username string) error {
|
func (hsdb *HSDatabase) AssignNodeToUser(node *types.Node, username string) error {
|
||||||
hsdb.mu.Lock()
|
hsdb.mu.Lock()
|
||||||
defer hsdb.mu.Unlock()
|
defer hsdb.mu.Unlock()
|
||||||
|
|
||||||
|
@ -187,8 +187,8 @@ func (hsdb *HSDatabase) AssignMachineToUser(machine *types.Machine, username str
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
machine.User = *user
|
node.User = *user
|
||||||
if result := hsdb.db.Save(&machine); result.Error != nil {
|
if result := hsdb.db.Save(&node); result.Error != nil {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,17 +46,17 @@ func (s *Suite) TestDestroyUserErrors(c *check.C) {
|
||||||
pak, err = db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err = db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
|
|
||||||
err = db.DestroyUser("test")
|
err = db.DestroyUser("test")
|
||||||
c.Assert(err, check.Equals, ErrUserStillHasNodes)
|
c.Assert(err, check.Equals, ErrUserStillHasNodes)
|
||||||
|
@ -101,29 +101,29 @@ func (s *Suite) TestSetMachineUser(c *check.C) {
|
||||||
pak, err := db.CreatePreAuthKey(oldUser.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(oldUser.Name, false, false, nil, nil)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
machine := types.Machine{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testnode",
|
||||||
UserID: oldUser.ID,
|
UserID: oldUser.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
}
|
}
|
||||||
db.db.Save(&machine)
|
db.db.Save(&node)
|
||||||
c.Assert(machine.UserID, check.Equals, oldUser.ID)
|
c.Assert(node.UserID, check.Equals, oldUser.ID)
|
||||||
|
|
||||||
err = db.AssignMachineToUser(&machine, newUser.Name)
|
err = db.AssignNodeToUser(&node, newUser.Name)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(machine.UserID, check.Equals, newUser.ID)
|
c.Assert(node.UserID, check.Equals, newUser.ID)
|
||||||
c.Assert(machine.User.Name, check.Equals, newUser.Name)
|
c.Assert(node.User.Name, check.Equals, newUser.Name)
|
||||||
|
|
||||||
err = db.AssignMachineToUser(&machine, "non-existing-user")
|
err = db.AssignNodeToUser(&node, "non-existing-user")
|
||||||
c.Assert(err, check.Equals, ErrUserNotFound)
|
c.Assert(err, check.Equals, ErrUserNotFound)
|
||||||
|
|
||||||
err = db.AssignMachineToUser(&machine, newUser.Name)
|
err = db.AssignNodeToUser(&node, newUser.Name)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(machine.UserID, check.Equals, newUser.ID)
|
c.Assert(node.UserID, check.Equals, newUser.ID)
|
||||||
c.Assert(machine.User.Name, check.Equals, newUser.Name)
|
c.Assert(node.User.Name, check.Equals, newUser.Name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,16 +166,16 @@ func (api headscaleV1APIServer) ListPreAuthKeys(
|
||||||
return &v1.ListPreAuthKeysResponse{PreAuthKeys: response}, nil
|
return &v1.ListPreAuthKeysResponse{PreAuthKeys: response}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) RegisterMachine(
|
func (api headscaleV1APIServer) RegisterNode(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *v1.RegisterMachineRequest,
|
request *v1.RegisterNodeRequest,
|
||||||
) (*v1.RegisterMachineResponse, error) {
|
) (*v1.RegisterNodeResponse, error) {
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Str("user", request.GetUser()).
|
Str("user", request.GetUser()).
|
||||||
Str("node_key", request.GetKey()).
|
Str("node_key", request.GetKey()).
|
||||||
Msg("Registering machine")
|
Msg("Registering node")
|
||||||
|
|
||||||
machine, err := api.h.db.RegisterMachineFromAuthCallback(
|
node, err := api.h.db.RegisterNodeFromAuthCallback(
|
||||||
api.h.registrationCache,
|
api.h.registrationCache,
|
||||||
request.GetKey(),
|
request.GetKey(),
|
||||||
request.GetUser(),
|
request.GetUser(),
|
||||||
|
@ -186,26 +186,26 @@ func (api headscaleV1APIServer) RegisterMachine(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v1.RegisterMachineResponse{Machine: machine.Proto()}, nil
|
return &v1.RegisterNodeResponse{Node: node.Proto()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) GetMachine(
|
func (api headscaleV1APIServer) GetNode(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *v1.GetMachineRequest,
|
request *v1.GetNodeRequest,
|
||||||
) (*v1.GetMachineResponse, error) {
|
) (*v1.GetNodeResponse, error) {
|
||||||
machine, err := api.h.db.GetMachineByID(request.GetMachineId())
|
node, err := api.h.db.GetNodeByID(request.GetNodeId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v1.GetMachineResponse{Machine: machine.Proto()}, nil
|
return &v1.GetNodeResponse{Node: node.Proto()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) SetTags(
|
func (api headscaleV1APIServer) SetTags(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *v1.SetTagsRequest,
|
request *v1.SetTagsRequest,
|
||||||
) (*v1.SetTagsResponse, error) {
|
) (*v1.SetTagsResponse, error) {
|
||||||
machine, err := api.h.db.GetMachineByID(request.GetMachineId())
|
node, err := api.h.db.GetNodeByID(request.GetNodeId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -214,24 +214,24 @@ func (api headscaleV1APIServer) SetTags(
|
||||||
err := validateTag(tag)
|
err := validateTag(tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &v1.SetTagsResponse{
|
return &v1.SetTagsResponse{
|
||||||
Machine: nil,
|
Node: nil,
|
||||||
}, status.Error(codes.InvalidArgument, err.Error())
|
}, status.Error(codes.InvalidArgument, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = api.h.db.SetTags(machine, request.GetTags())
|
err = api.h.db.SetTags(node, request.GetTags())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &v1.SetTagsResponse{
|
return &v1.SetTagsResponse{
|
||||||
Machine: nil,
|
Node: nil,
|
||||||
}, status.Error(codes.Internal, err.Error())
|
}, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Strs("tags", request.GetTags()).
|
Strs("tags", request.GetTags()).
|
||||||
Msg("Changing tags of machine")
|
Msg("Changing tags of node")
|
||||||
|
|
||||||
return &v1.SetTagsResponse{Machine: machine.Proto()}, nil
|
return &v1.SetTagsResponse{Node: node.Proto()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateTag(tag string) error {
|
func validateTag(tag string) error {
|
||||||
|
@ -247,60 +247,60 @@ func validateTag(tag string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) DeleteMachine(
|
func (api headscaleV1APIServer) DeleteNode(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *v1.DeleteMachineRequest,
|
request *v1.DeleteNodeRequest,
|
||||||
) (*v1.DeleteMachineResponse, error) {
|
) (*v1.DeleteNodeResponse, error) {
|
||||||
machine, err := api.h.db.GetMachineByID(request.GetMachineId())
|
node, err := api.h.db.GetNodeByID(request.GetNodeId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = api.h.db.DeleteMachine(
|
err = api.h.db.DeleteNode(
|
||||||
machine,
|
node,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v1.DeleteMachineResponse{}, nil
|
return &v1.DeleteNodeResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) ExpireMachine(
|
func (api headscaleV1APIServer) ExpireNode(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *v1.ExpireMachineRequest,
|
request *v1.ExpireNodeRequest,
|
||||||
) (*v1.ExpireMachineResponse, error) {
|
) (*v1.ExpireNodeResponse, error) {
|
||||||
machine, err := api.h.db.GetMachineByID(request.GetMachineId())
|
node, err := api.h.db.GetNodeByID(request.GetNodeId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
api.h.db.MachineSetExpiry(
|
api.h.db.NodeSetExpiry(
|
||||||
machine,
|
node,
|
||||||
now,
|
now,
|
||||||
)
|
)
|
||||||
|
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Time("expiry", *machine.Expiry).
|
Time("expiry", *node.Expiry).
|
||||||
Msg("machine expired")
|
Msg("node expired")
|
||||||
|
|
||||||
return &v1.ExpireMachineResponse{Machine: machine.Proto()}, nil
|
return &v1.ExpireNodeResponse{Node: node.Proto()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) RenameMachine(
|
func (api headscaleV1APIServer) RenameNode(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *v1.RenameMachineRequest,
|
request *v1.RenameNodeRequest,
|
||||||
) (*v1.RenameMachineResponse, error) {
|
) (*v1.RenameNodeResponse, error) {
|
||||||
machine, err := api.h.db.GetMachineByID(request.GetMachineId())
|
node, err := api.h.db.GetNodeByID(request.GetNodeId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = api.h.db.RenameMachine(
|
err = api.h.db.RenameNode(
|
||||||
machine,
|
node,
|
||||||
request.GetNewName(),
|
request.GetNewName(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -308,65 +308,65 @@ func (api headscaleV1APIServer) RenameMachine(
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Str("new_name", request.GetNewName()).
|
Str("new_name", request.GetNewName()).
|
||||||
Msg("machine renamed")
|
Msg("node renamed")
|
||||||
|
|
||||||
return &v1.RenameMachineResponse{Machine: machine.Proto()}, nil
|
return &v1.RenameNodeResponse{Node: node.Proto()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) ListMachines(
|
func (api headscaleV1APIServer) ListNodes(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *v1.ListMachinesRequest,
|
request *v1.ListNodesRequest,
|
||||||
) (*v1.ListMachinesResponse, error) {
|
) (*v1.ListNodesResponse, error) {
|
||||||
if request.GetUser() != "" {
|
if request.GetUser() != "" {
|
||||||
machines, err := api.h.db.ListMachinesByUser(request.GetUser())
|
nodes, err := api.h.db.ListNodesByUser(request.GetUser())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response := make([]*v1.Machine, len(machines))
|
response := make([]*v1.Node, len(nodes))
|
||||||
for index, machine := range machines {
|
for index, node := range nodes {
|
||||||
response[index] = machine.Proto()
|
response[index] = node.Proto()
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v1.ListMachinesResponse{Machines: response}, nil
|
return &v1.ListNodesResponse{Nodes: response}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
machines, err := api.h.db.ListMachines()
|
nodes, err := api.h.db.ListNodes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response := make([]*v1.Machine, len(machines))
|
response := make([]*v1.Node, len(nodes))
|
||||||
for index, machine := range machines {
|
for index, node := range nodes {
|
||||||
m := machine.Proto()
|
m := node.Proto()
|
||||||
validTags, invalidTags := api.h.ACLPolicy.TagsOfMachine(
|
validTags, invalidTags := api.h.ACLPolicy.TagsOfNode(
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
m.InvalidTags = invalidTags
|
m.InvalidTags = invalidTags
|
||||||
m.ValidTags = validTags
|
m.ValidTags = validTags
|
||||||
response[index] = m
|
response[index] = m
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v1.ListMachinesResponse{Machines: response}, nil
|
return &v1.ListNodesResponse{Nodes: response}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) MoveMachine(
|
func (api headscaleV1APIServer) MoveNode(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *v1.MoveMachineRequest,
|
request *v1.MoveNodeRequest,
|
||||||
) (*v1.MoveMachineResponse, error) {
|
) (*v1.MoveNodeResponse, error) {
|
||||||
machine, err := api.h.db.GetMachineByID(request.GetMachineId())
|
node, err := api.h.db.GetNodeByID(request.GetNodeId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = api.h.db.AssignMachineToUser(machine, request.GetUser())
|
err = api.h.db.AssignNodeToUser(node, request.GetUser())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v1.MoveMachineResponse{Machine: machine.Proto()}, nil
|
return &v1.MoveNodeResponse{Node: node.Proto()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) GetRoutes(
|
func (api headscaleV1APIServer) GetRoutes(
|
||||||
|
@ -407,21 +407,21 @@ func (api headscaleV1APIServer) DisableRoute(
|
||||||
return &v1.DisableRouteResponse{}, nil
|
return &v1.DisableRouteResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) GetMachineRoutes(
|
func (api headscaleV1APIServer) GetNodeRoutes(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *v1.GetMachineRoutesRequest,
|
request *v1.GetNodeRoutesRequest,
|
||||||
) (*v1.GetMachineRoutesResponse, error) {
|
) (*v1.GetNodeRoutesResponse, error) {
|
||||||
machine, err := api.h.db.GetMachineByID(request.GetMachineId())
|
node, err := api.h.db.GetNodeByID(request.GetNodeId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
routes, err := api.h.db.GetMachineRoutes(machine)
|
routes, err := api.h.db.GetNodeRoutes(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v1.GetMachineRoutesResponse{
|
return &v1.GetNodeRoutesResponse{
|
||||||
Routes: types.Routes(routes).Proto(),
|
Routes: types.Routes(routes).Proto(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -495,10 +495,10 @@ func (api headscaleV1APIServer) ListApiKeys(
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following service calls are for testing and debugging
|
// The following service calls are for testing and debugging
|
||||||
func (api headscaleV1APIServer) DebugCreateMachine(
|
func (api headscaleV1APIServer) DebugCreateNode(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
request *v1.DebugCreateMachineRequest,
|
request *v1.DebugCreateNodeRequest,
|
||||||
) (*v1.DebugCreateMachineResponse, error) {
|
) (*v1.DebugCreateNodeResponse, error) {
|
||||||
user, err := api.h.db.GetUser(request.GetUser())
|
user, err := api.h.db.GetUser(request.GetUser())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -518,7 +518,7 @@ func (api headscaleV1APIServer) DebugCreateMachine(
|
||||||
hostinfo := tailcfg.Hostinfo{
|
hostinfo := tailcfg.Hostinfo{
|
||||||
RoutableIPs: routes,
|
RoutableIPs: routes,
|
||||||
OS: "TestOS",
|
OS: "TestOS",
|
||||||
Hostname: "DebugTestMachine",
|
Hostname: "DebugTestNode",
|
||||||
}
|
}
|
||||||
|
|
||||||
givenName, err := api.h.db.GenerateGivenName(request.GetKey(), request.GetName())
|
givenName, err := api.h.db.GenerateGivenName(request.GetKey(), request.GetName())
|
||||||
|
@ -526,7 +526,7 @@ func (api headscaleV1APIServer) DebugCreateMachine(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
newMachine := types.Machine{
|
newNode := types.Node{
|
||||||
MachineKey: request.GetKey(),
|
MachineKey: request.GetKey(),
|
||||||
Hostname: request.GetName(),
|
Hostname: request.GetName(),
|
||||||
GivenName: givenName,
|
GivenName: givenName,
|
||||||
|
@ -541,16 +541,16 @@ func (api headscaleV1APIServer) DebugCreateMachine(
|
||||||
nodeKey := key.NodePublic{}
|
nodeKey := key.NodePublic{}
|
||||||
err = nodeKey.UnmarshalText([]byte(request.GetKey()))
|
err = nodeKey.UnmarshalText([]byte(request.GetKey()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panic().Msg("can not add machine for debug. invalid node key")
|
log.Panic().Msg("can not add node for debug. invalid node key")
|
||||||
}
|
}
|
||||||
|
|
||||||
api.h.registrationCache.Set(
|
api.h.registrationCache.Set(
|
||||||
util.NodePublicKeyStripPrefix(nodeKey),
|
util.NodePublicKeyStripPrefix(nodeKey),
|
||||||
newMachine,
|
newNode,
|
||||||
registerCacheExpiration,
|
registerCacheExpiration,
|
||||||
)
|
)
|
||||||
|
|
||||||
return &v1.DebugCreateMachineResponse{Machine: newMachine.Proto()}, nil
|
return &v1.DebugCreateNodeResponse{Node: newNode.Proto()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api headscaleV1APIServer) mustEmbedUnimplementedHeadscaleServiceServer() {}
|
func (api headscaleV1APIServer) mustEmbedUnimplementedHeadscaleServiceServer() {}
|
||||||
|
|
|
@ -41,7 +41,7 @@ var debugDumpMapResponsePath = envknob.String("HEADSCALE_DEBUG_DUMP_MAPRESPONSE_
|
||||||
// TODO: Optimise
|
// TODO: Optimise
|
||||||
// As this work continues, the idea is that there will be one Mapper instance
|
// As this work continues, the idea is that there will be one Mapper instance
|
||||||
// per node, attached to the open stream between the control and client.
|
// per node, attached to the open stream between the control and client.
|
||||||
// This means that this can hold a state per machine and we can use that to
|
// This means that this can hold a state per node and we can use that to
|
||||||
// improve the mapresponses sent.
|
// improve the mapresponses sent.
|
||||||
// We could:
|
// We could:
|
||||||
// - Keep information about the previous mapresponse so we can send a diff
|
// - Keep information about the previous mapresponse so we can send a diff
|
||||||
|
@ -67,12 +67,12 @@ type Mapper struct {
|
||||||
// Map isnt concurrency safe, so we need to ensure
|
// Map isnt concurrency safe, so we need to ensure
|
||||||
// only one func is accessing it over time.
|
// only one func is accessing it over time.
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
peers map[uint64]*types.Machine
|
peers map[uint64]*types.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMapper(
|
func NewMapper(
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
peers types.Machines,
|
peers types.Nodes,
|
||||||
privateKey *key.MachinePrivate,
|
privateKey *key.MachinePrivate,
|
||||||
isNoise bool,
|
isNoise bool,
|
||||||
derpMap *tailcfg.DERPMap,
|
derpMap *tailcfg.DERPMap,
|
||||||
|
@ -84,7 +84,7 @@ func NewMapper(
|
||||||
log.Debug().
|
log.Debug().
|
||||||
Caller().
|
Caller().
|
||||||
Bool("noise", isNoise).
|
Bool("noise", isNoise).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("creating new mapper")
|
Msg("creating new mapper")
|
||||||
|
|
||||||
uid, _ := util.GenerateRandomStringDNSSafe(mapperIDLength)
|
uid, _ := util.GenerateRandomStringDNSSafe(mapperIDLength)
|
||||||
|
@ -113,12 +113,12 @@ func (m *Mapper) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateUserProfiles(
|
func generateUserProfiles(
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
peers types.Machines,
|
peers types.Nodes,
|
||||||
baseDomain string,
|
baseDomain string,
|
||||||
) []tailcfg.UserProfile {
|
) []tailcfg.UserProfile {
|
||||||
userMap := make(map[string]types.User)
|
userMap := make(map[string]types.User)
|
||||||
userMap[machine.User.Name] = machine.User
|
userMap[node.User.Name] = node.User
|
||||||
for _, peer := range peers {
|
for _, peer := range peers {
|
||||||
userMap[peer.User.Name] = peer.User // not worth checking if already is there
|
userMap[peer.User.Name] = peer.User // not worth checking if already is there
|
||||||
}
|
}
|
||||||
|
@ -145,8 +145,8 @@ func generateUserProfiles(
|
||||||
func generateDNSConfig(
|
func generateDNSConfig(
|
||||||
base *tailcfg.DNSConfig,
|
base *tailcfg.DNSConfig,
|
||||||
baseDomain string,
|
baseDomain string,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
peers types.Machines,
|
peers types.Nodes,
|
||||||
) *tailcfg.DNSConfig {
|
) *tailcfg.DNSConfig {
|
||||||
dnsConfig := base.Clone()
|
dnsConfig := base.Clone()
|
||||||
|
|
||||||
|
@ -158,13 +158,13 @@ func generateDNSConfig(
|
||||||
dnsConfig.Domains,
|
dnsConfig.Domains,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"%s.%s",
|
"%s.%s",
|
||||||
machine.User.Name,
|
node.User.Name,
|
||||||
baseDomain,
|
baseDomain,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
userSet := mapset.NewSet[types.User]()
|
userSet := mapset.NewSet[types.User]()
|
||||||
userSet.Add(machine.User)
|
userSet.Add(node.User)
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
userSet.Add(p.User)
|
userSet.Add(p.User)
|
||||||
}
|
}
|
||||||
|
@ -176,28 +176,28 @@ func generateDNSConfig(
|
||||||
dnsConfig = base
|
dnsConfig = base
|
||||||
}
|
}
|
||||||
|
|
||||||
addNextDNSMetadata(dnsConfig.Resolvers, machine)
|
addNextDNSMetadata(dnsConfig.Resolvers, node)
|
||||||
|
|
||||||
return dnsConfig
|
return dnsConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any nextdns DoH resolvers are present in the list of resolvers it will
|
// If any nextdns DoH resolvers are present in the list of resolvers it will
|
||||||
// take metadata from the machine metadata and instruct tailscale to add it
|
// take metadata from the node metadata and instruct tailscale to add it
|
||||||
// to the requests. This makes it possible to identify from which device the
|
// to the requests. This makes it possible to identify from which device the
|
||||||
// requests come in the NextDNS dashboard.
|
// requests come in the NextDNS dashboard.
|
||||||
//
|
//
|
||||||
// This will produce a resolver like:
|
// This will produce a resolver like:
|
||||||
// `https://dns.nextdns.io/<nextdns-id>?device_name=node-name&device_model=linux&device_ip=100.64.0.1`
|
// `https://dns.nextdns.io/<nextdns-id>?device_name=node-name&device_model=linux&device_ip=100.64.0.1`
|
||||||
func addNextDNSMetadata(resolvers []*dnstype.Resolver, machine *types.Machine) {
|
func addNextDNSMetadata(resolvers []*dnstype.Resolver, node *types.Node) {
|
||||||
for _, resolver := range resolvers {
|
for _, resolver := range resolvers {
|
||||||
if strings.HasPrefix(resolver.Addr, nextDNSDoHPrefix) {
|
if strings.HasPrefix(resolver.Addr, nextDNSDoHPrefix) {
|
||||||
attrs := url.Values{
|
attrs := url.Values{
|
||||||
"device_name": []string{machine.Hostname},
|
"device_name": []string{node.Hostname},
|
||||||
"device_model": []string{machine.HostInfo.OS},
|
"device_model": []string{node.HostInfo.OS},
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(machine.IPAddresses) > 0 {
|
if len(node.IPAddresses) > 0 {
|
||||||
attrs.Add("device_ip", machine.IPAddresses[0].String())
|
attrs.Add("device_ip", node.IPAddresses[0].String())
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver.Addr = fmt.Sprintf("%s?%s", resolver.Addr, attrs.Encode())
|
resolver.Addr = fmt.Sprintf("%s?%s", resolver.Addr, attrs.Encode())
|
||||||
|
@ -208,23 +208,23 @@ func addNextDNSMetadata(resolvers []*dnstype.Resolver, machine *types.Machine) {
|
||||||
// fullMapResponse creates a complete MapResponse for a node.
|
// fullMapResponse creates a complete MapResponse for a node.
|
||||||
// It is a separate function to make testing easier.
|
// It is a separate function to make testing easier.
|
||||||
func (m *Mapper) fullMapResponse(
|
func (m *Mapper) fullMapResponse(
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
pol *policy.ACLPolicy,
|
pol *policy.ACLPolicy,
|
||||||
) (*tailcfg.MapResponse, error) {
|
) (*tailcfg.MapResponse, error) {
|
||||||
peers := machineMapToList(m.peers)
|
peers := nodeMapToList(m.peers)
|
||||||
|
|
||||||
resp, err := m.baseWithConfigMapResponse(machine, pol)
|
resp, err := m.baseWithConfigMapResponse(node, pol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(kradalby): Move this into appendPeerChanges?
|
// TODO(kradalby): Move this into appendPeerChanges?
|
||||||
resp.OnlineChange = db.OnlineMachineMap(peers)
|
resp.OnlineChange = db.OnlineNodeMap(peers)
|
||||||
|
|
||||||
err = appendPeerChanges(
|
err = appendPeerChanges(
|
||||||
resp,
|
resp,
|
||||||
pol,
|
pol,
|
||||||
machine,
|
node,
|
||||||
peers,
|
peers,
|
||||||
peers,
|
peers,
|
||||||
m.baseDomain,
|
m.baseDomain,
|
||||||
|
@ -237,72 +237,72 @@ func (m *Mapper) fullMapResponse(
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FullMapResponse returns a MapResponse for the given machine.
|
// FullMapResponse returns a MapResponse for the given node.
|
||||||
func (m *Mapper) FullMapResponse(
|
func (m *Mapper) FullMapResponse(
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
pol *policy.ACLPolicy,
|
pol *policy.ACLPolicy,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
resp, err := m.fullMapResponse(machine, pol)
|
resp, err := m.fullMapResponse(node, pol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.isNoise {
|
if m.isNoise {
|
||||||
return m.marshalMapResponse(mapRequest, resp, machine, mapRequest.Compress)
|
return m.marshalMapResponse(mapRequest, resp, node, mapRequest.Compress)
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.marshalMapResponse(mapRequest, resp, machine, mapRequest.Compress)
|
return m.marshalMapResponse(mapRequest, resp, node, mapRequest.Compress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LiteMapResponse returns a MapResponse for the given machine.
|
// LiteMapResponse returns a MapResponse for the given node.
|
||||||
// Lite means that the peers has been omitted, this is intended
|
// Lite means that the peers has been omitted, this is intended
|
||||||
// to be used to answer MapRequests with OmitPeers set to true.
|
// to be used to answer MapRequests with OmitPeers set to true.
|
||||||
func (m *Mapper) LiteMapResponse(
|
func (m *Mapper) LiteMapResponse(
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
pol *policy.ACLPolicy,
|
pol *policy.ACLPolicy,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
resp, err := m.baseWithConfigMapResponse(machine, pol)
|
resp, err := m.baseWithConfigMapResponse(node, pol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.isNoise {
|
if m.isNoise {
|
||||||
return m.marshalMapResponse(mapRequest, resp, machine, mapRequest.Compress)
|
return m.marshalMapResponse(mapRequest, resp, node, mapRequest.Compress)
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.marshalMapResponse(mapRequest, resp, machine, mapRequest.Compress)
|
return m.marshalMapResponse(mapRequest, resp, node, mapRequest.Compress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mapper) KeepAliveResponse(
|
func (m *Mapper) KeepAliveResponse(
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
resp := m.baseMapResponse()
|
resp := m.baseMapResponse()
|
||||||
resp.KeepAlive = true
|
resp.KeepAlive = true
|
||||||
|
|
||||||
return m.marshalMapResponse(mapRequest, &resp, machine, mapRequest.Compress)
|
return m.marshalMapResponse(mapRequest, &resp, node, mapRequest.Compress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mapper) DERPMapResponse(
|
func (m *Mapper) DERPMapResponse(
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
derpMap tailcfg.DERPMap,
|
derpMap tailcfg.DERPMap,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
resp := m.baseMapResponse()
|
resp := m.baseMapResponse()
|
||||||
resp.DERPMap = &derpMap
|
resp.DERPMap = &derpMap
|
||||||
|
|
||||||
return m.marshalMapResponse(mapRequest, &resp, machine, mapRequest.Compress)
|
return m.marshalMapResponse(mapRequest, &resp, node, mapRequest.Compress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mapper) PeerChangedResponse(
|
func (m *Mapper) PeerChangedResponse(
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
changed types.Machines,
|
changed types.Nodes,
|
||||||
pol *policy.ACLPolicy,
|
pol *policy.ACLPolicy,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
|
@ -311,11 +311,11 @@ func (m *Mapper) PeerChangedResponse(
|
||||||
lastSeen := make(map[tailcfg.NodeID]bool)
|
lastSeen := make(map[tailcfg.NodeID]bool)
|
||||||
|
|
||||||
// Update our internal map.
|
// Update our internal map.
|
||||||
for _, machine := range changed {
|
for _, node := range changed {
|
||||||
m.peers[machine.ID] = machine
|
m.peers[node.ID] = node
|
||||||
|
|
||||||
// We have just seen the node, let the peers update their list.
|
// We have just seen the node, let the peers update their list.
|
||||||
lastSeen[tailcfg.NodeID(machine.ID)] = true
|
lastSeen[tailcfg.NodeID(node.ID)] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := m.baseMapResponse()
|
resp := m.baseMapResponse()
|
||||||
|
@ -323,8 +323,8 @@ func (m *Mapper) PeerChangedResponse(
|
||||||
err := appendPeerChanges(
|
err := appendPeerChanges(
|
||||||
&resp,
|
&resp,
|
||||||
pol,
|
pol,
|
||||||
machine,
|
node,
|
||||||
machineMapToList(m.peers),
|
nodeMapToList(m.peers),
|
||||||
changed,
|
changed,
|
||||||
m.baseDomain,
|
m.baseDomain,
|
||||||
m.dnsCfg,
|
m.dnsCfg,
|
||||||
|
@ -335,12 +335,12 @@ func (m *Mapper) PeerChangedResponse(
|
||||||
|
|
||||||
// resp.PeerSeenChange = lastSeen
|
// resp.PeerSeenChange = lastSeen
|
||||||
|
|
||||||
return m.marshalMapResponse(mapRequest, &resp, machine, mapRequest.Compress)
|
return m.marshalMapResponse(mapRequest, &resp, node, mapRequest.Compress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mapper) PeerRemovedResponse(
|
func (m *Mapper) PeerRemovedResponse(
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
removed []tailcfg.NodeID,
|
removed []tailcfg.NodeID,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
|
@ -354,19 +354,19 @@ func (m *Mapper) PeerRemovedResponse(
|
||||||
resp := m.baseMapResponse()
|
resp := m.baseMapResponse()
|
||||||
resp.PeersRemoved = removed
|
resp.PeersRemoved = removed
|
||||||
|
|
||||||
return m.marshalMapResponse(mapRequest, &resp, machine, mapRequest.Compress)
|
return m.marshalMapResponse(mapRequest, &resp, node, mapRequest.Compress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mapper) marshalMapResponse(
|
func (m *Mapper) marshalMapResponse(
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
resp *tailcfg.MapResponse,
|
resp *tailcfg.MapResponse,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
compression string,
|
compression string,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
atomic.AddUint64(&m.seq, 1)
|
atomic.AddUint64(&m.seq, 1)
|
||||||
|
|
||||||
var machineKey key.MachinePublic
|
var machineKey key.MachinePublic
|
||||||
err := machineKey.UnmarshalText([]byte(util.MachinePublicKeyEnsurePrefix(machine.MachineKey)))
|
err := machineKey.UnmarshalText([]byte(util.MachinePublicKeyEnsurePrefix(node.MachineKey)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Caller().
|
Caller().
|
||||||
|
@ -399,7 +399,7 @@ func (m *Mapper) marshalMapResponse(
|
||||||
}
|
}
|
||||||
|
|
||||||
perms := fs.FileMode(debugMapResponsePerm)
|
perms := fs.FileMode(debugMapResponsePerm)
|
||||||
mPath := path.Join(debugDumpMapResponsePath, machine.Hostname)
|
mPath := path.Join(debugDumpMapResponsePath, node.Hostname)
|
||||||
err = os.MkdirAll(mPath, perms)
|
err = os.MkdirAll(mPath, perms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -509,12 +509,12 @@ func (m *Mapper) baseMapResponse() tailcfg.MapResponse {
|
||||||
// It is used in for bigger updates, such as full and lite, not
|
// It is used in for bigger updates, such as full and lite, not
|
||||||
// incremental.
|
// incremental.
|
||||||
func (m *Mapper) baseWithConfigMapResponse(
|
func (m *Mapper) baseWithConfigMapResponse(
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
pol *policy.ACLPolicy,
|
pol *policy.ACLPolicy,
|
||||||
) (*tailcfg.MapResponse, error) {
|
) (*tailcfg.MapResponse, error) {
|
||||||
resp := m.baseMapResponse()
|
resp := m.baseMapResponse()
|
||||||
|
|
||||||
tailnode, err := tailNode(machine, pol, m.dnsCfg, m.baseDomain)
|
tailnode, err := tailNode(node, pol, m.dnsCfg, m.baseDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -538,18 +538,18 @@ func (m *Mapper) baseWithConfigMapResponse(
|
||||||
return &resp, nil
|
return &resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func machineMapToList(machines map[uint64]*types.Machine) types.Machines {
|
func nodeMapToList(nodes map[uint64]*types.Node) types.Nodes {
|
||||||
ret := make(types.Machines, 0)
|
ret := make(types.Nodes, 0)
|
||||||
|
|
||||||
for _, machine := range machines {
|
for _, node := range nodes {
|
||||||
ret = append(ret, machine)
|
ret = append(ret, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterExpiredAndNotReady(peers types.Machines) types.Machines {
|
func filterExpiredAndNotReady(peers types.Nodes) types.Nodes {
|
||||||
return lo.Filter(peers, func(item *types.Machine, index int) bool {
|
return lo.Filter(peers, func(item *types.Node, index int) bool {
|
||||||
// Filter out nodes that are expired OR
|
// Filter out nodes that are expired OR
|
||||||
// nodes that has no endpoints, this typically means they have
|
// nodes that has no endpoints, this typically means they have
|
||||||
// registered, but are not configured.
|
// registered, but are not configured.
|
||||||
|
@ -563,9 +563,9 @@ func appendPeerChanges(
|
||||||
resp *tailcfg.MapResponse,
|
resp *tailcfg.MapResponse,
|
||||||
|
|
||||||
pol *policy.ACLPolicy,
|
pol *policy.ACLPolicy,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
peers types.Machines,
|
peers types.Nodes,
|
||||||
changed types.Machines,
|
changed types.Nodes,
|
||||||
baseDomain string,
|
baseDomain string,
|
||||||
dnsCfg *tailcfg.DNSConfig,
|
dnsCfg *tailcfg.DNSConfig,
|
||||||
) error {
|
) error {
|
||||||
|
@ -573,7 +573,7 @@ func appendPeerChanges(
|
||||||
|
|
||||||
rules, sshPolicy, err := policy.GenerateFilterAndSSHRules(
|
rules, sshPolicy, err := policy.GenerateFilterAndSSHRules(
|
||||||
pol,
|
pol,
|
||||||
machine,
|
node,
|
||||||
peers,
|
peers,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -583,18 +583,18 @@ func appendPeerChanges(
|
||||||
// Filter out peers that have expired.
|
// Filter out peers that have expired.
|
||||||
changed = filterExpiredAndNotReady(changed)
|
changed = filterExpiredAndNotReady(changed)
|
||||||
|
|
||||||
// If there are filter rules present, see if there are any machines that cannot
|
// If there are filter rules present, see if there are any nodes that cannot
|
||||||
// access eachother at all and remove them from the peers.
|
// access eachother at all and remove them from the peers.
|
||||||
if len(rules) > 0 {
|
if len(rules) > 0 {
|
||||||
changed = policy.FilterMachinesByACL(machine, changed, rules)
|
changed = policy.FilterNodesByACL(node, changed, rules)
|
||||||
}
|
}
|
||||||
|
|
||||||
profiles := generateUserProfiles(machine, changed, baseDomain)
|
profiles := generateUserProfiles(node, changed, baseDomain)
|
||||||
|
|
||||||
dnsConfig := generateDNSConfig(
|
dnsConfig := generateDNSConfig(
|
||||||
dnsCfg,
|
dnsCfg,
|
||||||
baseDomain,
|
baseDomain,
|
||||||
machine,
|
node,
|
||||||
peers,
|
peers,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -614,7 +614,7 @@ func appendPeerChanges(
|
||||||
resp.PeersChanged = tailPeers
|
resp.PeersChanged = tailPeers
|
||||||
}
|
}
|
||||||
resp.DNSConfig = dnsConfig
|
resp.DNSConfig = dnsConfig
|
||||||
resp.PacketFilter = policy.ReduceFilterRules(machine, rules)
|
resp.PacketFilter = policy.ReduceFilterRules(node, rules)
|
||||||
resp.UserProfiles = profiles
|
resp.UserProfiles = profiles
|
||||||
resp.SSHPolicy = sshPolicy
|
resp.SSHPolicy = sshPolicy
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
|
func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
|
||||||
mach := func(hostname, username string, userid uint) *types.Machine {
|
mach := func(hostname, username string, userid uint) *types.Node {
|
||||||
return &types.Machine{
|
return &types.Node{
|
||||||
Hostname: hostname,
|
Hostname: hostname,
|
||||||
UserID: userid,
|
UserID: userid,
|
||||||
User: types.User{
|
User: types.User{
|
||||||
|
@ -28,15 +28,15 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
machineInShared1 := mach("test_get_shared_nodes_1", "user1", 1)
|
nodeInShared1 := mach("test_get_shared_nodes_1", "user1", 1)
|
||||||
machineInShared2 := mach("test_get_shared_nodes_2", "user2", 2)
|
nodeInShared2 := mach("test_get_shared_nodes_2", "user2", 2)
|
||||||
machineInShared3 := mach("test_get_shared_nodes_3", "user3", 3)
|
nodeInShared3 := mach("test_get_shared_nodes_3", "user3", 3)
|
||||||
machine2InShared1 := mach("test_get_shared_nodes_4", "user1", 1)
|
node2InShared1 := mach("test_get_shared_nodes_4", "user1", 1)
|
||||||
|
|
||||||
userProfiles := generateUserProfiles(
|
userProfiles := generateUserProfiles(
|
||||||
machineInShared1,
|
nodeInShared1,
|
||||||
types.Machines{
|
types.Nodes{
|
||||||
machineInShared2, machineInShared3, machine2InShared1,
|
nodeInShared2, nodeInShared3, node2InShared1,
|
||||||
},
|
},
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
@ -91,8 +91,8 @@ func TestDNSConfigMapResponse(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(fmt.Sprintf("with-magicdns-%v", tt.magicDNS), func(t *testing.T) {
|
t.Run(fmt.Sprintf("with-magicdns-%v", tt.magicDNS), func(t *testing.T) {
|
||||||
mach := func(hostname, username string, userid uint) *types.Machine {
|
mach := func(hostname, username string, userid uint) *types.Node {
|
||||||
return &types.Machine{
|
return &types.Node{
|
||||||
Hostname: hostname,
|
Hostname: hostname,
|
||||||
UserID: userid,
|
UserID: userid,
|
||||||
User: types.User{
|
User: types.User{
|
||||||
|
@ -109,23 +109,23 @@ func TestDNSConfigMapResponse(t *testing.T) {
|
||||||
Proxied: tt.magicDNS,
|
Proxied: tt.magicDNS,
|
||||||
}
|
}
|
||||||
|
|
||||||
machineInShared1 := mach("test_get_shared_nodes_1", "shared1", 1)
|
nodeInShared1 := mach("test_get_shared_nodes_1", "shared1", 1)
|
||||||
machineInShared2 := mach("test_get_shared_nodes_2", "shared2", 2)
|
nodeInShared2 := mach("test_get_shared_nodes_2", "shared2", 2)
|
||||||
machineInShared3 := mach("test_get_shared_nodes_3", "shared3", 3)
|
nodeInShared3 := mach("test_get_shared_nodes_3", "shared3", 3)
|
||||||
machine2InShared1 := mach("test_get_shared_nodes_4", "shared1", 1)
|
node2InShared1 := mach("test_get_shared_nodes_4", "shared1", 1)
|
||||||
|
|
||||||
peersOfMachineInShared1 := types.Machines{
|
peersOfNodeInShared1 := types.Nodes{
|
||||||
machineInShared1,
|
nodeInShared1,
|
||||||
machineInShared2,
|
nodeInShared2,
|
||||||
machineInShared3,
|
nodeInShared3,
|
||||||
machine2InShared1,
|
node2InShared1,
|
||||||
}
|
}
|
||||||
|
|
||||||
got := generateDNSConfig(
|
got := generateDNSConfig(
|
||||||
&dnsConfigOrig,
|
&dnsConfigOrig,
|
||||||
baseDomain,
|
baseDomain,
|
||||||
machineInShared1,
|
nodeInShared1,
|
||||||
peersOfMachineInShared1,
|
peersOfNodeInShared1,
|
||||||
)
|
)
|
||||||
|
|
||||||
if diff := cmp.Diff(tt.want, got, cmpopts.EquateEmpty()); diff != "" {
|
if diff := cmp.Diff(tt.want, got, cmpopts.EquateEmpty()); diff != "" {
|
||||||
|
@ -165,7 +165,7 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
lastSeen := time.Date(2009, time.November, 10, 23, 9, 0, 0, time.UTC)
|
lastSeen := time.Date(2009, time.November, 10, 23, 9, 0, 0, time.UTC)
|
||||||
expire := time.Date(2500, time.November, 11, 23, 0, 0, 0, time.UTC)
|
expire := time.Date(2500, time.November, 11, 23, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
mini := &types.Machine{
|
mini := &types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
|
MachineKey: "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
|
||||||
NodeKey: "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
NodeKey: "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
||||||
|
@ -243,7 +243,7 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
peer1 := &types.Machine{
|
peer1 := &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
MachineKey: "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
|
MachineKey: "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
|
||||||
NodeKey: "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
NodeKey: "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
||||||
|
@ -295,7 +295,7 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
peer2 := &types.Machine{
|
peer2 := &types.Node{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
MachineKey: "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
|
MachineKey: "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
|
||||||
NodeKey: "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
NodeKey: "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
||||||
|
@ -317,8 +317,8 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
pol *policy.ACLPolicy
|
pol *policy.ACLPolicy
|
||||||
machine *types.Machine
|
node *types.Node
|
||||||
peers types.Machines
|
peers types.Nodes
|
||||||
|
|
||||||
baseDomain string
|
baseDomain string
|
||||||
dnsConfig *tailcfg.DNSConfig
|
dnsConfig *tailcfg.DNSConfig
|
||||||
|
@ -329,8 +329,8 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
// {
|
// {
|
||||||
// name: "empty-machine",
|
// name: "empty-node",
|
||||||
// machine: types.Machine{},
|
// node: types.Node{},
|
||||||
// pol: &policy.ACLPolicy{},
|
// pol: &policy.ACLPolicy{},
|
||||||
// dnsConfig: &tailcfg.DNSConfig{},
|
// dnsConfig: &tailcfg.DNSConfig{},
|
||||||
// baseDomain: "",
|
// baseDomain: "",
|
||||||
|
@ -340,8 +340,8 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "no-pol-no-peers-map-response",
|
name: "no-pol-no-peers-map-response",
|
||||||
pol: &policy.ACLPolicy{},
|
pol: &policy.ACLPolicy{},
|
||||||
machine: mini,
|
node: mini,
|
||||||
peers: types.Machines{},
|
peers: types.Nodes{},
|
||||||
baseDomain: "",
|
baseDomain: "",
|
||||||
dnsConfig: &tailcfg.DNSConfig{},
|
dnsConfig: &tailcfg.DNSConfig{},
|
||||||
derpMap: &tailcfg.DERPMap{},
|
derpMap: &tailcfg.DERPMap{},
|
||||||
|
@ -368,8 +368,8 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "no-pol-with-peer-map-response",
|
name: "no-pol-with-peer-map-response",
|
||||||
pol: &policy.ACLPolicy{},
|
pol: &policy.ACLPolicy{},
|
||||||
machine: mini,
|
node: mini,
|
||||||
peers: types.Machines{
|
peers: types.Nodes{
|
||||||
peer1,
|
peer1,
|
||||||
},
|
},
|
||||||
baseDomain: "",
|
baseDomain: "",
|
||||||
|
@ -409,8 +409,8 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
machine: mini,
|
node: mini,
|
||||||
peers: types.Machines{
|
peers: types.Nodes{
|
||||||
peer1,
|
peer1,
|
||||||
peer2,
|
peer2,
|
||||||
},
|
},
|
||||||
|
@ -457,7 +457,7 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
mappy := NewMapper(
|
mappy := NewMapper(
|
||||||
tt.machine,
|
tt.node,
|
||||||
tt.peers,
|
tt.peers,
|
||||||
nil,
|
nil,
|
||||||
false,
|
false,
|
||||||
|
@ -469,7 +469,7 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
)
|
)
|
||||||
|
|
||||||
got, err := mappy.fullMapResponse(
|
got, err := mappy.fullMapResponse(
|
||||||
tt.machine,
|
tt.node,
|
||||||
tt.pol,
|
tt.pol,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -14,16 +14,16 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func tailNodes(
|
func tailNodes(
|
||||||
machines types.Machines,
|
nodes types.Nodes,
|
||||||
pol *policy.ACLPolicy,
|
pol *policy.ACLPolicy,
|
||||||
dnsConfig *tailcfg.DNSConfig,
|
dnsConfig *tailcfg.DNSConfig,
|
||||||
baseDomain string,
|
baseDomain string,
|
||||||
) ([]*tailcfg.Node, error) {
|
) ([]*tailcfg.Node, error) {
|
||||||
nodes := make([]*tailcfg.Node, len(machines))
|
tNodes := make([]*tailcfg.Node, len(nodes))
|
||||||
|
|
||||||
for index, machine := range machines {
|
for index, node := range nodes {
|
||||||
node, err := tailNode(
|
node, err := tailNode(
|
||||||
machine,
|
node,
|
||||||
pol,
|
pol,
|
||||||
dnsConfig,
|
dnsConfig,
|
||||||
baseDomain,
|
baseDomain,
|
||||||
|
@ -32,37 +32,36 @@ func tailNodes(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes[index] = node
|
tNodes[index] = node
|
||||||
}
|
}
|
||||||
|
|
||||||
return nodes, nil
|
return tNodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// tailNode converts a Machine into a Tailscale Node. includeRoutes is false for shared nodes
|
// tailNode converts a Node into a Tailscale Node. includeRoutes is false for shared nodes
|
||||||
// as per the expected behaviour in the official SaaS.
|
// as per the expected behaviour in the official SaaS.
|
||||||
func tailNode(
|
func tailNode(
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
pol *policy.ACLPolicy,
|
pol *policy.ACLPolicy,
|
||||||
dnsConfig *tailcfg.DNSConfig,
|
dnsConfig *tailcfg.DNSConfig,
|
||||||
baseDomain string,
|
baseDomain string,
|
||||||
) (*tailcfg.Node, error) {
|
) (*tailcfg.Node, error) {
|
||||||
nodeKey, err := machine.NodePublicKey()
|
nodeKey, err := node.NodePublicKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MachineKey is only used in the legacy protocol
|
machineKey, err := node.MachinePublicKey()
|
||||||
machineKey, err := machine.MachinePublicKey()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
discoKey, err := machine.DiscoPublicKey()
|
discoKey, err := node.DiscoPublicKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
addrs := machine.IPAddresses.Prefixes()
|
addrs := node.IPAddresses.Prefixes()
|
||||||
|
|
||||||
allowedIPs := append(
|
allowedIPs := append(
|
||||||
[]netip.Prefix{},
|
[]netip.Prefix{},
|
||||||
|
@ -70,7 +69,7 @@ func tailNode(
|
||||||
|
|
||||||
primaryPrefixes := []netip.Prefix{}
|
primaryPrefixes := []netip.Prefix{}
|
||||||
|
|
||||||
for _, route := range machine.Routes {
|
for _, route := range node.Routes {
|
||||||
if route.Enabled {
|
if route.Enabled {
|
||||||
if route.IsPrimary {
|
if route.IsPrimary {
|
||||||
allowedIPs = append(allowedIPs, netip.Prefix(route.Prefix))
|
allowedIPs = append(allowedIPs, netip.Prefix(route.Prefix))
|
||||||
|
@ -82,39 +81,39 @@ func tailNode(
|
||||||
}
|
}
|
||||||
|
|
||||||
var derp string
|
var derp string
|
||||||
if machine.HostInfo.NetInfo != nil {
|
if node.HostInfo.NetInfo != nil {
|
||||||
derp = fmt.Sprintf("127.3.3.40:%d", machine.HostInfo.NetInfo.PreferredDERP)
|
derp = fmt.Sprintf("127.3.3.40:%d", node.HostInfo.NetInfo.PreferredDERP)
|
||||||
} else {
|
} else {
|
||||||
derp = "127.3.3.40:0" // Zero means disconnected or unknown.
|
derp = "127.3.3.40:0" // Zero means disconnected or unknown.
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyExpiry time.Time
|
var keyExpiry time.Time
|
||||||
if machine.Expiry != nil {
|
if node.Expiry != nil {
|
||||||
keyExpiry = *machine.Expiry
|
keyExpiry = *node.Expiry
|
||||||
} else {
|
} else {
|
||||||
keyExpiry = time.Time{}
|
keyExpiry = time.Time{}
|
||||||
}
|
}
|
||||||
|
|
||||||
hostname, err := machine.GetFQDN(dnsConfig, baseDomain)
|
hostname, err := node.GetFQDN(dnsConfig, baseDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
hostInfo := machine.GetHostInfo()
|
hostInfo := node.GetHostInfo()
|
||||||
|
|
||||||
online := machine.IsOnline()
|
online := node.IsOnline()
|
||||||
|
|
||||||
tags, _ := pol.TagsOfMachine(machine)
|
tags, _ := pol.TagsOfNode(node)
|
||||||
tags = lo.Uniq(append(tags, machine.ForcedTags...))
|
tags = lo.Uniq(append(tags, node.ForcedTags...))
|
||||||
|
|
||||||
node := tailcfg.Node{
|
tNode := tailcfg.Node{
|
||||||
ID: tailcfg.NodeID(machine.ID), // this is the actual ID
|
ID: tailcfg.NodeID(node.ID), // this is the actual ID
|
||||||
StableID: tailcfg.StableNodeID(
|
StableID: tailcfg.StableNodeID(
|
||||||
strconv.FormatUint(machine.ID, util.Base10),
|
strconv.FormatUint(node.ID, util.Base10),
|
||||||
), // in headscale, unlike tailcontrol server, IDs are permanent
|
), // in headscale, unlike tailcontrol server, IDs are permanent
|
||||||
Name: hostname,
|
Name: hostname,
|
||||||
|
|
||||||
User: tailcfg.UserID(machine.UserID),
|
User: tailcfg.UserID(node.UserID),
|
||||||
|
|
||||||
Key: nodeKey,
|
Key: nodeKey,
|
||||||
KeyExpiry: keyExpiry,
|
KeyExpiry: keyExpiry,
|
||||||
|
@ -123,19 +122,19 @@ func tailNode(
|
||||||
DiscoKey: discoKey,
|
DiscoKey: discoKey,
|
||||||
Addresses: addrs,
|
Addresses: addrs,
|
||||||
AllowedIPs: allowedIPs,
|
AllowedIPs: allowedIPs,
|
||||||
Endpoints: machine.Endpoints,
|
Endpoints: node.Endpoints,
|
||||||
DERP: derp,
|
DERP: derp,
|
||||||
Hostinfo: hostInfo.View(),
|
Hostinfo: hostInfo.View(),
|
||||||
Created: machine.CreatedAt,
|
Created: node.CreatedAt,
|
||||||
|
|
||||||
Tags: tags,
|
Tags: tags,
|
||||||
|
|
||||||
PrimaryRoutes: primaryPrefixes,
|
PrimaryRoutes: primaryPrefixes,
|
||||||
|
|
||||||
LastSeen: machine.LastSeen,
|
LastSeen: node.LastSeen,
|
||||||
Online: &online,
|
Online: &online,
|
||||||
KeepAlive: true,
|
KeepAlive: true,
|
||||||
MachineAuthorized: !machine.IsExpired(),
|
MachineAuthorized: !node.IsExpired(),
|
||||||
|
|
||||||
Capabilities: []string{
|
Capabilities: []string{
|
||||||
tailcfg.CapabilityFileSharing,
|
tailcfg.CapabilityFileSharing,
|
||||||
|
@ -144,5 +143,5 @@ func tailNode(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return &node, nil
|
return &tNode, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ func TestTailNode(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
machine *types.Machine
|
node *types.Node
|
||||||
pol *policy.ACLPolicy
|
pol *policy.ACLPolicy
|
||||||
dnsConfig *tailcfg.DNSConfig
|
dnsConfig *tailcfg.DNSConfig
|
||||||
baseDomain string
|
baseDomain string
|
||||||
|
@ -53,8 +53,8 @@ func TestTailNode(t *testing.T) {
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty-machine",
|
name: "empty-node",
|
||||||
machine: &types.Machine{},
|
node: &types.Node{},
|
||||||
pol: &policy.ACLPolicy{},
|
pol: &policy.ACLPolicy{},
|
||||||
dnsConfig: &tailcfg.DNSConfig{},
|
dnsConfig: &tailcfg.DNSConfig{},
|
||||||
baseDomain: "",
|
baseDomain: "",
|
||||||
|
@ -62,8 +62,8 @@ func TestTailNode(t *testing.T) {
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "minimal-machine",
|
name: "minimal-node",
|
||||||
machine: &types.Machine{
|
node: &types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
|
MachineKey: "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
|
||||||
NodeKey: "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
NodeKey: "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
||||||
|
@ -165,7 +165,7 @@ func TestTailNode(t *testing.T) {
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := tailNode(
|
got, err := tailNode(
|
||||||
tt.machine,
|
tt.node,
|
||||||
tt.pol,
|
tt.pol,
|
||||||
tt.dnsConfig,
|
tt.dnsConfig,
|
||||||
tt.baseDomain,
|
tt.baseDomain,
|
||||||
|
|
|
@ -8,18 +8,18 @@ import (
|
||||||
const prometheusNamespace = "headscale"
|
const prometheusNamespace = "headscale"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// This is a high cardinality metric (user x machines), we might want to make this
|
// This is a high cardinality metric (user x node), we might want to make this
|
||||||
// configurable/opt-in in the future.
|
// configurable/opt-in in the future.
|
||||||
machineRegistrations = promauto.NewCounterVec(prometheus.CounterOpts{
|
nodeRegistrations = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||||
Namespace: prometheusNamespace,
|
Namespace: prometheusNamespace,
|
||||||
Name: "machine_registrations_total",
|
Name: "node_registrations_total",
|
||||||
Help: "The total amount of registered machine attempts",
|
Help: "The total amount of registered node attempts",
|
||||||
}, []string{"action", "auth", "status", "user"})
|
}, []string{"action", "auth", "status", "user"})
|
||||||
|
|
||||||
updateRequestsSentToNode = promauto.NewCounterVec(prometheus.CounterOpts{
|
updateRequestsSentToNode = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||||
Namespace: prometheusNamespace,
|
Namespace: prometheusNamespace,
|
||||||
Name: "update_request_sent_to_node_total",
|
Name: "update_request_sent_to_node_total",
|
||||||
Help: "The number of calls/messages issued on a specific nodes update channel",
|
Help: "The number of calls/messages issued on a specific nodes update channel",
|
||||||
}, []string{"user", "machine", "status"})
|
}, []string{"user", "node", "status"})
|
||||||
// TODO(kradalby): This is very debugging, we might want to remove it.
|
// TODO(kradalby): This is very debugging, we might want to remove it.
|
||||||
)
|
)
|
||||||
|
|
|
@ -37,8 +37,8 @@ var (
|
||||||
errOIDCAllowedUsers = errors.New(
|
errOIDCAllowedUsers = errors.New(
|
||||||
"authenticated principal does not match any allowed user",
|
"authenticated principal does not match any allowed user",
|
||||||
)
|
)
|
||||||
errOIDCInvalidMachineState = errors.New(
|
errOIDCInvalidNodeState = errors.New(
|
||||||
"requested machine state key expired before authorisation completed",
|
"requested node state key expired before authorisation completed",
|
||||||
)
|
)
|
||||||
errOIDCNodeKeyMissing = errors.New("could not get node key from cache")
|
errOIDCNodeKeyMissing = errors.New("could not get node key from cache")
|
||||||
)
|
)
|
||||||
|
@ -184,9 +184,9 @@ var oidcCallbackTemplate = template.Must(
|
||||||
)
|
)
|
||||||
|
|
||||||
// OIDCCallback handles the callback from the OIDC endpoint
|
// OIDCCallback handles the callback from the OIDC endpoint
|
||||||
// Retrieves the nkey from the state cache and adds the machine to the users email user
|
// Retrieves the nkey from the state cache and adds the node to the users email user
|
||||||
// TODO: A confirmation page for new machines should be added to avoid phishing vulnerabilities
|
// TODO: A confirmation page for new nodes should be added to avoid phishing vulnerabilities
|
||||||
// TODO: Add groups information from OIDC tokens into machine HostInfo
|
// TODO: Add groups information from OIDC tokens into node HostInfo
|
||||||
// Listens in /oidc/callback.
|
// Listens in /oidc/callback.
|
||||||
func (h *Headscale) OIDCCallback(
|
func (h *Headscale) OIDCCallback(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
|
@ -232,13 +232,13 @@ func (h *Headscale) OIDCCallback(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeKey, machineExists, err := h.validateMachineForOIDCCallback(
|
nodeKey, nodeExists, err := h.validateNodeForOIDCCallback(
|
||||||
writer,
|
writer,
|
||||||
state,
|
state,
|
||||||
claims,
|
claims,
|
||||||
idTokenExpiry,
|
idTokenExpiry,
|
||||||
)
|
)
|
||||||
if err != nil || machineExists {
|
if err != nil || nodeExists {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,15 +247,15 @@ func (h *Headscale) OIDCCallback(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// register the machine if it's new
|
// register the node if it's new
|
||||||
log.Debug().Msg("Registering new machine after successful callback")
|
log.Debug().Msg("Registering new node after successful callback")
|
||||||
|
|
||||||
user, err := h.findOrCreateNewUserForOIDCCallback(writer, userName)
|
user, err := h.findOrCreateNewUserForOIDCCallback(writer, userName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.registerMachineForOIDCCallback(writer, user, nodeKey, idTokenExpiry); err != nil {
|
if err := h.registerNodeForOIDCCallback(writer, user, nodeKey, idTokenExpiry); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,21 +453,21 @@ func validateOIDCAllowedUsers(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateMachine retrieves machine information if it exist
|
// validateNode retrieves node information if it exist
|
||||||
// The error is not important, because if it does not
|
// The error is not important, because if it does not
|
||||||
// exist, then this is a new machine and we will move
|
// exist, then this is a new node and we will move
|
||||||
// on to registration.
|
// on to registration.
|
||||||
func (h *Headscale) validateMachineForOIDCCallback(
|
func (h *Headscale) validateNodeForOIDCCallback(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
state string,
|
state string,
|
||||||
claims *IDTokenClaims,
|
claims *IDTokenClaims,
|
||||||
expiry time.Time,
|
expiry time.Time,
|
||||||
) (*key.NodePublic, bool, error) {
|
) (*key.NodePublic, bool, error) {
|
||||||
// retrieve machinekey from state cache
|
// retrieve nodekey from state cache
|
||||||
nodeKeyIf, nodeKeyFound := h.registrationCache.Get(state)
|
nodeKeyIf, nodeKeyFound := h.registrationCache.Get(state)
|
||||||
if !nodeKeyFound {
|
if !nodeKeyFound {
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Msg("requested machine state key expired before authorisation completed")
|
Msg("requested node state key expired before authorisation completed")
|
||||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
_, err := writer.Write([]byte("state has expired"))
|
_, err := writer.Write([]byte("state has expired"))
|
||||||
|
@ -482,7 +482,7 @@ func (h *Headscale) validateMachineForOIDCCallback(
|
||||||
nodeKeyFromCache, nodeKeyOK := nodeKeyIf.(string)
|
nodeKeyFromCache, nodeKeyOK := nodeKeyIf.(string)
|
||||||
if !nodeKeyOK {
|
if !nodeKeyOK {
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Msg("requested machine state key is not a string")
|
Msg("requested node state key is not a string")
|
||||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
_, err := writer.Write([]byte("state is invalid"))
|
_, err := writer.Write([]byte("state is invalid"))
|
||||||
|
@ -490,7 +490,7 @@ func (h *Headscale) validateMachineForOIDCCallback(
|
||||||
util.LogErr(err, "Failed to write response")
|
util.LogErr(err, "Failed to write response")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, false, errOIDCInvalidMachineState
|
return nil, false, errOIDCInvalidNodeState
|
||||||
}
|
}
|
||||||
|
|
||||||
err := nodeKey.UnmarshalText(
|
err := nodeKey.UnmarshalText(
|
||||||
|
@ -511,33 +511,33 @@ func (h *Headscale) validateMachineForOIDCCallback(
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve machine information if it exist
|
// retrieve node information if it exist
|
||||||
// The error is not important, because if it does not
|
// The error is not important, because if it does not
|
||||||
// exist, then this is a new machine and we will move
|
// exist, then this is a new node and we will move
|
||||||
// on to registration.
|
// on to registration.
|
||||||
machine, _ := h.db.GetMachineByNodeKey(nodeKey)
|
node, _ := h.db.GetNodeByNodeKey(nodeKey)
|
||||||
|
|
||||||
if machine != nil {
|
if node != nil {
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Caller().
|
Caller().
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("machine already registered, reauthenticating")
|
Msg("node already registered, reauthenticating")
|
||||||
|
|
||||||
err := h.db.MachineSetExpiry(machine, expiry)
|
err := h.db.NodeSetExpiry(node, expiry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.LogErr(err, "Failed to refresh machine")
|
util.LogErr(err, "Failed to refresh node")
|
||||||
http.Error(
|
http.Error(
|
||||||
writer,
|
writer,
|
||||||
"Failed to refresh machine",
|
"Failed to refresh node",
|
||||||
http.StatusInternalServerError,
|
http.StatusInternalServerError,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil, true, err
|
return nil, true, err
|
||||||
}
|
}
|
||||||
log.Debug().
|
log.Debug().
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Str("expiresAt", fmt.Sprintf("%v", expiry)).
|
Str("expiresAt", fmt.Sprintf("%v", expiry)).
|
||||||
Msg("successfully refreshed machine")
|
Msg("successfully refreshed node")
|
||||||
|
|
||||||
var content bytes.Buffer
|
var content bytes.Buffer
|
||||||
if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{
|
if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{
|
||||||
|
@ -638,13 +638,13 @@ func (h *Headscale) findOrCreateNewUserForOIDCCallback(
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headscale) registerMachineForOIDCCallback(
|
func (h *Headscale) registerNodeForOIDCCallback(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
user *types.User,
|
user *types.User,
|
||||||
nodeKey *key.NodePublic,
|
nodeKey *key.NodePublic,
|
||||||
expiry time.Time,
|
expiry time.Time,
|
||||||
) error {
|
) error {
|
||||||
if _, err := h.db.RegisterMachineFromAuthCallback(
|
if _, err := h.db.RegisterNodeFromAuthCallback(
|
||||||
// TODO(kradalby): find a better way to use the cache across modules
|
// TODO(kradalby): find a better way to use the cache across modules
|
||||||
h.registrationCache,
|
h.registrationCache,
|
||||||
nodeKey.String(),
|
nodeKey.String(),
|
||||||
|
@ -652,10 +652,10 @@ func (h *Headscale) registerMachineForOIDCCallback(
|
||||||
&expiry,
|
&expiry,
|
||||||
util.RegisterMethodOIDC,
|
util.RegisterMethodOIDC,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
util.LogErr(err, "could not register machine")
|
util.LogErr(err, "could not register node")
|
||||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusInternalServerError)
|
writer.WriteHeader(http.StatusInternalServerError)
|
||||||
_, werr := writer.Write([]byte("could not register machine"))
|
_, werr := writer.Write([]byte("could not register node"))
|
||||||
if werr != nil {
|
if werr != nil {
|
||||||
util.LogErr(err, "Failed to write response")
|
util.LogErr(err, "Failed to write response")
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,30 +116,30 @@ func LoadACLPolicyFromBytes(acl []byte, format string) (*ACLPolicy, error) {
|
||||||
|
|
||||||
func GenerateFilterAndSSHRules(
|
func GenerateFilterAndSSHRules(
|
||||||
policy *ACLPolicy,
|
policy *ACLPolicy,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
peers types.Machines,
|
peers types.Nodes,
|
||||||
) ([]tailcfg.FilterRule, *tailcfg.SSHPolicy, error) {
|
) ([]tailcfg.FilterRule, *tailcfg.SSHPolicy, error) {
|
||||||
// If there is no policy defined, we default to allow all
|
// If there is no policy defined, we default to allow all
|
||||||
if policy == nil {
|
if policy == nil {
|
||||||
return tailcfg.FilterAllowAll, &tailcfg.SSHPolicy{}, nil
|
return tailcfg.FilterAllowAll, &tailcfg.SSHPolicy{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rules, err := policy.generateFilterRules(machine, peers)
|
rules, err := policy.generateFilterRules(node, peers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []tailcfg.FilterRule{}, &tailcfg.SSHPolicy{}, err
|
return []tailcfg.FilterRule{}, &tailcfg.SSHPolicy{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Interface("ACL", rules).Str("machine", machine.GivenName).Msg("ACL rules")
|
log.Trace().Interface("ACL", rules).Str("node", node.GivenName).Msg("ACL rules")
|
||||||
|
|
||||||
var sshPolicy *tailcfg.SSHPolicy
|
var sshPolicy *tailcfg.SSHPolicy
|
||||||
sshRules, err := policy.generateSSHRules(machine, peers)
|
sshRules, err := policy.generateSSHRules(node, peers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []tailcfg.FilterRule{}, &tailcfg.SSHPolicy{}, err
|
return []tailcfg.FilterRule{}, &tailcfg.SSHPolicy{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Interface("SSH", sshRules).
|
Interface("SSH", sshRules).
|
||||||
Str("machine", machine.GivenName).
|
Str("node", node.GivenName).
|
||||||
Msg("SSH rules")
|
Msg("SSH rules")
|
||||||
|
|
||||||
if sshPolicy == nil {
|
if sshPolicy == nil {
|
||||||
|
@ -150,14 +150,14 @@ func GenerateFilterAndSSHRules(
|
||||||
return rules, sshPolicy, nil
|
return rules, sshPolicy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateFilterRules takes a set of machines and an ACLPolicy and generates a
|
// generateFilterRules takes a set of nodes and an ACLPolicy and generates a
|
||||||
// set of Tailscale compatible FilterRules used to allow traffic on clients.
|
// set of Tailscale compatible FilterRules used to allow traffic on clients.
|
||||||
func (pol *ACLPolicy) generateFilterRules(
|
func (pol *ACLPolicy) generateFilterRules(
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
peers types.Machines,
|
peers types.Nodes,
|
||||||
) ([]tailcfg.FilterRule, error) {
|
) ([]tailcfg.FilterRule, error) {
|
||||||
rules := []tailcfg.FilterRule{}
|
rules := []tailcfg.FilterRule{}
|
||||||
machines := append(peers, machine)
|
nodes := append(peers, node)
|
||||||
|
|
||||||
for index, acl := range pol.ACLs {
|
for index, acl := range pol.ACLs {
|
||||||
if acl.Action != "accept" {
|
if acl.Action != "accept" {
|
||||||
|
@ -166,7 +166,7 @@ func (pol *ACLPolicy) generateFilterRules(
|
||||||
|
|
||||||
srcIPs := []string{}
|
srcIPs := []string{}
|
||||||
for srcIndex, src := range acl.Sources {
|
for srcIndex, src := range acl.Sources {
|
||||||
srcs, err := pol.expandSource(src, machines)
|
srcs, err := pol.expandSource(src, nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Interface("src", src).
|
Interface("src", src).
|
||||||
|
@ -195,7 +195,7 @@ func (pol *ACLPolicy) generateFilterRules(
|
||||||
}
|
}
|
||||||
|
|
||||||
expanded, err := pol.ExpandAlias(
|
expanded, err := pol.ExpandAlias(
|
||||||
machines,
|
nodes,
|
||||||
alias,
|
alias,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -230,13 +230,13 @@ func (pol *ACLPolicy) generateFilterRules(
|
||||||
return rules, nil
|
return rules, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReduceFilterRules takes a machine and a set of rules and removes all rules and destinations
|
// ReduceFilterRules takes a node and a set of rules and removes all rules and destinations
|
||||||
// that are not relevant to that particular node.
|
// that are not relevant to that particular node.
|
||||||
func ReduceFilterRules(machine *types.Machine, rules []tailcfg.FilterRule) []tailcfg.FilterRule {
|
func ReduceFilterRules(node *types.Node, rules []tailcfg.FilterRule) []tailcfg.FilterRule {
|
||||||
ret := []tailcfg.FilterRule{}
|
ret := []tailcfg.FilterRule{}
|
||||||
|
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
// record if the rule is actually relevant for the given machine.
|
// record if the rule is actually relevant for the given node.
|
||||||
dests := []tailcfg.NetPortRange{}
|
dests := []tailcfg.NetPortRange{}
|
||||||
|
|
||||||
for _, dest := range rule.DstPorts {
|
for _, dest := range rule.DstPorts {
|
||||||
|
@ -247,7 +247,7 @@ func ReduceFilterRules(machine *types.Machine, rules []tailcfg.FilterRule) []tai
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if machine.IPAddresses.InIPSet(expanded) {
|
if node.IPAddresses.InIPSet(expanded) {
|
||||||
dests = append(dests, dest)
|
dests = append(dests, dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,8 +265,8 @@ func ReduceFilterRules(machine *types.Machine, rules []tailcfg.FilterRule) []tai
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pol *ACLPolicy) generateSSHRules(
|
func (pol *ACLPolicy) generateSSHRules(
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
peers types.Machines,
|
peers types.Nodes,
|
||||||
) ([]*tailcfg.SSHRule, error) {
|
) ([]*tailcfg.SSHRule, error) {
|
||||||
rules := []*tailcfg.SSHRule{}
|
rules := []*tailcfg.SSHRule{}
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ func (pol *ACLPolicy) generateSSHRules(
|
||||||
for index, sshACL := range pol.SSHs {
|
for index, sshACL := range pol.SSHs {
|
||||||
var dest netipx.IPSetBuilder
|
var dest netipx.IPSetBuilder
|
||||||
for _, src := range sshACL.Destinations {
|
for _, src := range sshACL.Destinations {
|
||||||
expanded, err := pol.ExpandAlias(append(peers, machine), src)
|
expanded, err := pol.ExpandAlias(append(peers, node), src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -305,7 +305,7 @@ func (pol *ACLPolicy) generateSSHRules(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !machine.IPAddresses.InIPSet(destSet) {
|
if !node.IPAddresses.InIPSet(destSet) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,9 +501,9 @@ func parseProtocol(protocol string) ([]int, bool, error) {
|
||||||
// with the given src alias.
|
// with the given src alias.
|
||||||
func (pol *ACLPolicy) expandSource(
|
func (pol *ACLPolicy) expandSource(
|
||||||
src string,
|
src string,
|
||||||
machines types.Machines,
|
nodes types.Nodes,
|
||||||
) ([]string, error) {
|
) ([]string, error) {
|
||||||
ipSet, err := pol.ExpandAlias(machines, src)
|
ipSet, err := pol.ExpandAlias(nodes, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}, err
|
return []string{}, err
|
||||||
}
|
}
|
||||||
|
@ -526,7 +526,7 @@ func (pol *ACLPolicy) expandSource(
|
||||||
// - a cidr
|
// - a cidr
|
||||||
// and transform these in IPAddresses.
|
// and transform these in IPAddresses.
|
||||||
func (pol *ACLPolicy) ExpandAlias(
|
func (pol *ACLPolicy) ExpandAlias(
|
||||||
machines types.Machines,
|
nodes types.Nodes,
|
||||||
alias string,
|
alias string,
|
||||||
) (*netipx.IPSet, error) {
|
) (*netipx.IPSet, error) {
|
||||||
if isWildcard(alias) {
|
if isWildcard(alias) {
|
||||||
|
@ -541,16 +541,16 @@ func (pol *ACLPolicy) ExpandAlias(
|
||||||
|
|
||||||
// if alias is a group
|
// if alias is a group
|
||||||
if isGroup(alias) {
|
if isGroup(alias) {
|
||||||
return pol.expandIPsFromGroup(alias, machines)
|
return pol.expandIPsFromGroup(alias, nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if alias is a tag
|
// if alias is a tag
|
||||||
if isTag(alias) {
|
if isTag(alias) {
|
||||||
return pol.expandIPsFromTag(alias, machines)
|
return pol.expandIPsFromTag(alias, nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if alias is a user
|
// if alias is a user
|
||||||
if ips, err := pol.expandIPsFromUser(alias, machines); ips != nil {
|
if ips, err := pol.expandIPsFromUser(alias, nodes); ips != nil {
|
||||||
return ips, err
|
return ips, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,17 +559,17 @@ func (pol *ACLPolicy) ExpandAlias(
|
||||||
if h, ok := pol.Hosts[alias]; ok {
|
if h, ok := pol.Hosts[alias]; ok {
|
||||||
log.Trace().Str("host", h.String()).Msg("ExpandAlias got hosts entry")
|
log.Trace().Str("host", h.String()).Msg("ExpandAlias got hosts entry")
|
||||||
|
|
||||||
return pol.ExpandAlias(machines, h.String())
|
return pol.ExpandAlias(nodes, h.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// if alias is an IP
|
// if alias is an IP
|
||||||
if ip, err := netip.ParseAddr(alias); err == nil {
|
if ip, err := netip.ParseAddr(alias); err == nil {
|
||||||
return pol.expandIPsFromSingleIP(ip, machines)
|
return pol.expandIPsFromSingleIP(ip, nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if alias is an IP Prefix (CIDR)
|
// if alias is an IP Prefix (CIDR)
|
||||||
if prefix, err := netip.ParsePrefix(alias); err == nil {
|
if prefix, err := netip.ParsePrefix(alias); err == nil {
|
||||||
return pol.expandIPsFromIPPrefix(prefix, machines)
|
return pol.expandIPsFromIPPrefix(prefix, nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warn().Msgf("No IPs found with the alias %v", alias)
|
log.Warn().Msgf("No IPs found with the alias %v", alias)
|
||||||
|
@ -582,10 +582,10 @@ func (pol *ACLPolicy) ExpandAlias(
|
||||||
// we assume in this function that we only have nodes from 1 user.
|
// we assume in this function that we only have nodes from 1 user.
|
||||||
func excludeCorrectlyTaggedNodes(
|
func excludeCorrectlyTaggedNodes(
|
||||||
aclPolicy *ACLPolicy,
|
aclPolicy *ACLPolicy,
|
||||||
nodes types.Machines,
|
nodes types.Nodes,
|
||||||
user string,
|
user string,
|
||||||
) types.Machines {
|
) types.Nodes {
|
||||||
out := types.Machines{}
|
out := types.Nodes{}
|
||||||
tags := []string{}
|
tags := []string{}
|
||||||
for tag := range aclPolicy.TagOwners {
|
for tag := range aclPolicy.TagOwners {
|
||||||
owners, _ := expandOwnersFromTag(aclPolicy, user)
|
owners, _ := expandOwnersFromTag(aclPolicy, user)
|
||||||
|
@ -594,9 +594,9 @@ func excludeCorrectlyTaggedNodes(
|
||||||
tags = append(tags, tag)
|
tags = append(tags, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// for each machine if tag is in tags list, don't append it.
|
// for each node if tag is in tags list, don't append it.
|
||||||
for _, machine := range nodes {
|
for _, node := range nodes {
|
||||||
hi := machine.GetHostInfo()
|
hi := node.GetHostInfo()
|
||||||
|
|
||||||
found := false
|
found := false
|
||||||
for _, t := range hi.RequestTags {
|
for _, t := range hi.RequestTags {
|
||||||
|
@ -606,11 +606,11 @@ func excludeCorrectlyTaggedNodes(
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(machine.ForcedTags) > 0 {
|
if len(node.ForcedTags) > 0 {
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
out = append(out, machine)
|
out = append(out, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -733,7 +733,7 @@ func (pol *ACLPolicy) expandUsersFromGroup(
|
||||||
|
|
||||||
func (pol *ACLPolicy) expandIPsFromGroup(
|
func (pol *ACLPolicy) expandIPsFromGroup(
|
||||||
group string,
|
group string,
|
||||||
machines types.Machines,
|
nodes types.Nodes,
|
||||||
) (*netipx.IPSet, error) {
|
) (*netipx.IPSet, error) {
|
||||||
build := netipx.IPSetBuilder{}
|
build := netipx.IPSetBuilder{}
|
||||||
|
|
||||||
|
@ -742,9 +742,9 @@ func (pol *ACLPolicy) expandIPsFromGroup(
|
||||||
return &netipx.IPSet{}, err
|
return &netipx.IPSet{}, err
|
||||||
}
|
}
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
filteredMachines := filterMachinesByUser(machines, user)
|
filteredNodes := filterNodesByUser(nodes, user)
|
||||||
for _, machine := range filteredMachines {
|
for _, node := range filteredNodes {
|
||||||
machine.IPAddresses.AppendToIPSet(&build)
|
node.IPAddresses.AppendToIPSet(&build)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,14 +753,14 @@ func (pol *ACLPolicy) expandIPsFromGroup(
|
||||||
|
|
||||||
func (pol *ACLPolicy) expandIPsFromTag(
|
func (pol *ACLPolicy) expandIPsFromTag(
|
||||||
alias string,
|
alias string,
|
||||||
machines types.Machines,
|
nodes types.Nodes,
|
||||||
) (*netipx.IPSet, error) {
|
) (*netipx.IPSet, error) {
|
||||||
build := netipx.IPSetBuilder{}
|
build := netipx.IPSetBuilder{}
|
||||||
|
|
||||||
// check for forced tags
|
// check for forced tags
|
||||||
for _, machine := range machines {
|
for _, node := range nodes {
|
||||||
if util.StringOrPrefixListContains(machine.ForcedTags, alias) {
|
if util.StringOrPrefixListContains(node.ForcedTags, alias) {
|
||||||
machine.IPAddresses.AppendToIPSet(&build)
|
node.IPAddresses.AppendToIPSet(&build)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,13 +783,13 @@ func (pol *ACLPolicy) expandIPsFromTag(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter out machines per tag owner
|
// filter out nodes per tag owner
|
||||||
for _, user := range owners {
|
for _, user := range owners {
|
||||||
machines := filterMachinesByUser(machines, user)
|
nodes := filterNodesByUser(nodes, user)
|
||||||
for _, machine := range machines {
|
for _, node := range nodes {
|
||||||
hi := machine.GetHostInfo()
|
hi := node.GetHostInfo()
|
||||||
if util.StringOrPrefixListContains(hi.RequestTags, alias) {
|
if util.StringOrPrefixListContains(hi.RequestTags, alias) {
|
||||||
machine.IPAddresses.AppendToIPSet(&build)
|
node.IPAddresses.AppendToIPSet(&build)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -799,20 +799,20 @@ func (pol *ACLPolicy) expandIPsFromTag(
|
||||||
|
|
||||||
func (pol *ACLPolicy) expandIPsFromUser(
|
func (pol *ACLPolicy) expandIPsFromUser(
|
||||||
user string,
|
user string,
|
||||||
machines types.Machines,
|
nodes types.Nodes,
|
||||||
) (*netipx.IPSet, error) {
|
) (*netipx.IPSet, error) {
|
||||||
build := netipx.IPSetBuilder{}
|
build := netipx.IPSetBuilder{}
|
||||||
|
|
||||||
filteredMachines := filterMachinesByUser(machines, user)
|
filteredNodes := filterNodesByUser(nodes, user)
|
||||||
filteredMachines = excludeCorrectlyTaggedNodes(pol, filteredMachines, user)
|
filteredNodes = excludeCorrectlyTaggedNodes(pol, filteredNodes, user)
|
||||||
|
|
||||||
// shortcurcuit if we have no machines to get ips from.
|
// shortcurcuit if we have no nodes to get ips from.
|
||||||
if len(filteredMachines) == 0 {
|
if len(filteredNodes) == 0 {
|
||||||
return nil, nil //nolint
|
return nil, nil //nolint
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, machine := range filteredMachines {
|
for _, node := range filteredNodes {
|
||||||
machine.IPAddresses.AppendToIPSet(&build)
|
node.IPAddresses.AppendToIPSet(&build)
|
||||||
}
|
}
|
||||||
|
|
||||||
return build.IPSet()
|
return build.IPSet()
|
||||||
|
@ -820,17 +820,17 @@ func (pol *ACLPolicy) expandIPsFromUser(
|
||||||
|
|
||||||
func (pol *ACLPolicy) expandIPsFromSingleIP(
|
func (pol *ACLPolicy) expandIPsFromSingleIP(
|
||||||
ip netip.Addr,
|
ip netip.Addr,
|
||||||
machines types.Machines,
|
nodes types.Nodes,
|
||||||
) (*netipx.IPSet, error) {
|
) (*netipx.IPSet, error) {
|
||||||
log.Trace().Str("ip", ip.String()).Msg("ExpandAlias got ip")
|
log.Trace().Str("ip", ip.String()).Msg("ExpandAlias got ip")
|
||||||
|
|
||||||
matches := machines.FilterByIP(ip)
|
matches := nodes.FilterByIP(ip)
|
||||||
|
|
||||||
build := netipx.IPSetBuilder{}
|
build := netipx.IPSetBuilder{}
|
||||||
build.Add(ip)
|
build.Add(ip)
|
||||||
|
|
||||||
for _, machine := range matches {
|
for _, node := range matches {
|
||||||
machine.IPAddresses.AppendToIPSet(&build)
|
node.IPAddresses.AppendToIPSet(&build)
|
||||||
}
|
}
|
||||||
|
|
||||||
return build.IPSet()
|
return build.IPSet()
|
||||||
|
@ -838,7 +838,7 @@ func (pol *ACLPolicy) expandIPsFromSingleIP(
|
||||||
|
|
||||||
func (pol *ACLPolicy) expandIPsFromIPPrefix(
|
func (pol *ACLPolicy) expandIPsFromIPPrefix(
|
||||||
prefix netip.Prefix,
|
prefix netip.Prefix,
|
||||||
machines types.Machines,
|
nodes types.Nodes,
|
||||||
) (*netipx.IPSet, error) {
|
) (*netipx.IPSet, error) {
|
||||||
log.Trace().Str("prefix", prefix.String()).Msg("expandAlias got prefix")
|
log.Trace().Str("prefix", prefix.String()).Msg("expandAlias got prefix")
|
||||||
build := netipx.IPSetBuilder{}
|
build := netipx.IPSetBuilder{}
|
||||||
|
@ -846,12 +846,12 @@ func (pol *ACLPolicy) expandIPsFromIPPrefix(
|
||||||
|
|
||||||
// This is suboptimal and quite expensive, but if we only add the prefix, we will miss all the relevant IPv6
|
// This is suboptimal and quite expensive, but if we only add the prefix, we will miss all the relevant IPv6
|
||||||
// addresses for the hosts that belong to tailscale. This doesnt really affect stuff like subnet routers.
|
// addresses for the hosts that belong to tailscale. This doesnt really affect stuff like subnet routers.
|
||||||
for _, machine := range machines {
|
for _, node := range nodes {
|
||||||
for _, ip := range machine.IPAddresses {
|
for _, ip := range node.IPAddresses {
|
||||||
// log.Trace().
|
// log.Trace().
|
||||||
// Msgf("checking if machine ip (%s) is part of prefix (%s): %v, is single ip prefix (%v), addr: %s", ip.String(), prefix.String(), prefix.Contains(ip), prefix.IsSingleIP(), prefix.Addr().String())
|
// Msgf("checking if node ip (%s) is part of prefix (%s): %v, is single ip prefix (%v), addr: %s", ip.String(), prefix.String(), prefix.Contains(ip), prefix.IsSingleIP(), prefix.Addr().String())
|
||||||
if prefix.Contains(ip) {
|
if prefix.Contains(ip) {
|
||||||
machine.IPAddresses.AppendToIPSet(&build)
|
node.IPAddresses.AppendToIPSet(&build)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -871,18 +871,18 @@ func isTag(str string) bool {
|
||||||
return strings.HasPrefix(str, "tag:")
|
return strings.HasPrefix(str, "tag:")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TagsOfMachine will return the tags of the current machine.
|
// TagsOfNode will return the tags of the current node.
|
||||||
// Invalid tags are tags added by a user on a node, and that user doesn't have authority to add this tag.
|
// Invalid tags are tags added by a user on a node, and that user doesn't have authority to add this tag.
|
||||||
// Valid tags are tags added by a user that is allowed in the ACL policy to add this tag.
|
// Valid tags are tags added by a user that is allowed in the ACL policy to add this tag.
|
||||||
func (pol *ACLPolicy) TagsOfMachine(
|
func (pol *ACLPolicy) TagsOfNode(
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
) ([]string, []string) {
|
) ([]string, []string) {
|
||||||
validTags := make([]string, 0)
|
validTags := make([]string, 0)
|
||||||
invalidTags := make([]string, 0)
|
invalidTags := make([]string, 0)
|
||||||
|
|
||||||
validTagMap := make(map[string]bool)
|
validTagMap := make(map[string]bool)
|
||||||
invalidTagMap := make(map[string]bool)
|
invalidTagMap := make(map[string]bool)
|
||||||
for _, tag := range machine.HostInfo.RequestTags {
|
for _, tag := range node.HostInfo.RequestTags {
|
||||||
owners, err := expandOwnersFromTag(pol, tag)
|
owners, err := expandOwnersFromTag(pol, tag)
|
||||||
if errors.Is(err, ErrInvalidTag) {
|
if errors.Is(err, ErrInvalidTag) {
|
||||||
invalidTagMap[tag] = true
|
invalidTagMap[tag] = true
|
||||||
|
@ -891,7 +891,7 @@ func (pol *ACLPolicy) TagsOfMachine(
|
||||||
}
|
}
|
||||||
var found bool
|
var found bool
|
||||||
for _, owner := range owners {
|
for _, owner := range owners {
|
||||||
if machine.User.Name == owner {
|
if node.User.Name == owner {
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -911,31 +911,31 @@ func (pol *ACLPolicy) TagsOfMachine(
|
||||||
return validTags, invalidTags
|
return validTags, invalidTags
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterMachinesByUser(machines types.Machines, user string) types.Machines {
|
func filterNodesByUser(nodes types.Nodes, user string) types.Nodes {
|
||||||
out := types.Machines{}
|
out := types.Nodes{}
|
||||||
for _, machine := range machines {
|
for _, node := range nodes {
|
||||||
if machine.User.Name == user {
|
if node.User.Name == user {
|
||||||
out = append(out, machine)
|
out = append(out, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterMachinesByACL returns the list of peers authorized to be accessed from a given machine.
|
// FilterNodesByACL returns the list of peers authorized to be accessed from a given node.
|
||||||
func FilterMachinesByACL(
|
func FilterNodesByACL(
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
machines types.Machines,
|
nodes types.Nodes,
|
||||||
filter []tailcfg.FilterRule,
|
filter []tailcfg.FilterRule,
|
||||||
) types.Machines {
|
) types.Nodes {
|
||||||
result := types.Machines{}
|
result := types.Nodes{}
|
||||||
|
|
||||||
for index, peer := range machines {
|
for index, peer := range nodes {
|
||||||
if peer.ID == machine.ID {
|
if peer.ID == node.ID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if machine.CanAccess(filter, machines[index]) || peer.CanAccess(filter, machine) {
|
if node.CanAccess(filter, nodes[index]) || peer.CanAccess(filter, node) {
|
||||||
result = append(result, peer)
|
result = append(result, peer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,13 +19,13 @@ const (
|
||||||
|
|
||||||
type contextKey string
|
type contextKey string
|
||||||
|
|
||||||
const machineNameContextKey = contextKey("machineName")
|
const nodeNameContextKey = contextKey("nodeName")
|
||||||
|
|
||||||
type UpdateNode func()
|
type UpdateNode func()
|
||||||
|
|
||||||
func logPollFunc(
|
func logPollFunc(
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
isNoise bool,
|
isNoise bool,
|
||||||
) (func(string), func(error, string)) {
|
) (func(string), func(error, string)) {
|
||||||
return func(msg string) {
|
return func(msg string) {
|
||||||
|
@ -35,8 +35,8 @@ func logPollFunc(
|
||||||
Bool("readOnly", mapRequest.ReadOnly).
|
Bool("readOnly", mapRequest.ReadOnly).
|
||||||
Bool("omitPeers", mapRequest.OmitPeers).
|
Bool("omitPeers", mapRequest.OmitPeers).
|
||||||
Bool("stream", mapRequest.Stream).
|
Bool("stream", mapRequest.Stream).
|
||||||
Str("node_key", machine.NodeKey).
|
Str("node_key", node.NodeKey).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg(msg)
|
Msg(msg)
|
||||||
},
|
},
|
||||||
func(err error, msg string) {
|
func(err error, msg string) {
|
||||||
|
@ -46,8 +46,8 @@ func logPollFunc(
|
||||||
Bool("readOnly", mapRequest.ReadOnly).
|
Bool("readOnly", mapRequest.ReadOnly).
|
||||||
Bool("omitPeers", mapRequest.OmitPeers).
|
Bool("omitPeers", mapRequest.OmitPeers).
|
||||||
Bool("stream", mapRequest.Stream).
|
Bool("stream", mapRequest.Stream).
|
||||||
Str("node_key", machine.NodeKey).
|
Str("node_key", node.NodeKey).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg(msg)
|
Msg(msg)
|
||||||
}
|
}
|
||||||
|
@ -60,11 +60,11 @@ func logPollFunc(
|
||||||
func (h *Headscale) handlePoll(
|
func (h *Headscale) handlePoll(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
isNoise bool,
|
isNoise bool,
|
||||||
) {
|
) {
|
||||||
logInfo, logErr := logPollFunc(mapRequest, machine, isNoise)
|
logInfo, logErr := logPollFunc(mapRequest, node, isNoise)
|
||||||
|
|
||||||
// This is the mechanism where the node gives us inforamtion about its
|
// This is the mechanism where the node gives us inforamtion about its
|
||||||
// current configuration.
|
// current configuration.
|
||||||
|
@ -81,28 +81,28 @@ func (h *Headscale) handlePoll(
|
||||||
Bool("readOnly", mapRequest.ReadOnly).
|
Bool("readOnly", mapRequest.ReadOnly).
|
||||||
Bool("omitPeers", mapRequest.OmitPeers).
|
Bool("omitPeers", mapRequest.OmitPeers).
|
||||||
Bool("stream", mapRequest.Stream).
|
Bool("stream", mapRequest.Stream).
|
||||||
Str("node_key", machine.NodeKey).
|
Str("node_key", node.NodeKey).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Strs("endpoints", machine.Endpoints).
|
Strs("endpoints", node.Endpoints).
|
||||||
Msg("Received endpoint update")
|
Msg("Received endpoint update")
|
||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
machine.LastSeen = &now
|
node.LastSeen = &now
|
||||||
machine.Hostname = mapRequest.Hostinfo.Hostname
|
node.Hostname = mapRequest.Hostinfo.Hostname
|
||||||
machine.HostInfo = types.HostInfo(*mapRequest.Hostinfo)
|
node.HostInfo = types.HostInfo(*mapRequest.Hostinfo)
|
||||||
machine.DiscoKey = util.DiscoPublicKeyStripPrefix(mapRequest.DiscoKey)
|
node.DiscoKey = util.DiscoPublicKeyStripPrefix(mapRequest.DiscoKey)
|
||||||
machine.Endpoints = mapRequest.Endpoints
|
node.Endpoints = mapRequest.Endpoints
|
||||||
|
|
||||||
if err := h.db.MachineSave(machine); err != nil {
|
if err := h.db.NodeSave(node); err != nil {
|
||||||
logErr(err, "Failed to persist/update machine in the database")
|
logErr(err, "Failed to persist/update node in the database")
|
||||||
http.Error(writer, "", http.StatusInternalServerError)
|
http.Error(writer, "", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := h.db.SaveMachineRoutes(machine)
|
err := h.db.SaveNodeRoutes(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Error processing machine routes")
|
logErr(err, "Error processing node routes")
|
||||||
http.Error(writer, "", http.StatusInternalServerError)
|
http.Error(writer, "", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -111,9 +111,9 @@ func (h *Headscale) handlePoll(
|
||||||
h.nodeNotifier.NotifyWithIgnore(
|
h.nodeNotifier.NotifyWithIgnore(
|
||||||
types.StateUpdate{
|
types.StateUpdate{
|
||||||
Type: types.StatePeerChanged,
|
Type: types.StatePeerChanged,
|
||||||
Changed: types.Machines{machine},
|
Changed: types.Nodes{node},
|
||||||
},
|
},
|
||||||
machine.MachineKey)
|
node.MachineKey)
|
||||||
|
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
if f, ok := writer.(http.Flusher); ok {
|
if f, ok := writer.(http.Flusher); ok {
|
||||||
|
@ -130,7 +130,7 @@ func (h *Headscale) handlePoll(
|
||||||
// The intended use is for clients to discover the DERP map at
|
// The intended use is for clients to discover the DERP map at
|
||||||
// start-up before their first real endpoint update.
|
// start-up before their first real endpoint update.
|
||||||
} else if mapRequest.OmitPeers && !mapRequest.Stream && mapRequest.ReadOnly {
|
} else if mapRequest.OmitPeers && !mapRequest.Stream && mapRequest.ReadOnly {
|
||||||
h.handleLiteRequest(writer, machine, mapRequest, isNoise)
|
h.handleLiteRequest(writer, node, mapRequest, isNoise)
|
||||||
|
|
||||||
return
|
return
|
||||||
} else if mapRequest.OmitPeers && mapRequest.Stream {
|
} else if mapRequest.OmitPeers && mapRequest.Stream {
|
||||||
|
@ -143,23 +143,23 @@ func (h *Headscale) handlePoll(
|
||||||
// TODO(kradalby): I am not sure if this has any function based on
|
// TODO(kradalby): I am not sure if this has any function based on
|
||||||
// incoming requests from clients.
|
// incoming requests from clients.
|
||||||
if mapRequest.ReadOnly && !mapRequest.Stream {
|
if mapRequest.ReadOnly && !mapRequest.Stream {
|
||||||
h.handleReadOnly(writer, machine, mapRequest, isNoise)
|
h.handleReadOnly(writer, node, mapRequest, isNoise)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
machine.LastSeen = &now
|
node.LastSeen = &now
|
||||||
machine.Hostname = mapRequest.Hostinfo.Hostname
|
node.Hostname = mapRequest.Hostinfo.Hostname
|
||||||
machine.HostInfo = types.HostInfo(*mapRequest.Hostinfo)
|
node.HostInfo = types.HostInfo(*mapRequest.Hostinfo)
|
||||||
machine.DiscoKey = util.DiscoPublicKeyStripPrefix(mapRequest.DiscoKey)
|
node.DiscoKey = util.DiscoPublicKeyStripPrefix(mapRequest.DiscoKey)
|
||||||
machine.Endpoints = mapRequest.Endpoints
|
node.Endpoints = mapRequest.Endpoints
|
||||||
|
|
||||||
// When a node connects to control, list the peers it has at
|
// When a node connects to control, list the peers it has at
|
||||||
// that given point, further updates are kept in memory in
|
// that given point, further updates are kept in memory in
|
||||||
// the Mapper, which lives for the duration of the polling
|
// the Mapper, which lives for the duration of the polling
|
||||||
// session.
|
// session.
|
||||||
peers, err := h.db.ListPeers(machine)
|
peers, err := h.db.ListPeers(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Failed to list peers when opening poller")
|
logErr(err, "Failed to list peers when opening poller")
|
||||||
http.Error(writer, "", http.StatusInternalServerError)
|
http.Error(writer, "", http.StatusInternalServerError)
|
||||||
|
@ -168,7 +168,7 @@ func (h *Headscale) handlePoll(
|
||||||
}
|
}
|
||||||
|
|
||||||
mapp := mapper.NewMapper(
|
mapp := mapper.NewMapper(
|
||||||
machine,
|
node,
|
||||||
peers,
|
peers,
|
||||||
h.privateKey2019,
|
h.privateKey2019,
|
||||||
isNoise,
|
isNoise,
|
||||||
|
@ -179,23 +179,23 @@ func (h *Headscale) handlePoll(
|
||||||
h.cfg.RandomizeClientPort,
|
h.cfg.RandomizeClientPort,
|
||||||
)
|
)
|
||||||
|
|
||||||
err = h.db.SaveMachineRoutes(machine)
|
err = h.db.SaveNodeRoutes(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Error processing machine routes")
|
logErr(err, "Error processing node routes")
|
||||||
}
|
}
|
||||||
|
|
||||||
// update ACLRules with peer informations (to update server tags if necessary)
|
// update ACLRules with peer informations (to update server tags if necessary)
|
||||||
if h.ACLPolicy != nil {
|
if h.ACLPolicy != nil {
|
||||||
// update routes with peer information
|
// update routes with peer information
|
||||||
err = h.db.EnableAutoApprovedRoutes(h.ACLPolicy, machine)
|
err = h.db.EnableAutoApprovedRoutes(h.ACLPolicy, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Error running auto approved routes")
|
logErr(err, "Error running auto approved routes")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(kradalby): Save specific stuff, not whole object.
|
// TODO(kradalby): Save specific stuff, not whole object.
|
||||||
if err := h.db.MachineSave(machine); err != nil {
|
if err := h.db.NodeSave(node); err != nil {
|
||||||
logErr(err, "Failed to persist/update machine in the database")
|
logErr(err, "Failed to persist/update node in the database")
|
||||||
http.Error(writer, "", http.StatusInternalServerError)
|
http.Error(writer, "", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -203,7 +203,7 @@ func (h *Headscale) handlePoll(
|
||||||
|
|
||||||
logInfo("Sending initial map")
|
logInfo("Sending initial map")
|
||||||
|
|
||||||
mapResp, err := mapp.FullMapResponse(mapRequest, machine, h.ACLPolicy)
|
mapResp, err := mapp.FullMapResponse(mapRequest, node, h.ACLPolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Failed to create MapResponse")
|
logErr(err, "Failed to create MapResponse")
|
||||||
http.Error(writer, "", http.StatusInternalServerError)
|
http.Error(writer, "", http.StatusInternalServerError)
|
||||||
|
@ -228,24 +228,24 @@ func (h *Headscale) handlePoll(
|
||||||
h.nodeNotifier.NotifyWithIgnore(
|
h.nodeNotifier.NotifyWithIgnore(
|
||||||
types.StateUpdate{
|
types.StateUpdate{
|
||||||
Type: types.StatePeerChanged,
|
Type: types.StatePeerChanged,
|
||||||
Changed: types.Machines{machine},
|
Changed: types.Nodes{node},
|
||||||
},
|
},
|
||||||
machine.MachineKey)
|
node.MachineKey)
|
||||||
|
|
||||||
// Set up the client stream
|
// Set up the client stream
|
||||||
h.pollNetMapStreamWG.Add(1)
|
h.pollNetMapStreamWG.Add(1)
|
||||||
defer h.pollNetMapStreamWG.Done()
|
defer h.pollNetMapStreamWG.Done()
|
||||||
|
|
||||||
updateChan := make(chan types.StateUpdate)
|
updateChan := make(chan types.StateUpdate)
|
||||||
defer closeChanWithLog(updateChan, machine.Hostname, "updateChan")
|
defer closeChanWithLog(updateChan, node.Hostname, "updateChan")
|
||||||
|
|
||||||
// Register the node's update channel
|
// Register the node's update channel
|
||||||
h.nodeNotifier.AddNode(machine.MachineKey, updateChan)
|
h.nodeNotifier.AddNode(node.MachineKey, updateChan)
|
||||||
defer h.nodeNotifier.RemoveNode(machine.MachineKey)
|
defer h.nodeNotifier.RemoveNode(node.MachineKey)
|
||||||
|
|
||||||
keepAliveTicker := time.NewTicker(keepAliveInterval)
|
keepAliveTicker := time.NewTicker(keepAliveInterval)
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, machineNameContextKey, machine.Hostname)
|
ctx = context.WithValue(ctx, nodeNameContextKey, node.Hostname)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -254,7 +254,7 @@ func (h *Headscale) handlePoll(
|
||||||
logInfo("Waiting for update on stream channel")
|
logInfo("Waiting for update on stream channel")
|
||||||
select {
|
select {
|
||||||
case <-keepAliveTicker.C:
|
case <-keepAliveTicker.C:
|
||||||
data, err := mapp.KeepAliveResponse(mapRequest, machine)
|
data, err := mapp.KeepAliveResponse(mapRequest, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Error generating the keep alive msg")
|
logErr(err, "Error generating the keep alive msg")
|
||||||
|
|
||||||
|
@ -280,9 +280,9 @@ func (h *Headscale) handlePoll(
|
||||||
// goroutines, but then you might have a problem without a lock
|
// goroutines, but then you might have a problem without a lock
|
||||||
// if a keepalive is written at the same time as an update.
|
// if a keepalive is written at the same time as an update.
|
||||||
go func() {
|
go func() {
|
||||||
err = h.db.UpdateLastSeen(machine)
|
err = h.db.UpdateLastSeen(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Cannot update machine LastSeen")
|
logErr(err, "Cannot update node LastSeen")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -298,16 +298,16 @@ func (h *Headscale) handlePoll(
|
||||||
switch update.Type {
|
switch update.Type {
|
||||||
case types.StatePeerChanged:
|
case types.StatePeerChanged:
|
||||||
logInfo("Sending PeerChanged MapResponse")
|
logInfo("Sending PeerChanged MapResponse")
|
||||||
data, err = mapp.PeerChangedResponse(mapRequest, machine, update.Changed, h.ACLPolicy)
|
data, err = mapp.PeerChangedResponse(mapRequest, node, update.Changed, h.ACLPolicy)
|
||||||
case types.StatePeerRemoved:
|
case types.StatePeerRemoved:
|
||||||
logInfo("Sending PeerRemoved MapResponse")
|
logInfo("Sending PeerRemoved MapResponse")
|
||||||
data, err = mapp.PeerRemovedResponse(mapRequest, machine, update.Removed)
|
data, err = mapp.PeerRemovedResponse(mapRequest, node, update.Removed)
|
||||||
case types.StateDERPUpdated:
|
case types.StateDERPUpdated:
|
||||||
logInfo("Sending DERPUpdate MapResponse")
|
logInfo("Sending DERPUpdate MapResponse")
|
||||||
data, err = mapp.DERPMapResponse(mapRequest, machine, update.DERPMap)
|
data, err = mapp.DERPMapResponse(mapRequest, node, update.DERPMap)
|
||||||
case types.StateFullUpdate:
|
case types.StateFullUpdate:
|
||||||
logInfo("Sending Full MapResponse")
|
logInfo("Sending Full MapResponse")
|
||||||
data, err = mapp.FullMapResponse(mapRequest, machine, h.ACLPolicy)
|
data, err = mapp.FullMapResponse(mapRequest, node, h.ACLPolicy)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -320,7 +320,7 @@ func (h *Headscale) handlePoll(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Could not write the map response")
|
logErr(err, "Could not write the map response")
|
||||||
|
|
||||||
updateRequestsSentToNode.WithLabelValues(machine.User.Name, machine.Hostname, "failed").
|
updateRequestsSentToNode.WithLabelValues(node.User.Name, node.Hostname, "failed").
|
||||||
Inc()
|
Inc()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -336,9 +336,9 @@ func (h *Headscale) handlePoll(
|
||||||
|
|
||||||
// See comment in keepAliveTicker
|
// See comment in keepAliveTicker
|
||||||
go func() {
|
go func() {
|
||||||
err = h.db.UpdateLastSeen(machine)
|
err = h.db.UpdateLastSeen(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Cannot update machine LastSeen")
|
logErr(err, "Cannot update node LastSeen")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -350,17 +350,17 @@ func (h *Headscale) handlePoll(
|
||||||
Bool("readOnly", mapRequest.ReadOnly).
|
Bool("readOnly", mapRequest.ReadOnly).
|
||||||
Bool("omitPeers", mapRequest.OmitPeers).
|
Bool("omitPeers", mapRequest.OmitPeers).
|
||||||
Bool("stream", mapRequest.Stream).
|
Bool("stream", mapRequest.Stream).
|
||||||
Str("node_key", machine.NodeKey).
|
Str("node_key", node.NodeKey).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
TimeDiff("timeSpent", time.Now(), now).
|
TimeDiff("timeSpent", time.Now(), now).
|
||||||
Msg("update sent")
|
Msg("update sent")
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
logInfo("The client has closed the connection")
|
logInfo("The client has closed the connection")
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err = h.db.UpdateLastSeen(machine)
|
err = h.db.UpdateLastSeen(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Cannot update machine LastSeen")
|
logErr(err, "Cannot update node LastSeen")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -377,10 +377,10 @@ func (h *Headscale) handlePoll(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func closeChanWithLog[C chan []byte | chan struct{} | chan types.StateUpdate](channel C, machine, name string) {
|
func closeChanWithLog[C chan []byte | chan struct{} | chan types.StateUpdate](channel C, node, name string) {
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Str("handler", "PollNetMap").
|
Str("handler", "PollNetMap").
|
||||||
Str("machine", machine).
|
Str("node", node).
|
||||||
Str("channel", "Done").
|
Str("channel", "Done").
|
||||||
Msg(fmt.Sprintf("Closing %s channel", name))
|
Msg(fmt.Sprintf("Closing %s channel", name))
|
||||||
|
|
||||||
|
@ -392,17 +392,17 @@ func closeChanWithLog[C chan []byte | chan struct{} | chan types.StateUpdate](ch
|
||||||
// is not.
|
// is not.
|
||||||
func (h *Headscale) handleReadOnly(
|
func (h *Headscale) handleReadOnly(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
isNoise bool,
|
isNoise bool,
|
||||||
) {
|
) {
|
||||||
logInfo, logErr := logPollFunc(mapRequest, machine, isNoise)
|
logInfo, logErr := logPollFunc(mapRequest, node, isNoise)
|
||||||
|
|
||||||
mapp := mapper.NewMapper(
|
mapp := mapper.NewMapper(
|
||||||
machine,
|
node,
|
||||||
// TODO(kradalby): It might not be acceptable to send
|
// TODO(kradalby): It might not be acceptable to send
|
||||||
// an empty peer list here.
|
// an empty peer list here.
|
||||||
types.Machines{},
|
types.Nodes{},
|
||||||
h.privateKey2019,
|
h.privateKey2019,
|
||||||
isNoise,
|
isNoise,
|
||||||
h.DERPMap,
|
h.DERPMap,
|
||||||
|
@ -413,7 +413,7 @@ func (h *Headscale) handleReadOnly(
|
||||||
)
|
)
|
||||||
logInfo("Client is starting up. Probably interested in a DERP map")
|
logInfo("Client is starting up. Probably interested in a DERP map")
|
||||||
|
|
||||||
mapResp, err := mapp.FullMapResponse(mapRequest, machine, h.ACLPolicy)
|
mapResp, err := mapp.FullMapResponse(mapRequest, node, h.ACLPolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Failed to create MapResponse")
|
logErr(err, "Failed to create MapResponse")
|
||||||
http.Error(writer, "", http.StatusInternalServerError)
|
http.Error(writer, "", http.StatusInternalServerError)
|
||||||
|
@ -435,17 +435,17 @@ func (h *Headscale) handleReadOnly(
|
||||||
|
|
||||||
func (h *Headscale) handleLiteRequest(
|
func (h *Headscale) handleLiteRequest(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
machine *types.Machine,
|
node *types.Node,
|
||||||
mapRequest tailcfg.MapRequest,
|
mapRequest tailcfg.MapRequest,
|
||||||
isNoise bool,
|
isNoise bool,
|
||||||
) {
|
) {
|
||||||
logInfo, logErr := logPollFunc(mapRequest, machine, isNoise)
|
logInfo, logErr := logPollFunc(mapRequest, node, isNoise)
|
||||||
|
|
||||||
mapp := mapper.NewMapper(
|
mapp := mapper.NewMapper(
|
||||||
machine,
|
node,
|
||||||
// TODO(kradalby): It might not be acceptable to send
|
// TODO(kradalby): It might not be acceptable to send
|
||||||
// an empty peer list here.
|
// an empty peer list here.
|
||||||
types.Machines{},
|
types.Nodes{},
|
||||||
h.privateKey2019,
|
h.privateKey2019,
|
||||||
isNoise,
|
isNoise,
|
||||||
h.DERPMap,
|
h.DERPMap,
|
||||||
|
@ -457,7 +457,7 @@ func (h *Headscale) handleLiteRequest(
|
||||||
|
|
||||||
logInfo("Client asked for a lite update, responding without peers")
|
logInfo("Client asked for a lite update, responding without peers")
|
||||||
|
|
||||||
mapResp, err := mapp.LiteMapResponse(mapRequest, machine, h.ACLPolicy)
|
mapResp, err := mapp.LiteMapResponse(mapRequest, node, h.ACLPolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logErr(err, "Failed to create MapResponse")
|
logErr(err, "Failed to create MapResponse")
|
||||||
http.Error(writer, "", http.StatusInternalServerError)
|
http.Error(writer, "", http.StatusInternalServerError)
|
||||||
|
|
|
@ -68,12 +68,12 @@ func (h *Headscale) PollNetMapHandler(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
machine, err := h.db.GetMachineByMachineKey(machineKey)
|
node, err := h.db.GetNodeByMachineKey(machineKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
log.Warn().
|
log.Warn().
|
||||||
Str("handler", "PollNetMap").
|
Str("handler", "PollNetMap").
|
||||||
Msgf("Ignoring request, cannot find machine with key %s", machineKey.String())
|
Msgf("Ignoring request, cannot find node with key %s", machineKey.String())
|
||||||
|
|
||||||
http.Error(writer, "", http.StatusUnauthorized)
|
http.Error(writer, "", http.StatusUnauthorized)
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ func (h *Headscale) PollNetMapHandler(
|
||||||
}
|
}
|
||||||
log.Error().
|
log.Error().
|
||||||
Str("handler", "PollNetMap").
|
Str("handler", "PollNetMap").
|
||||||
Msgf("Failed to fetch machine from the database with Machine key: %s", machineKey.String())
|
Msgf("Failed to fetch node from the database with Machine key: %s", machineKey.String())
|
||||||
http.Error(writer, "", http.StatusInternalServerError)
|
http.Error(writer, "", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -90,8 +90,8 @@ func (h *Headscale) PollNetMapHandler(
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Str("handler", "PollNetMap").
|
Str("handler", "PollNetMap").
|
||||||
Str("id", machineKeyStr).
|
Str("id", machineKeyStr).
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("A machine is sending a MapRequest via legacy protocol")
|
Msg("A node is sending a MapRequest via legacy protocol")
|
||||||
|
|
||||||
h.handlePoll(writer, req.Context(), machine, mapRequest, false)
|
h.handlePoll(writer, req.Context(), node, mapRequest, false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ func (ns *noiseServer) NoisePollNetMapHandler(
|
||||||
|
|
||||||
ns.nodeKey = mapRequest.NodeKey
|
ns.nodeKey = mapRequest.NodeKey
|
||||||
|
|
||||||
machine, err := ns.headscale.db.GetMachineByAnyKey(
|
node, err := ns.headscale.db.GetNodeByAnyKey(
|
||||||
ns.conn.Peer(),
|
ns.conn.Peer(),
|
||||||
mapRequest.NodeKey,
|
mapRequest.NodeKey,
|
||||||
key.NodePublic{},
|
key.NodePublic{},
|
||||||
|
@ -58,22 +58,22 @@ func (ns *noiseServer) NoisePollNetMapHandler(
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
log.Warn().
|
log.Warn().
|
||||||
Str("handler", "NoisePollNetMap").
|
Str("handler", "NoisePollNetMap").
|
||||||
Msgf("Ignoring request, cannot find machine with key %s", mapRequest.NodeKey.String())
|
Msgf("Ignoring request, cannot find node with key %s", mapRequest.NodeKey.String())
|
||||||
http.Error(writer, "Internal error", http.StatusNotFound)
|
http.Error(writer, "Internal error", http.StatusNotFound)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Error().
|
log.Error().
|
||||||
Str("handler", "NoisePollNetMap").
|
Str("handler", "NoisePollNetMap").
|
||||||
Msgf("Failed to fetch machine from the database with node key: %s", mapRequest.NodeKey.String())
|
Msgf("Failed to fetch node from the database with node key: %s", mapRequest.NodeKey.String())
|
||||||
http.Error(writer, "Internal error", http.StatusInternalServerError)
|
http.Error(writer, "Internal error", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug().
|
log.Debug().
|
||||||
Str("handler", "NoisePollNetMap").
|
Str("handler", "NoisePollNetMap").
|
||||||
Str("machine", machine.Hostname).
|
Str("node", node.Hostname).
|
||||||
Msg("A machine sending a MapRequest with Noise protocol")
|
Msg("A node sending a MapRequest with Noise protocol")
|
||||||
|
|
||||||
ns.headscale.handlePoll(writer, req.Context(), machine, mapRequest, true)
|
ns.headscale.handlePoll(writer, req.Context(), node, mapRequest, true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ func (hi *HostInfo) Scan(destination interface{}) error {
|
||||||
return json.Unmarshal([]byte(value), hi)
|
return json.Unmarshal([]byte(value), hi)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: unexpected data type %T", ErrMachineAddressesInvalid, destination)
|
return fmt.Errorf("%w: unexpected data type %T", ErrNodeAddressesInvalid, destination)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ func (i *IPPrefixes) Scan(destination interface{}) error {
|
||||||
return json.Unmarshal([]byte(value), i)
|
return json.Unmarshal([]byte(value), i)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: unexpected data type %T", ErrMachineAddressesInvalid, destination)
|
return fmt.Errorf("%w: unexpected data type %T", ErrNodeAddressesInvalid, destination)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ func (i *StringList) Scan(destination interface{}) error {
|
||||||
return json.Unmarshal([]byte(value), i)
|
return json.Unmarshal([]byte(value), i)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: unexpected data type %T", ErrMachineAddressesInvalid, destination)
|
return fmt.Errorf("%w: unexpected data type %T", ErrNodeAddressesInvalid, destination)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,8 +123,8 @@ type StateUpdate struct {
|
||||||
Type StateUpdateType
|
Type StateUpdateType
|
||||||
|
|
||||||
// Changed must be set when Type is StatePeerChanged and
|
// Changed must be set when Type is StatePeerChanged and
|
||||||
// contain the Machine IDs of machines that has changed.
|
// contain the Node IDs of nodes that have changed.
|
||||||
Changed Machines
|
Changed Nodes
|
||||||
|
|
||||||
// Removed must be set when Type is StatePeerRemoved and
|
// Removed must be set when Type is StatePeerRemoved and
|
||||||
// contain a list of the nodes that has been removed from
|
// contain a list of the nodes that has been removed from
|
||||||
|
|
|
@ -1,346 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql/driver"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/netip"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
|
||||||
"github.com/juanfont/headscale/hscontrol/policy/matcher"
|
|
||||||
"github.com/juanfont/headscale/hscontrol/util"
|
|
||||||
"go4.org/netipx"
|
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
|
||||||
"tailscale.com/tailcfg"
|
|
||||||
"tailscale.com/types/key"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrMachineAddressesInvalid = errors.New("failed to parse machine addresses")
|
|
||||||
ErrHostnameTooLong = errors.New("hostname too long")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Machine is a Headscale client.
|
|
||||||
type Machine struct {
|
|
||||||
ID uint64 `gorm:"primary_key"`
|
|
||||||
MachineKey string `gorm:"type:varchar(64);unique_index"`
|
|
||||||
NodeKey string
|
|
||||||
DiscoKey string
|
|
||||||
IPAddresses MachineAddresses
|
|
||||||
|
|
||||||
// Hostname represents the name given by the Tailscale
|
|
||||||
// client during registration
|
|
||||||
Hostname string
|
|
||||||
|
|
||||||
// Givenname represents either:
|
|
||||||
// a DNS normalized version of Hostname
|
|
||||||
// a valid name set by the User
|
|
||||||
//
|
|
||||||
// GivenName is the name used in all DNS related
|
|
||||||
// parts of headscale.
|
|
||||||
GivenName string `gorm:"type:varchar(63);unique_index"`
|
|
||||||
UserID uint
|
|
||||||
User User `gorm:"foreignKey:UserID"`
|
|
||||||
|
|
||||||
RegisterMethod string
|
|
||||||
|
|
||||||
ForcedTags StringList
|
|
||||||
|
|
||||||
// TODO(kradalby): This seems like irrelevant information?
|
|
||||||
AuthKeyID uint
|
|
||||||
AuthKey *PreAuthKey
|
|
||||||
|
|
||||||
LastSeen *time.Time
|
|
||||||
Expiry *time.Time
|
|
||||||
|
|
||||||
HostInfo HostInfo
|
|
||||||
Endpoints StringList
|
|
||||||
|
|
||||||
Routes []Route
|
|
||||||
|
|
||||||
CreatedAt time.Time
|
|
||||||
UpdatedAt time.Time
|
|
||||||
DeletedAt *time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type (
|
|
||||||
Machines []*Machine
|
|
||||||
)
|
|
||||||
|
|
||||||
type MachineAddresses []netip.Addr
|
|
||||||
|
|
||||||
func (ma MachineAddresses) Sort() {
|
|
||||||
sort.Slice(ma, func(index1, index2 int) bool {
|
|
||||||
if ma[index1].Is4() && ma[index2].Is6() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if ma[index1].Is6() && ma[index2].Is4() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return ma[index1].Compare(ma[index2]) < 0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma MachineAddresses) StringSlice() []string {
|
|
||||||
ma.Sort()
|
|
||||||
strSlice := make([]string, 0, len(ma))
|
|
||||||
for _, addr := range ma {
|
|
||||||
strSlice = append(strSlice, addr.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return strSlice
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma MachineAddresses) Prefixes() []netip.Prefix {
|
|
||||||
addrs := []netip.Prefix{}
|
|
||||||
for _, machineAddress := range ma {
|
|
||||||
ip := netip.PrefixFrom(machineAddress, machineAddress.BitLen())
|
|
||||||
addrs = append(addrs, ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
return addrs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma MachineAddresses) InIPSet(set *netipx.IPSet) bool {
|
|
||||||
for _, machineAddr := range ma {
|
|
||||||
if set.Contains(machineAddr) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendToIPSet adds the individual ips in MachineAddresses to a
|
|
||||||
// given netipx.IPSetBuilder.
|
|
||||||
func (ma MachineAddresses) AppendToIPSet(build *netipx.IPSetBuilder) {
|
|
||||||
for _, ip := range ma {
|
|
||||||
build.Add(ip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *MachineAddresses) Scan(destination interface{}) error {
|
|
||||||
switch value := destination.(type) {
|
|
||||||
case string:
|
|
||||||
addresses := strings.Split(value, ",")
|
|
||||||
*ma = (*ma)[:0]
|
|
||||||
for _, addr := range addresses {
|
|
||||||
if len(addr) < 1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parsed, err := netip.ParseAddr(addr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*ma = append(*ma, parsed)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("%w: unexpected data type %T", ErrMachineAddressesInvalid, destination)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value return json value, implement driver.Valuer interface.
|
|
||||||
func (ma MachineAddresses) Value() (driver.Value, error) {
|
|
||||||
addresses := strings.Join(ma.StringSlice(), ",")
|
|
||||||
|
|
||||||
return addresses, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsExpired returns whether the machine registration has expired.
|
|
||||||
func (machine Machine) IsExpired() bool {
|
|
||||||
// If Expiry is not set, the client has not indicated that
|
|
||||||
// it wants an expiry time, it is therefor considered
|
|
||||||
// to mean "not expired"
|
|
||||||
if machine.Expiry == nil || machine.Expiry.IsZero() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return time.Now().UTC().After(*machine.Expiry)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsOnline returns if the machine is connected to Headscale.
|
|
||||||
// This is really a naive implementation, as we don't really see
|
|
||||||
// if there is a working connection between the client and the server.
|
|
||||||
func (machine *Machine) IsOnline() bool {
|
|
||||||
if machine.LastSeen == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if machine.IsExpired() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return machine.LastSeen.After(time.Now().Add(-KeepAliveInterval))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsEphemeral returns if the machine is registered as an Ephemeral node.
|
|
||||||
// https://tailscale.com/kb/1111/ephemeral-nodes/
|
|
||||||
func (machine *Machine) IsEphemeral() bool {
|
|
||||||
return machine.AuthKey != nil && machine.AuthKey.Ephemeral
|
|
||||||
}
|
|
||||||
|
|
||||||
func (machine *Machine) CanAccess(filter []tailcfg.FilterRule, machine2 *Machine) bool {
|
|
||||||
for _, rule := range filter {
|
|
||||||
// TODO(kradalby): Cache or pregen this
|
|
||||||
matcher := matcher.MatchFromFilterRule(rule)
|
|
||||||
|
|
||||||
if !matcher.SrcsContainsIPs([]netip.Addr(machine.IPAddresses)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if matcher.DestsContainsIP([]netip.Addr(machine2.IPAddresses)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (machines Machines) FilterByIP(ip netip.Addr) Machines {
|
|
||||||
found := make(Machines, 0)
|
|
||||||
|
|
||||||
for _, machine := range machines {
|
|
||||||
for _, mIP := range machine.IPAddresses {
|
|
||||||
if ip == mIP {
|
|
||||||
found = append(found, machine)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found
|
|
||||||
}
|
|
||||||
|
|
||||||
func (machine *Machine) Proto() *v1.Machine {
|
|
||||||
machineProto := &v1.Machine{
|
|
||||||
Id: machine.ID,
|
|
||||||
MachineKey: machine.MachineKey,
|
|
||||||
|
|
||||||
NodeKey: machine.NodeKey,
|
|
||||||
DiscoKey: machine.DiscoKey,
|
|
||||||
IpAddresses: machine.IPAddresses.StringSlice(),
|
|
||||||
Name: machine.Hostname,
|
|
||||||
GivenName: machine.GivenName,
|
|
||||||
User: machine.User.Proto(),
|
|
||||||
ForcedTags: machine.ForcedTags,
|
|
||||||
Online: machine.IsOnline(),
|
|
||||||
|
|
||||||
// TODO(kradalby): Implement register method enum converter
|
|
||||||
// RegisterMethod: ,
|
|
||||||
|
|
||||||
CreatedAt: timestamppb.New(machine.CreatedAt),
|
|
||||||
}
|
|
||||||
|
|
||||||
if machine.AuthKey != nil {
|
|
||||||
machineProto.PreAuthKey = machine.AuthKey.Proto()
|
|
||||||
}
|
|
||||||
|
|
||||||
if machine.LastSeen != nil {
|
|
||||||
machineProto.LastSeen = timestamppb.New(*machine.LastSeen)
|
|
||||||
}
|
|
||||||
|
|
||||||
if machine.Expiry != nil {
|
|
||||||
machineProto.Expiry = timestamppb.New(*machine.Expiry)
|
|
||||||
}
|
|
||||||
|
|
||||||
return machineProto
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHostInfo returns a Hostinfo struct for the machine.
|
|
||||||
func (machine *Machine) GetHostInfo() tailcfg.Hostinfo {
|
|
||||||
return tailcfg.Hostinfo(machine.HostInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (machine *Machine) GetFQDN(dnsConfig *tailcfg.DNSConfig, baseDomain string) (string, error) {
|
|
||||||
var hostname string
|
|
||||||
if dnsConfig != nil && dnsConfig.Proxied { // MagicDNS
|
|
||||||
hostname = fmt.Sprintf(
|
|
||||||
"%s.%s.%s",
|
|
||||||
machine.GivenName,
|
|
||||||
machine.User.Name,
|
|
||||||
baseDomain,
|
|
||||||
)
|
|
||||||
if len(hostname) > MaxHostnameLength {
|
|
||||||
return "", fmt.Errorf(
|
|
||||||
"hostname %q is too long it cannot except 255 ASCII chars: %w",
|
|
||||||
hostname,
|
|
||||||
ErrHostnameTooLong,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hostname = machine.GivenName
|
|
||||||
}
|
|
||||||
|
|
||||||
return hostname, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (machine *Machine) MachinePublicKey() (key.MachinePublic, error) {
|
|
||||||
var machineKey key.MachinePublic
|
|
||||||
|
|
||||||
if machine.MachineKey != "" {
|
|
||||||
err := machineKey.UnmarshalText(
|
|
||||||
[]byte(util.MachinePublicKeyEnsurePrefix(machine.MachineKey)),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return key.MachinePublic{}, fmt.Errorf("failed to parse machine public key: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return machineKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (machine *Machine) DiscoPublicKey() (key.DiscoPublic, error) {
|
|
||||||
var discoKey key.DiscoPublic
|
|
||||||
if machine.DiscoKey != "" {
|
|
||||||
err := discoKey.UnmarshalText(
|
|
||||||
[]byte(util.DiscoPublicKeyEnsurePrefix(machine.DiscoKey)),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return key.DiscoPublic{}, fmt.Errorf("failed to parse disco public key: %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
discoKey = key.DiscoPublic{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return discoKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (machine *Machine) NodePublicKey() (key.NodePublic, error) {
|
|
||||||
var nodeKey key.NodePublic
|
|
||||||
err := nodeKey.UnmarshalText([]byte(util.NodePublicKeyEnsurePrefix(machine.NodeKey)))
|
|
||||||
if err != nil {
|
|
||||||
return key.NodePublic{}, fmt.Errorf("failed to parse node public key: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodeKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (machine Machine) String() string {
|
|
||||||
return machine.Hostname
|
|
||||||
}
|
|
||||||
|
|
||||||
func (machines Machines) String() string {
|
|
||||||
temp := make([]string, len(machines))
|
|
||||||
|
|
||||||
for index, machine := range machines {
|
|
||||||
temp[index] = machine.Hostname
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("[ %s ](%d)", strings.Join(temp, ", "), len(temp))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (machines Machines) IDMap() map[uint64]*Machine {
|
|
||||||
ret := map[uint64]*Machine{}
|
|
||||||
|
|
||||||
for _, machine := range machines {
|
|
||||||
ret[machine.ID] = machine
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
346
hscontrol/types/node.go
Normal file
346
hscontrol/types/node.go
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
||||||
|
"github.com/juanfont/headscale/hscontrol/policy/matcher"
|
||||||
|
"github.com/juanfont/headscale/hscontrol/util"
|
||||||
|
"go4.org/netipx"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
|
"tailscale.com/types/key"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNodeAddressesInvalid = errors.New("failed to parse node addresses")
|
||||||
|
ErrHostnameTooLong = errors.New("hostname too long")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Node is a Headscale client.
|
||||||
|
type Node struct {
|
||||||
|
ID uint64 `gorm:"primary_key"`
|
||||||
|
MachineKey string `gorm:"type:varchar(64);unique_index"`
|
||||||
|
NodeKey string
|
||||||
|
DiscoKey string
|
||||||
|
IPAddresses NodeAddresses
|
||||||
|
|
||||||
|
// Hostname represents the name given by the Tailscale
|
||||||
|
// client during registration
|
||||||
|
Hostname string
|
||||||
|
|
||||||
|
// Givenname represents either:
|
||||||
|
// a DNS normalized version of Hostname
|
||||||
|
// a valid name set by the User
|
||||||
|
//
|
||||||
|
// GivenName is the name used in all DNS related
|
||||||
|
// parts of headscale.
|
||||||
|
GivenName string `gorm:"type:varchar(63);unique_index"`
|
||||||
|
UserID uint
|
||||||
|
User User `gorm:"foreignKey:UserID"`
|
||||||
|
|
||||||
|
RegisterMethod string
|
||||||
|
|
||||||
|
ForcedTags StringList
|
||||||
|
|
||||||
|
// TODO(kradalby): This seems like irrelevant information?
|
||||||
|
AuthKeyID uint
|
||||||
|
AuthKey *PreAuthKey
|
||||||
|
|
||||||
|
LastSeen *time.Time
|
||||||
|
Expiry *time.Time
|
||||||
|
|
||||||
|
HostInfo HostInfo
|
||||||
|
Endpoints StringList
|
||||||
|
|
||||||
|
Routes []Route
|
||||||
|
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
DeletedAt *time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
Nodes []*Node
|
||||||
|
)
|
||||||
|
|
||||||
|
type NodeAddresses []netip.Addr
|
||||||
|
|
||||||
|
func (na NodeAddresses) Sort() {
|
||||||
|
sort.Slice(na, func(index1, index2 int) bool {
|
||||||
|
if na[index1].Is4() && na[index2].Is6() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if na[index1].Is6() && na[index2].Is4() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return na[index1].Compare(na[index2]) < 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (na NodeAddresses) StringSlice() []string {
|
||||||
|
na.Sort()
|
||||||
|
strSlice := make([]string, 0, len(na))
|
||||||
|
for _, addr := range na {
|
||||||
|
strSlice = append(strSlice, addr.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return strSlice
|
||||||
|
}
|
||||||
|
|
||||||
|
func (na NodeAddresses) Prefixes() []netip.Prefix {
|
||||||
|
addrs := []netip.Prefix{}
|
||||||
|
for _, nodeAddress := range na {
|
||||||
|
ip := netip.PrefixFrom(nodeAddress, nodeAddress.BitLen())
|
||||||
|
addrs = append(addrs, ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
return addrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (na NodeAddresses) InIPSet(set *netipx.IPSet) bool {
|
||||||
|
for _, nodeAddr := range na {
|
||||||
|
if set.Contains(nodeAddr) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendToIPSet adds the individual ips in NodeAddresses to a
|
||||||
|
// given netipx.IPSetBuilder.
|
||||||
|
func (na NodeAddresses) AppendToIPSet(build *netipx.IPSetBuilder) {
|
||||||
|
for _, ip := range na {
|
||||||
|
build.Add(ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (na *NodeAddresses) Scan(destination interface{}) error {
|
||||||
|
switch value := destination.(type) {
|
||||||
|
case string:
|
||||||
|
addresses := strings.Split(value, ",")
|
||||||
|
*na = (*na)[:0]
|
||||||
|
for _, addr := range addresses {
|
||||||
|
if len(addr) < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parsed, err := netip.ParseAddr(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*na = append(*na, parsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("%w: unexpected data type %T", ErrNodeAddressesInvalid, destination)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value return json value, implement driver.Valuer interface.
|
||||||
|
func (na NodeAddresses) Value() (driver.Value, error) {
|
||||||
|
addresses := strings.Join(na.StringSlice(), ",")
|
||||||
|
|
||||||
|
return addresses, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns whether the node registration has expired.
|
||||||
|
func (node Node) IsExpired() bool {
|
||||||
|
// If Expiry is not set, the client has not indicated that
|
||||||
|
// it wants an expiry time, it is therefor considered
|
||||||
|
// to mean "not expired"
|
||||||
|
if node.Expiry == nil || node.Expiry.IsZero() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Now().UTC().After(*node.Expiry)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsOnline returns if the node is connected to Headscale.
|
||||||
|
// This is really a naive implementation, as we don't really see
|
||||||
|
// if there is a working connection between the client and the server.
|
||||||
|
func (node *Node) IsOnline() bool {
|
||||||
|
if node.LastSeen == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.IsExpired() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.LastSeen.After(time.Now().Add(-KeepAliveInterval))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEphemeral returns if the node is registered as an Ephemeral node.
|
||||||
|
// https://tailscale.com/kb/1111/ephemeral-nodes/
|
||||||
|
func (node *Node) IsEphemeral() bool {
|
||||||
|
return node.AuthKey != nil && node.AuthKey.Ephemeral
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node) CanAccess(filter []tailcfg.FilterRule, node2 *Node) bool {
|
||||||
|
for _, rule := range filter {
|
||||||
|
// TODO(kradalby): Cache or pregen this
|
||||||
|
matcher := matcher.MatchFromFilterRule(rule)
|
||||||
|
|
||||||
|
if !matcher.SrcsContainsIPs([]netip.Addr(node.IPAddresses)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if matcher.DestsContainsIP([]netip.Addr(node2.IPAddresses)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nodes Nodes) FilterByIP(ip netip.Addr) Nodes {
|
||||||
|
found := make(Nodes, 0)
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
for _, mIP := range node.IPAddresses {
|
||||||
|
if ip == mIP {
|
||||||
|
found = append(found, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node) Proto() *v1.Node {
|
||||||
|
nodeProto := &v1.Node{
|
||||||
|
Id: node.ID,
|
||||||
|
MachineKey: node.MachineKey,
|
||||||
|
|
||||||
|
NodeKey: node.NodeKey,
|
||||||
|
DiscoKey: node.DiscoKey,
|
||||||
|
IpAddresses: node.IPAddresses.StringSlice(),
|
||||||
|
Name: node.Hostname,
|
||||||
|
GivenName: node.GivenName,
|
||||||
|
User: node.User.Proto(),
|
||||||
|
ForcedTags: node.ForcedTags,
|
||||||
|
Online: node.IsOnline(),
|
||||||
|
|
||||||
|
// TODO(kradalby): Implement register method enum converter
|
||||||
|
// RegisterMethod: ,
|
||||||
|
|
||||||
|
CreatedAt: timestamppb.New(node.CreatedAt),
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.AuthKey != nil {
|
||||||
|
nodeProto.PreAuthKey = node.AuthKey.Proto()
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.LastSeen != nil {
|
||||||
|
nodeProto.LastSeen = timestamppb.New(*node.LastSeen)
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.Expiry != nil {
|
||||||
|
nodeProto.Expiry = timestamppb.New(*node.Expiry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeProto
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHostInfo returns a Hostinfo struct for the node.
|
||||||
|
func (node *Node) GetHostInfo() tailcfg.Hostinfo {
|
||||||
|
return tailcfg.Hostinfo(node.HostInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node) GetFQDN(dnsConfig *tailcfg.DNSConfig, baseDomain string) (string, error) {
|
||||||
|
var hostname string
|
||||||
|
if dnsConfig != nil && dnsConfig.Proxied { // MagicDNS
|
||||||
|
hostname = fmt.Sprintf(
|
||||||
|
"%s.%s.%s",
|
||||||
|
node.GivenName,
|
||||||
|
node.User.Name,
|
||||||
|
baseDomain,
|
||||||
|
)
|
||||||
|
if len(hostname) > MaxHostnameLength {
|
||||||
|
return "", fmt.Errorf(
|
||||||
|
"hostname %q is too long it cannot except 255 ASCII chars: %w",
|
||||||
|
hostname,
|
||||||
|
ErrHostnameTooLong,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hostname = node.GivenName
|
||||||
|
}
|
||||||
|
|
||||||
|
return hostname, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node) MachinePublicKey() (key.MachinePublic, error) {
|
||||||
|
var machineKey key.MachinePublic
|
||||||
|
|
||||||
|
if node.MachineKey != "" {
|
||||||
|
err := machineKey.UnmarshalText(
|
||||||
|
[]byte(util.MachinePublicKeyEnsurePrefix(node.MachineKey)),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return key.MachinePublic{}, fmt.Errorf("failed to parse machine public key: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return machineKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node) DiscoPublicKey() (key.DiscoPublic, error) {
|
||||||
|
var discoKey key.DiscoPublic
|
||||||
|
if node.DiscoKey != "" {
|
||||||
|
err := discoKey.UnmarshalText(
|
||||||
|
[]byte(util.DiscoPublicKeyEnsurePrefix(node.DiscoKey)),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return key.DiscoPublic{}, fmt.Errorf("failed to parse disco public key: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
discoKey = key.DiscoPublic{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return discoKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node) NodePublicKey() (key.NodePublic, error) {
|
||||||
|
var nodeKey key.NodePublic
|
||||||
|
err := nodeKey.UnmarshalText([]byte(util.NodePublicKeyEnsurePrefix(node.NodeKey)))
|
||||||
|
if err != nil {
|
||||||
|
return key.NodePublic{}, fmt.Errorf("failed to parse node public key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node Node) String() string {
|
||||||
|
return node.Hostname
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nodes Nodes) String() string {
|
||||||
|
temp := make([]string, len(nodes))
|
||||||
|
|
||||||
|
for index, node := range nodes {
|
||||||
|
temp[index] = node.Hostname
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("[ %s ](%d)", strings.Join(temp, ", "), len(temp))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nodes Nodes) IDMap() map[uint64]*Node {
|
||||||
|
ret := map[uint64]*Node{}
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
ret[node.ID] = node
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
|
@ -7,20 +7,20 @@ import (
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_MachineCanAccess(t *testing.T) {
|
func Test_NodeCanAccess(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
machine1 Machine
|
node1 Node
|
||||||
machine2 Machine
|
node2 Node
|
||||||
rules []tailcfg.FilterRule
|
rules []tailcfg.FilterRule
|
||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no-rules",
|
name: "no-rules",
|
||||||
machine1: Machine{
|
node1: Node{
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("10.0.0.1")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("10.0.0.1")},
|
||||||
},
|
},
|
||||||
machine2: Machine{
|
node2: Node{
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("10.0.0.2")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("10.0.0.2")},
|
||||||
},
|
},
|
||||||
rules: []tailcfg.FilterRule{},
|
rules: []tailcfg.FilterRule{},
|
||||||
|
@ -28,10 +28,10 @@ func Test_MachineCanAccess(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wildcard",
|
name: "wildcard",
|
||||||
machine1: Machine{
|
node1: Node{
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("10.0.0.1")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("10.0.0.1")},
|
||||||
},
|
},
|
||||||
machine2: Machine{
|
node2: Node{
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("10.0.0.2")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("10.0.0.2")},
|
||||||
},
|
},
|
||||||
rules: []tailcfg.FilterRule{
|
rules: []tailcfg.FilterRule{
|
||||||
|
@ -49,10 +49,10 @@ func Test_MachineCanAccess(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "other-cant-access-src",
|
name: "other-cant-access-src",
|
||||||
machine1: Machine{
|
node1: Node{
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")},
|
||||||
},
|
},
|
||||||
machine2: Machine{
|
node2: Node{
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
|
||||||
},
|
},
|
||||||
rules: []tailcfg.FilterRule{
|
rules: []tailcfg.FilterRule{
|
||||||
|
@ -67,10 +67,10 @@ func Test_MachineCanAccess(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "dest-cant-access-src",
|
name: "dest-cant-access-src",
|
||||||
machine1: Machine{
|
node1: Node{
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
|
||||||
},
|
},
|
||||||
machine2: Machine{
|
node2: Node{
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")},
|
||||||
},
|
},
|
||||||
rules: []tailcfg.FilterRule{
|
rules: []tailcfg.FilterRule{
|
||||||
|
@ -85,10 +85,10 @@ func Test_MachineCanAccess(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "src-can-access-dest",
|
name: "src-can-access-dest",
|
||||||
machine1: Machine{
|
node1: Node{
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")},
|
||||||
},
|
},
|
||||||
machine2: Machine{
|
node2: Node{
|
||||||
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
|
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
|
||||||
},
|
},
|
||||||
rules: []tailcfg.FilterRule{
|
rules: []tailcfg.FilterRule{
|
||||||
|
@ -105,7 +105,7 @@ func Test_MachineCanAccess(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := tt.machine1.CanAccess(tt.rules, &tt.machine2)
|
got := tt.node1.CanAccess(tt.rules, &tt.node2)
|
||||||
|
|
||||||
if got != tt.want {
|
if got != tt.want {
|
||||||
t.Errorf("canAccess() failed: want (%t), got (%t)", tt.want, got)
|
t.Errorf("canAccess() failed: want (%t), got (%t)", tt.want, got)
|
||||||
|
@ -114,8 +114,8 @@ func Test_MachineCanAccess(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMachineAddressesOrder(t *testing.T) {
|
func TestNodeAddressesOrder(t *testing.T) {
|
||||||
machineAddresses := MachineAddresses{
|
machineAddresses := NodeAddresses{
|
||||||
netip.MustParseAddr("2001:db8::2"),
|
netip.MustParseAddr("2001:db8::2"),
|
||||||
netip.MustParseAddr("100.64.0.2"),
|
netip.MustParseAddr("100.64.0.2"),
|
||||||
netip.MustParseAddr("2001:db8::1"),
|
netip.MustParseAddr("2001:db8::1"),
|
|
@ -17,8 +17,8 @@ var (
|
||||||
type Route struct {
|
type Route struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
|
|
||||||
MachineID uint64
|
NodeID uint64
|
||||||
Machine Machine
|
Node Node
|
||||||
Prefix IPPrefix
|
Prefix IPPrefix
|
||||||
|
|
||||||
Advertised bool
|
Advertised bool
|
||||||
|
@ -29,7 +29,7 @@ type Route struct {
|
||||||
type Routes []Route
|
type Routes []Route
|
||||||
|
|
||||||
func (r *Route) String() string {
|
func (r *Route) String() string {
|
||||||
return fmt.Sprintf("%s:%s", r.Machine, netip.Prefix(r.Prefix).String())
|
return fmt.Sprintf("%s:%s", r.Node, netip.Prefix(r.Prefix).String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Route) IsExitRoute() bool {
|
func (r *Route) IsExitRoute() bool {
|
||||||
|
@ -51,7 +51,7 @@ func (rs Routes) Proto() []*v1.Route {
|
||||||
for _, route := range rs {
|
for _, route := range rs {
|
||||||
protoRoute := v1.Route{
|
protoRoute := v1.Route{
|
||||||
Id: uint64(route.ID),
|
Id: uint64(route.ID),
|
||||||
Machine: route.Machine.Proto(),
|
Node: route.Node.Proto(),
|
||||||
Prefix: netip.Prefix(route.Prefix).String(),
|
Prefix: netip.Prefix(route.Prefix).String(),
|
||||||
Advertised: route.Advertised,
|
Advertised: route.Advertised,
|
||||||
Enabled: route.Enabled,
|
Enabled: route.Enabled,
|
||||||
|
|
|
@ -686,7 +686,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
||||||
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
|
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
|
||||||
}
|
}
|
||||||
machines := make([]*v1.Machine, len(machineKeys))
|
nodes := make([]*v1.Node, len(machineKeys))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
for index, machineKey := range machineKeys {
|
for index, machineKey := range machineKeys {
|
||||||
|
@ -696,7 +696,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
"debug",
|
"debug",
|
||||||
"create-node",
|
"create-node",
|
||||||
"--name",
|
"--name",
|
||||||
fmt.Sprintf("machine-%d", index+1),
|
fmt.Sprintf("node-%d", index+1),
|
||||||
"--user",
|
"--user",
|
||||||
"user1",
|
"user1",
|
||||||
"--key",
|
"--key",
|
||||||
|
@ -707,7 +707,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
var machine v1.Machine
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -721,15 +721,15 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
machines[index] = &machine
|
nodes[index] = &node
|
||||||
}
|
}
|
||||||
assert.Len(t, machines, len(machineKeys))
|
assert.Len(t, nodes, len(machineKeys))
|
||||||
|
|
||||||
var machine v1.Machine
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -740,11 +740,11 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
"-t", "tag:test",
|
"-t", "tag:test",
|
||||||
"--output", "json",
|
"--output", "json",
|
||||||
},
|
},
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, []string{"tag:test"}, machine.ForcedTags)
|
assert.Equal(t, []string{"tag:test"}, node.ForcedTags)
|
||||||
|
|
||||||
// try to set a wrong tag and retrieve the error
|
// try to set a wrong tag and retrieve the error
|
||||||
type errOutput struct {
|
type errOutput struct {
|
||||||
|
@ -767,7 +767,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
assert.Contains(t, errorOutput.Error, "tag must start with the string 'tag:'")
|
assert.Contains(t, errorOutput.Error, "tag must start with the string 'tag:'")
|
||||||
|
|
||||||
// Test list all nodes after added seconds
|
// Test list all nodes after added seconds
|
||||||
resultMachines := make([]*v1.Machine, len(machineKeys))
|
resultMachines := make([]*v1.Node, len(machineKeys))
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -780,9 +780,9 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
found := false
|
found := false
|
||||||
for _, machine := range resultMachines {
|
for _, node := range resultMachines {
|
||||||
if machine.ForcedTags != nil {
|
if node.ForcedTags != nil {
|
||||||
for _, tag := range machine.ForcedTags {
|
for _, tag := range node.ForcedTags {
|
||||||
if tag == "tag:test" {
|
if tag == "tag:test" {
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
|
@ -793,7 +793,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
t,
|
t,
|
||||||
true,
|
true,
|
||||||
found,
|
found,
|
||||||
"should find a machine with the tag 'tag:test' in the list of machines",
|
"should find a node with the tag 'tag:test' in the list of nodes",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -806,7 +806,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
defer scenario.Shutdown()
|
defer scenario.Shutdown()
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
"machine-user": 0,
|
"node-user": 0,
|
||||||
"other-user": 0,
|
"other-user": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,7 +816,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
assertNoErr(t, err)
|
||||||
|
|
||||||
// Randomly generated machine keys
|
// Randomly generated node keys
|
||||||
machineKeys := []string{
|
machineKeys := []string{
|
||||||
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
||||||
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
|
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
|
||||||
|
@ -824,7 +824,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1",
|
"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1",
|
||||||
"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
|
"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
|
||||||
}
|
}
|
||||||
machines := make([]*v1.Machine, len(machineKeys))
|
nodes := make([]*v1.Node, len(machineKeys))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
for index, machineKey := range machineKeys {
|
for index, machineKey := range machineKeys {
|
||||||
|
@ -834,9 +834,9 @@ func TestNodeCommand(t *testing.T) {
|
||||||
"debug",
|
"debug",
|
||||||
"create-node",
|
"create-node",
|
||||||
"--name",
|
"--name",
|
||||||
fmt.Sprintf("machine-%d", index+1),
|
fmt.Sprintf("node-%d", index+1),
|
||||||
"--user",
|
"--user",
|
||||||
"machine-user",
|
"node-user",
|
||||||
"--key",
|
"--key",
|
||||||
machineKey,
|
machineKey,
|
||||||
"--output",
|
"--output",
|
||||||
|
@ -845,31 +845,31 @@ func TestNodeCommand(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
var machine v1.Machine
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
"headscale",
|
"headscale",
|
||||||
"nodes",
|
"nodes",
|
||||||
"--user",
|
"--user",
|
||||||
"machine-user",
|
"node-user",
|
||||||
"register",
|
"register",
|
||||||
"--key",
|
"--key",
|
||||||
machineKey,
|
machineKey,
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
machines[index] = &machine
|
nodes[index] = &node
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Len(t, machines, len(machineKeys))
|
assert.Len(t, nodes, len(machineKeys))
|
||||||
|
|
||||||
// Test list all nodes after added seconds
|
// Test list all nodes after added seconds
|
||||||
var listAll []v1.Machine
|
var listAll []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -891,17 +891,17 @@ func TestNodeCommand(t *testing.T) {
|
||||||
assert.Equal(t, uint64(4), listAll[3].Id)
|
assert.Equal(t, uint64(4), listAll[3].Id)
|
||||||
assert.Equal(t, uint64(5), listAll[4].Id)
|
assert.Equal(t, uint64(5), listAll[4].Id)
|
||||||
|
|
||||||
assert.Equal(t, "machine-1", listAll[0].Name)
|
assert.Equal(t, "node-1", listAll[0].Name)
|
||||||
assert.Equal(t, "machine-2", listAll[1].Name)
|
assert.Equal(t, "node-2", listAll[1].Name)
|
||||||
assert.Equal(t, "machine-3", listAll[2].Name)
|
assert.Equal(t, "node-3", listAll[2].Name)
|
||||||
assert.Equal(t, "machine-4", listAll[3].Name)
|
assert.Equal(t, "node-4", listAll[3].Name)
|
||||||
assert.Equal(t, "machine-5", listAll[4].Name)
|
assert.Equal(t, "node-5", listAll[4].Name)
|
||||||
|
|
||||||
otherUserMachineKeys := []string{
|
otherUserMachineKeys := []string{
|
||||||
"nodekey:b5b444774186d4217adcec407563a1223929465ee2c68a4da13af0d0185b4f8e",
|
"nodekey:b5b444774186d4217adcec407563a1223929465ee2c68a4da13af0d0185b4f8e",
|
||||||
"nodekey:dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584",
|
"nodekey:dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584",
|
||||||
}
|
}
|
||||||
otherUserMachines := make([]*v1.Machine, len(otherUserMachineKeys))
|
otherUserMachines := make([]*v1.Node, len(otherUserMachineKeys))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
for index, machineKey := range otherUserMachineKeys {
|
for index, machineKey := range otherUserMachineKeys {
|
||||||
|
@ -911,7 +911,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
"debug",
|
"debug",
|
||||||
"create-node",
|
"create-node",
|
||||||
"--name",
|
"--name",
|
||||||
fmt.Sprintf("otherUser-machine-%d", index+1),
|
fmt.Sprintf("otherUser-node-%d", index+1),
|
||||||
"--user",
|
"--user",
|
||||||
"other-user",
|
"other-user",
|
||||||
"--key",
|
"--key",
|
||||||
|
@ -922,7 +922,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
var machine v1.Machine
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -936,17 +936,17 @@ func TestNodeCommand(t *testing.T) {
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
otherUserMachines[index] = &machine
|
otherUserMachines[index] = &node
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Len(t, otherUserMachines, len(otherUserMachineKeys))
|
assert.Len(t, otherUserMachines, len(otherUserMachineKeys))
|
||||||
|
|
||||||
// Test list all nodes after added otherUser
|
// Test list all nodes after added otherUser
|
||||||
var listAllWithotherUser []v1.Machine
|
var listAllWithotherUser []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -960,17 +960,17 @@ func TestNodeCommand(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// All nodes, machines + otherUser
|
// All nodes, nodes + otherUser
|
||||||
assert.Len(t, listAllWithotherUser, 7)
|
assert.Len(t, listAllWithotherUser, 7)
|
||||||
|
|
||||||
assert.Equal(t, uint64(6), listAllWithotherUser[5].Id)
|
assert.Equal(t, uint64(6), listAllWithotherUser[5].Id)
|
||||||
assert.Equal(t, uint64(7), listAllWithotherUser[6].Id)
|
assert.Equal(t, uint64(7), listAllWithotherUser[6].Id)
|
||||||
|
|
||||||
assert.Equal(t, "otherUser-machine-1", listAllWithotherUser[5].Name)
|
assert.Equal(t, "otherUser-node-1", listAllWithotherUser[5].Name)
|
||||||
assert.Equal(t, "otherUser-machine-2", listAllWithotherUser[6].Name)
|
assert.Equal(t, "otherUser-node-2", listAllWithotherUser[6].Name)
|
||||||
|
|
||||||
// Test list all nodes after added otherUser
|
// Test list all nodes after added otherUser
|
||||||
var listOnlyotherUserMachineUser []v1.Machine
|
var listOnlyotherUserMachineUser []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -993,16 +993,16 @@ func TestNodeCommand(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(
|
assert.Equal(
|
||||||
t,
|
t,
|
||||||
"otherUser-machine-1",
|
"otherUser-node-1",
|
||||||
listOnlyotherUserMachineUser[0].Name,
|
listOnlyotherUserMachineUser[0].Name,
|
||||||
)
|
)
|
||||||
assert.Equal(
|
assert.Equal(
|
||||||
t,
|
t,
|
||||||
"otherUser-machine-2",
|
"otherUser-node-2",
|
||||||
listOnlyotherUserMachineUser[1].Name,
|
listOnlyotherUserMachineUser[1].Name,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Delete a machines
|
// Delete a nodes
|
||||||
_, err = headscale.Execute(
|
_, err = headscale.Execute(
|
||||||
[]string{
|
[]string{
|
||||||
"headscale",
|
"headscale",
|
||||||
|
@ -1018,8 +1018,8 @@ func TestNodeCommand(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// Test: list main user after machine is deleted
|
// Test: list main user after node is deleted
|
||||||
var listOnlyMachineUserAfterDelete []v1.Machine
|
var listOnlyMachineUserAfterDelete []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -1027,7 +1027,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
"nodes",
|
"nodes",
|
||||||
"list",
|
"list",
|
||||||
"--user",
|
"--user",
|
||||||
"machine-user",
|
"node-user",
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
|
@ -1047,7 +1047,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
defer scenario.Shutdown()
|
defer scenario.Shutdown()
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
"machine-expire-user": 0,
|
"node-expire-user": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
||||||
|
@ -1056,7 +1056,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
assertNoErr(t, err)
|
||||||
|
|
||||||
// Randomly generated machine keys
|
// Randomly generated node keys
|
||||||
machineKeys := []string{
|
machineKeys := []string{
|
||||||
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
||||||
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
|
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
|
||||||
|
@ -1064,7 +1064,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1",
|
"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1",
|
||||||
"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
|
"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
|
||||||
}
|
}
|
||||||
machines := make([]*v1.Machine, len(machineKeys))
|
nodes := make([]*v1.Node, len(machineKeys))
|
||||||
|
|
||||||
for index, machineKey := range machineKeys {
|
for index, machineKey := range machineKeys {
|
||||||
_, err := headscale.Execute(
|
_, err := headscale.Execute(
|
||||||
|
@ -1073,9 +1073,9 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
"debug",
|
"debug",
|
||||||
"create-node",
|
"create-node",
|
||||||
"--name",
|
"--name",
|
||||||
fmt.Sprintf("machine-%d", index+1),
|
fmt.Sprintf("node-%d", index+1),
|
||||||
"--user",
|
"--user",
|
||||||
"machine-expire-user",
|
"node-expire-user",
|
||||||
"--key",
|
"--key",
|
||||||
machineKey,
|
machineKey,
|
||||||
"--output",
|
"--output",
|
||||||
|
@ -1084,30 +1084,30 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
var machine v1.Machine
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
"headscale",
|
"headscale",
|
||||||
"nodes",
|
"nodes",
|
||||||
"--user",
|
"--user",
|
||||||
"machine-expire-user",
|
"node-expire-user",
|
||||||
"register",
|
"register",
|
||||||
"--key",
|
"--key",
|
||||||
machineKey,
|
machineKey,
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
machines[index] = &machine
|
nodes[index] = &node
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Len(t, machines, len(machineKeys))
|
assert.Len(t, nodes, len(machineKeys))
|
||||||
|
|
||||||
var listAll []v1.Machine
|
var listAll []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -1142,7 +1142,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var listAllAfterExpiry []v1.Machine
|
var listAllAfterExpiry []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -1174,7 +1174,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
defer scenario.Shutdown()
|
defer scenario.Shutdown()
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
"machine-rename-command": 0,
|
"node-rename-command": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
||||||
|
@ -1183,7 +1183,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
assertNoErr(t, err)
|
||||||
|
|
||||||
// Randomly generated machine keys
|
// Randomly generated node keys
|
||||||
machineKeys := []string{
|
machineKeys := []string{
|
||||||
"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
|
"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
|
||||||
"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1",
|
"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1",
|
||||||
|
@ -1191,7 +1191,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
|
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
|
||||||
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
||||||
}
|
}
|
||||||
machines := make([]*v1.Machine, len(machineKeys))
|
nodes := make([]*v1.Node, len(machineKeys))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
for index, machineKey := range machineKeys {
|
for index, machineKey := range machineKeys {
|
||||||
|
@ -1201,9 +1201,9 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
"debug",
|
"debug",
|
||||||
"create-node",
|
"create-node",
|
||||||
"--name",
|
"--name",
|
||||||
fmt.Sprintf("machine-%d", index+1),
|
fmt.Sprintf("node-%d", index+1),
|
||||||
"--user",
|
"--user",
|
||||||
"machine-rename-command",
|
"node-rename-command",
|
||||||
"--key",
|
"--key",
|
||||||
machineKey,
|
machineKey,
|
||||||
"--output",
|
"--output",
|
||||||
|
@ -1212,30 +1212,30 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
var machine v1.Machine
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
"headscale",
|
"headscale",
|
||||||
"nodes",
|
"nodes",
|
||||||
"--user",
|
"--user",
|
||||||
"machine-rename-command",
|
"node-rename-command",
|
||||||
"register",
|
"register",
|
||||||
"--key",
|
"--key",
|
||||||
machineKey,
|
machineKey,
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
machines[index] = &machine
|
nodes[index] = &node
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Len(t, machines, len(machineKeys))
|
assert.Len(t, nodes, len(machineKeys))
|
||||||
|
|
||||||
var listAll []v1.Machine
|
var listAll []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -1251,11 +1251,11 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
|
|
||||||
assert.Len(t, listAll, 5)
|
assert.Len(t, listAll, 5)
|
||||||
|
|
||||||
assert.Contains(t, listAll[0].GetGivenName(), "machine-1")
|
assert.Contains(t, listAll[0].GetGivenName(), "node-1")
|
||||||
assert.Contains(t, listAll[1].GetGivenName(), "machine-2")
|
assert.Contains(t, listAll[1].GetGivenName(), "node-2")
|
||||||
assert.Contains(t, listAll[2].GetGivenName(), "machine-3")
|
assert.Contains(t, listAll[2].GetGivenName(), "node-3")
|
||||||
assert.Contains(t, listAll[3].GetGivenName(), "machine-4")
|
assert.Contains(t, listAll[3].GetGivenName(), "node-4")
|
||||||
assert.Contains(t, listAll[4].GetGivenName(), "machine-5")
|
assert.Contains(t, listAll[4].GetGivenName(), "node-5")
|
||||||
|
|
||||||
for idx := 0; idx < 3; idx++ {
|
for idx := 0; idx < 3; idx++ {
|
||||||
_, err := headscale.Execute(
|
_, err := headscale.Execute(
|
||||||
|
@ -1265,13 +1265,13 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
"rename",
|
"rename",
|
||||||
"--identifier",
|
"--identifier",
|
||||||
fmt.Sprintf("%d", listAll[idx].Id),
|
fmt.Sprintf("%d", listAll[idx].Id),
|
||||||
fmt.Sprintf("newmachine-%d", idx+1),
|
fmt.Sprintf("newnode-%d", idx+1),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var listAllAfterRename []v1.Machine
|
var listAllAfterRename []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -1287,11 +1287,11 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
|
|
||||||
assert.Len(t, listAllAfterRename, 5)
|
assert.Len(t, listAllAfterRename, 5)
|
||||||
|
|
||||||
assert.Equal(t, "newmachine-1", listAllAfterRename[0].GetGivenName())
|
assert.Equal(t, "newnode-1", listAllAfterRename[0].GetGivenName())
|
||||||
assert.Equal(t, "newmachine-2", listAllAfterRename[1].GetGivenName())
|
assert.Equal(t, "newnode-2", listAllAfterRename[1].GetGivenName())
|
||||||
assert.Equal(t, "newmachine-3", listAllAfterRename[2].GetGivenName())
|
assert.Equal(t, "newnode-3", listAllAfterRename[2].GetGivenName())
|
||||||
assert.Contains(t, listAllAfterRename[3].GetGivenName(), "machine-4")
|
assert.Contains(t, listAllAfterRename[3].GetGivenName(), "node-4")
|
||||||
assert.Contains(t, listAllAfterRename[4].GetGivenName(), "machine-5")
|
assert.Contains(t, listAllAfterRename[4].GetGivenName(), "node-5")
|
||||||
|
|
||||||
// Test failure for too long names
|
// Test failure for too long names
|
||||||
result, err := headscale.Execute(
|
result, err := headscale.Execute(
|
||||||
|
@ -1307,7 +1307,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Contains(t, result, "not be over 63 chars")
|
assert.Contains(t, result, "not be over 63 chars")
|
||||||
|
|
||||||
var listAllAfterRenameAttempt []v1.Machine
|
var listAllAfterRenameAttempt []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -1323,11 +1323,11 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
|
|
||||||
assert.Len(t, listAllAfterRenameAttempt, 5)
|
assert.Len(t, listAllAfterRenameAttempt, 5)
|
||||||
|
|
||||||
assert.Equal(t, "newmachine-1", listAllAfterRenameAttempt[0].GetGivenName())
|
assert.Equal(t, "newnode-1", listAllAfterRenameAttempt[0].GetGivenName())
|
||||||
assert.Equal(t, "newmachine-2", listAllAfterRenameAttempt[1].GetGivenName())
|
assert.Equal(t, "newnode-2", listAllAfterRenameAttempt[1].GetGivenName())
|
||||||
assert.Equal(t, "newmachine-3", listAllAfterRenameAttempt[2].GetGivenName())
|
assert.Equal(t, "newnode-3", listAllAfterRenameAttempt[2].GetGivenName())
|
||||||
assert.Contains(t, listAllAfterRenameAttempt[3].GetGivenName(), "machine-4")
|
assert.Contains(t, listAllAfterRenameAttempt[3].GetGivenName(), "node-4")
|
||||||
assert.Contains(t, listAllAfterRenameAttempt[4].GetGivenName(), "machine-5")
|
assert.Contains(t, listAllAfterRenameAttempt[4].GetGivenName(), "node-5")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeMoveCommand(t *testing.T) {
|
func TestNodeMoveCommand(t *testing.T) {
|
||||||
|
@ -1349,7 +1349,7 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
assertNoErr(t, err)
|
||||||
|
|
||||||
// Randomly generated machine key
|
// Randomly generated node key
|
||||||
machineKey := "nodekey:688411b767663479632d44140f08a9fde87383adc7cdeb518f62ce28a17ef0aa"
|
machineKey := "nodekey:688411b767663479632d44140f08a9fde87383adc7cdeb518f62ce28a17ef0aa"
|
||||||
|
|
||||||
_, err = headscale.Execute(
|
_, err = headscale.Execute(
|
||||||
|
@ -1358,7 +1358,7 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
"debug",
|
"debug",
|
||||||
"create-node",
|
"create-node",
|
||||||
"--name",
|
"--name",
|
||||||
"nomad-machine",
|
"nomad-node",
|
||||||
"--user",
|
"--user",
|
||||||
"old-user",
|
"old-user",
|
||||||
"--key",
|
"--key",
|
||||||
|
@ -1369,7 +1369,7 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
var machine v1.Machine
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -1383,15 +1383,15 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, uint64(1), machine.Id)
|
assert.Equal(t, uint64(1), node.Id)
|
||||||
assert.Equal(t, "nomad-machine", machine.Name)
|
assert.Equal(t, "nomad-node", node.Name)
|
||||||
assert.Equal(t, machine.User.Name, "old-user")
|
assert.Equal(t, node.User.Name, "old-user")
|
||||||
|
|
||||||
machineID := fmt.Sprintf("%d", machine.Id)
|
nodeID := fmt.Sprintf("%d", node.Id)
|
||||||
|
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
|
@ -1400,19 +1400,19 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
"nodes",
|
"nodes",
|
||||||
"move",
|
"move",
|
||||||
"--identifier",
|
"--identifier",
|
||||||
machineID,
|
nodeID,
|
||||||
"--user",
|
"--user",
|
||||||
"new-user",
|
"new-user",
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, machine.User.Name, "new-user")
|
assert.Equal(t, node.User.Name, "new-user")
|
||||||
|
|
||||||
var allNodes []v1.Machine
|
var allNodes []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -1428,8 +1428,8 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
|
|
||||||
assert.Len(t, allNodes, 1)
|
assert.Len(t, allNodes, 1)
|
||||||
|
|
||||||
assert.Equal(t, allNodes[0].Id, machine.Id)
|
assert.Equal(t, allNodes[0].Id, node.Id)
|
||||||
assert.Equal(t, allNodes[0].User, machine.User)
|
assert.Equal(t, allNodes[0].User, node.User)
|
||||||
assert.Equal(t, allNodes[0].User.Name, "new-user")
|
assert.Equal(t, allNodes[0].User.Name, "new-user")
|
||||||
|
|
||||||
moveToNonExistingNSResult, err := headscale.Execute(
|
moveToNonExistingNSResult, err := headscale.Execute(
|
||||||
|
@ -1438,7 +1438,7 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
"nodes",
|
"nodes",
|
||||||
"move",
|
"move",
|
||||||
"--identifier",
|
"--identifier",
|
||||||
machineID,
|
nodeID,
|
||||||
"--user",
|
"--user",
|
||||||
"non-existing-user",
|
"non-existing-user",
|
||||||
"--output",
|
"--output",
|
||||||
|
@ -1452,7 +1452,7 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
moveToNonExistingNSResult,
|
moveToNonExistingNSResult,
|
||||||
"user not found",
|
"user not found",
|
||||||
)
|
)
|
||||||
assert.Equal(t, machine.User.Name, "new-user")
|
assert.Equal(t, node.User.Name, "new-user")
|
||||||
|
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
|
@ -1461,17 +1461,17 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
"nodes",
|
"nodes",
|
||||||
"move",
|
"move",
|
||||||
"--identifier",
|
"--identifier",
|
||||||
machineID,
|
nodeID,
|
||||||
"--user",
|
"--user",
|
||||||
"old-user",
|
"old-user",
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, machine.User.Name, "old-user")
|
assert.Equal(t, node.User.Name, "old-user")
|
||||||
|
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
|
@ -1480,15 +1480,15 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
"nodes",
|
"nodes",
|
||||||
"move",
|
"move",
|
||||||
"--identifier",
|
"--identifier",
|
||||||
machineID,
|
nodeID,
|
||||||
"--user",
|
"--user",
|
||||||
"old-user",
|
"old-user",
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
&machine,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, machine.User.Name, "old-user")
|
assert.Equal(t, node.User.Name, "old-user")
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ type ControlServer interface {
|
||||||
WaitForRunning() error
|
WaitForRunning() error
|
||||||
CreateUser(user string) error
|
CreateUser(user string) error
|
||||||
CreateAuthKey(user string, reusable bool, ephemeral bool) (*v1.PreAuthKey, error)
|
CreateAuthKey(user string, reusable bool, ephemeral bool) (*v1.PreAuthKey, error)
|
||||||
ListMachinesInUser(user string) ([]*v1.Machine, error)
|
ListNodesInUser(user string) ([]*v1.Node, error)
|
||||||
GetCert() []byte
|
GetCert() []byte
|
||||||
GetHostname() string
|
GetHostname() string
|
||||||
GetIP() string
|
GetIP() string
|
||||||
|
|
|
@ -223,18 +223,18 @@ func TestEphemeral(t *testing.T) {
|
||||||
t.Logf("all clients logged out")
|
t.Logf("all clients logged out")
|
||||||
|
|
||||||
for userName := range spec {
|
for userName := range spec {
|
||||||
machines, err := headscale.ListMachinesInUser(userName)
|
nodes, err := headscale.ListNodesInUser(userName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
Str("user", userName).
|
Str("user", userName).
|
||||||
Msg("Error listing machines in user")
|
Msg("Error listing nodes in user")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(machines) != 0 {
|
if len(nodes) != 0 {
|
||||||
t.Fatalf("expected no machines, got %d in user %s", len(machines), userName)
|
t.Fatalf("expected no nodes, got %d in user %s", len(nodes), userName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -513,8 +513,8 @@ func TestExpireNode(t *testing.T) {
|
||||||
})
|
})
|
||||||
assertNoErr(t, err)
|
assertNoErr(t, err)
|
||||||
|
|
||||||
var machine v1.Machine
|
var node v1.Node
|
||||||
err = json.Unmarshal([]byte(result), &machine)
|
err = json.Unmarshal([]byte(result), &node)
|
||||||
assertNoErr(t, err)
|
assertNoErr(t, err)
|
||||||
|
|
||||||
time.Sleep(30 * time.Second)
|
time.Sleep(30 * time.Second)
|
||||||
|
@ -530,10 +530,10 @@ func TestExpireNode(t *testing.T) {
|
||||||
|
|
||||||
peerPublicKey := strings.TrimPrefix(peerStatus.PublicKey.String(), "nodekey:")
|
peerPublicKey := strings.TrimPrefix(peerStatus.PublicKey.String(), "nodekey:")
|
||||||
|
|
||||||
assert.NotEqual(t, machine.NodeKey, peerPublicKey)
|
assert.NotEqual(t, node.NodeKey, peerPublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.Hostname() != machine.Name {
|
if client.Hostname() != node.Name {
|
||||||
// Assert that we have the original count - self - expired node
|
// Assert that we have the original count - self - expired node
|
||||||
assert.Len(t, status.Peers(), len(MustTestVersions)-2)
|
assert.Len(t, status.Peers(), len(MustTestVersions)-2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -547,11 +547,11 @@ func (t *HeadscaleInContainer) CreateAuthKey(
|
||||||
return &preAuthKey, nil
|
return &preAuthKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListMachinesInUser list the TailscaleClients (Machine, Headscale internal representation)
|
// ListNodesInUser list the TailscaleClients (Node, Headscale internal representation)
|
||||||
// associated with a user.
|
// associated with a user.
|
||||||
func (t *HeadscaleInContainer) ListMachinesInUser(
|
func (t *HeadscaleInContainer) ListNodesInUser(
|
||||||
user string,
|
user string,
|
||||||
) ([]*v1.Machine, error) {
|
) ([]*v1.Node, error) {
|
||||||
command := []string{"headscale", "--user", user, "nodes", "list", "--output", "json"}
|
command := []string{"headscale", "--user", user, "nodes", "list", "--output", "json"}
|
||||||
|
|
||||||
result, _, err := dockertestutil.ExecuteCommand(
|
result, _, err := dockertestutil.ExecuteCommand(
|
||||||
|
@ -563,7 +563,7 @@ func (t *HeadscaleInContainer) ListMachinesInUser(
|
||||||
return nil, fmt.Errorf("failed to execute list node command: %w", err)
|
return nil, fmt.Errorf("failed to execute list node command: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var nodes []*v1.Machine
|
var nodes []*v1.Node
|
||||||
err = json.Unmarshal([]byte(result), &nodes)
|
err = json.Unmarshal([]byte(result), &nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to unmarshal nodes: %w", err)
|
return nil, fmt.Errorf("failed to unmarshal nodes: %w", err)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import "google/api/annotations.proto";
|
||||||
|
|
||||||
import "headscale/v1/user.proto";
|
import "headscale/v1/user.proto";
|
||||||
import "headscale/v1/preauthkey.proto";
|
import "headscale/v1/preauthkey.proto";
|
||||||
import "headscale/v1/machine.proto";
|
import "headscale/v1/node.proto";
|
||||||
import "headscale/v1/routes.proto";
|
import "headscale/v1/routes.proto";
|
||||||
import "headscale/v1/apikey.proto";
|
import "headscale/v1/apikey.proto";
|
||||||
// import "headscale/v1/device.proto";
|
// import "headscale/v1/device.proto";
|
||||||
|
@ -67,63 +67,63 @@ service HeadscaleService {
|
||||||
}
|
}
|
||||||
// --- PreAuthKeys end ---
|
// --- PreAuthKeys end ---
|
||||||
|
|
||||||
// --- Machine start ---
|
// --- Node start ---
|
||||||
rpc DebugCreateMachine(DebugCreateMachineRequest) returns(DebugCreateMachineResponse) {
|
rpc DebugCreateNode(DebugCreateNodeRequest) returns(DebugCreateNodeResponse) {
|
||||||
option(google.api.http) = {
|
option(google.api.http) = {
|
||||||
post : "/api/v1/debug/machine"
|
post : "/api/v1/debug/node"
|
||||||
body : "*"
|
body : "*"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetMachine(GetMachineRequest) returns(GetMachineResponse) {
|
rpc GetNode(GetNodeRequest) returns(GetNodeResponse) {
|
||||||
option(google.api.http) = {
|
option(google.api.http) = {
|
||||||
get : "/api/v1/machine/{machine_id}"
|
get : "/api/v1/node/{node_id}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc SetTags(SetTagsRequest) returns(SetTagsResponse) {
|
rpc SetTags(SetTagsRequest) returns(SetTagsResponse) {
|
||||||
option(google.api.http) = {
|
option(google.api.http) = {
|
||||||
post : "/api/v1/machine/{machine_id}/tags"
|
post : "/api/v1/node/{node_id}/tags"
|
||||||
body : "*"
|
body : "*"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc RegisterMachine(RegisterMachineRequest) returns(RegisterMachineResponse) {
|
rpc RegisterNode(RegisterNodeRequest) returns(RegisterNodeResponse) {
|
||||||
option(google.api.http) = {
|
option(google.api.http) = {
|
||||||
post : "/api/v1/machine/register"
|
post : "/api/v1/node/register"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc DeleteMachine(DeleteMachineRequest) returns(DeleteMachineResponse) {
|
rpc DeleteNode(DeleteNodeRequest) returns(DeleteNodeResponse) {
|
||||||
option(google.api.http) = {
|
option(google.api.http) = {
|
||||||
delete : "/api/v1/machine/{machine_id}"
|
delete : "/api/v1/node/{node_id}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc ExpireMachine(ExpireMachineRequest) returns(ExpireMachineResponse) {
|
rpc ExpireNode(ExpireNodeRequest) returns(ExpireNodeResponse) {
|
||||||
option(google.api.http) = {
|
option(google.api.http) = {
|
||||||
post : "/api/v1/machine/{machine_id}/expire"
|
post : "/api/v1/node/{node_id}/expire"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc RenameMachine(RenameMachineRequest) returns(RenameMachineResponse) {
|
rpc RenameNode(RenameNodeRequest) returns(RenameNodeResponse) {
|
||||||
option(google.api.http) = {
|
option(google.api.http) = {
|
||||||
post : "/api/v1/machine/{machine_id}/rename/{new_name}"
|
post : "/api/v1/node/{node_id}/rename/{new_name}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc ListMachines(ListMachinesRequest) returns(ListMachinesResponse) {
|
rpc ListNodes(ListNodesRequest) returns(ListNodesResponse) {
|
||||||
option(google.api.http) = {
|
option(google.api.http) = {
|
||||||
get : "/api/v1/machine"
|
get : "/api/v1/node"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc MoveMachine(MoveMachineRequest) returns(MoveMachineResponse) {
|
rpc MoveNode(MoveNodeRequest) returns(MoveNodeResponse) {
|
||||||
option(google.api.http) = {
|
option(google.api.http) = {
|
||||||
post : "/api/v1/machine/{machine_id}/user"
|
post : "/api/v1/node/{node_id}/user"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// --- Machine end ---
|
// --- Node end ---
|
||||||
|
|
||||||
// --- Route start ---
|
// --- Route start ---
|
||||||
rpc GetRoutes(GetRoutesRequest) returns(GetRoutesResponse) {
|
rpc GetRoutes(GetRoutesRequest) returns(GetRoutesResponse) {
|
||||||
|
@ -144,9 +144,9 @@ service HeadscaleService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetMachineRoutes(GetMachineRoutesRequest) returns(GetMachineRoutesResponse) {
|
rpc GetNodeRoutes(GetNodeRoutesRequest) returns(GetNodeRoutesResponse) {
|
||||||
option(google.api.http) = {
|
option(google.api.http) = {
|
||||||
get : "/api/v1/machine/{machine_id}/routes"
|
get : "/api/v1/node/{node_id}/routes"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ enum RegisterMethod {
|
||||||
REGISTER_METHOD_OIDC = 3;
|
REGISTER_METHOD_OIDC = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Machine {
|
message Node {
|
||||||
uint64 id = 1;
|
uint64 id = 1;
|
||||||
string machine_key = 2;
|
string machine_key = 2;
|
||||||
string node_key = 3;
|
string node_key = 3;
|
||||||
|
@ -47,80 +47,80 @@ message Machine {
|
||||||
bool online = 22;
|
bool online = 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RegisterMachineRequest {
|
message RegisterNodeRequest {
|
||||||
string user = 1;
|
string user = 1;
|
||||||
string key = 2;
|
string key = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RegisterMachineResponse {
|
message RegisterNodeResponse {
|
||||||
Machine machine = 1;
|
Node node = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetMachineRequest {
|
message GetNodeRequest {
|
||||||
uint64 machine_id = 1;
|
uint64 node_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetMachineResponse {
|
message GetNodeResponse {
|
||||||
Machine machine = 1;
|
Node node = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetTagsRequest {
|
message SetTagsRequest {
|
||||||
uint64 machine_id = 1;
|
uint64 node_id = 1;
|
||||||
repeated string tags = 2;
|
repeated string tags = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetTagsResponse {
|
message SetTagsResponse {
|
||||||
Machine machine = 1;
|
Node node = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeleteMachineRequest {
|
message DeleteNodeRequest {
|
||||||
uint64 machine_id = 1;
|
uint64 node_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeleteMachineResponse {
|
message DeleteNodeResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
message ExpireMachineRequest {
|
message ExpireNodeRequest {
|
||||||
uint64 machine_id = 1;
|
uint64 node_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ExpireMachineResponse {
|
message ExpireNodeResponse {
|
||||||
Machine machine = 1;
|
Node node = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RenameMachineRequest {
|
message RenameNodeRequest {
|
||||||
uint64 machine_id = 1;
|
uint64 node_id = 1;
|
||||||
string new_name = 2;
|
string new_name = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RenameMachineResponse {
|
message RenameNodeResponse {
|
||||||
Machine machine = 1;
|
Node node = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListMachinesRequest {
|
message ListNodesRequest {
|
||||||
string user = 1;
|
string user = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListMachinesResponse {
|
message ListNodesResponse {
|
||||||
repeated Machine machines = 1;
|
repeated Node nodes = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message MoveMachineRequest {
|
message MoveNodeRequest {
|
||||||
uint64 machine_id = 1;
|
uint64 node_id = 1;
|
||||||
string user = 2;
|
string user = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message MoveMachineResponse {
|
message MoveNodeResponse {
|
||||||
Machine machine = 1;
|
Node node = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DebugCreateMachineRequest {
|
message DebugCreateNodeRequest {
|
||||||
string user = 1;
|
string user = 1;
|
||||||
string key = 2;
|
string key = 2;
|
||||||
string name = 3;
|
string name = 3;
|
||||||
repeated string routes = 4;
|
repeated string routes = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DebugCreateMachineResponse {
|
message DebugCreateNodeResponse {
|
||||||
Machine machine = 1;
|
Node node = 1;
|
||||||
}
|
}
|
|
@ -3,11 +3,11 @@ package headscale.v1;
|
||||||
option go_package = "github.com/juanfont/headscale/gen/go/v1";
|
option go_package = "github.com/juanfont/headscale/gen/go/v1";
|
||||||
|
|
||||||
import "google/protobuf/timestamp.proto";
|
import "google/protobuf/timestamp.proto";
|
||||||
import "headscale/v1/machine.proto";
|
import "headscale/v1/node.proto";
|
||||||
|
|
||||||
message Route {
|
message Route {
|
||||||
uint64 id = 1;
|
uint64 id = 1;
|
||||||
Machine machine = 2;
|
Node node = 2;
|
||||||
string prefix = 3;
|
string prefix = 3;
|
||||||
bool advertised = 4;
|
bool advertised = 4;
|
||||||
bool enabled = 5;
|
bool enabled = 5;
|
||||||
|
@ -39,11 +39,11 @@ message DisableRouteRequest {
|
||||||
message DisableRouteResponse {
|
message DisableRouteResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetMachineRoutesRequest {
|
message GetNodeRoutesRequest {
|
||||||
uint64 machine_id = 1;
|
uint64 node_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetMachineRoutesResponse {
|
message GetNodeRoutesResponse {
|
||||||
repeated Route routes = 1;
|
repeated Route routes = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue