Rename Machine to Node (#1553)

This commit is contained in:
Juan Font 2023-09-24 13:42:05 +02:00 committed by GitHub
parent 096ac31bb3
commit 0030af3fa4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 5222 additions and 5238 deletions

View file

@ -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

View file

@ -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)
}, },
} }

View file

@ -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,
) )
} }

View file

@ -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)

View file

@ -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),

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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"
} }
} }
}, },

View file

@ -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": [

View file

@ -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)
} }
} }

View file

@ -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 = &registerRequest.Expiry newNode.Expiry = &registerRequest.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")
} }

View file

@ -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

View file

@ -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

View file

@ -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(

View file

@ -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)

View file

@ -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")
} }
} }
} }

View file

@ -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
View 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
}

View file

@ -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)
} }

View file

@ -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
} }

View file

@ -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)
} }

View file

@ -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(&currentRoutes).Error err := hsdb.db.Where("node_id = ?", node.ID).Find(&currentRoutes).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

View file

@ -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)
} }

View file

@ -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
} }

View file

@ -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)
} }

View file

@ -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() {}

View file

@ -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

View file

@ -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,
) )

View file

@ -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
} }

View file

@ -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,

View file

@ -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.
) )

View file

@ -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")
} }

View file

@ -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

View file

@ -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)

View file

@ -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)
} }

View file

@ -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)
} }

View file

@ -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

View file

@ -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
View 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
}

View file

@ -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"),

View file

@ -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,

View file

@ -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")
} }

View file

@ -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

View file

@ -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)
} }

View file

@ -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)

View file

@ -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"
}; };
} }

View file

@ -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;
} }

View file

@ -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;
} }