From 7891378f5701f4b5c31453e9cf29f6bad0e781ba Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Wed, 26 Feb 2025 07:22:55 -0800 Subject: [PATCH] Redo route code (#2422) Signed-off-by: Kristoffer Dalby --- .golangci.yaml | 8 +- CHANGELOG.md | 30 + cmd/headscale/cli/nodes.go | 166 ++- cmd/headscale/cli/routes.go | 271 ---- docs/ref/exit-node.md | 28 +- gen/go/headscale/v1/apikey.pb.go | 76 +- gen/go/headscale/v1/device.pb.go | 120 +- gen/go/headscale/v1/headscale.pb.go | 591 ++++---- gen/go/headscale/v1/headscale.pb.gw.go | 530 ++----- gen/go/headscale/v1/headscale_grpc.pb.go | 365 ++--- gen/go/headscale/v1/node.pb.go | 686 +++++---- gen/go/headscale/v1/policy.pb.go | 43 +- gen/go/headscale/v1/preauthkey.pb.go | 86 +- gen/go/headscale/v1/routes.pb.go | 677 --------- gen/go/headscale/v1/user.pb.go | 86 +- .../headscale/v1/headscale.swagger.json | 278 +--- .../headscale/v1/routes.swagger.json | 44 - hscontrol/app.go | 8 +- hscontrol/auth.go | 5 +- hscontrol/db/db.go | 57 + hscontrol/db/db_test.go | 93 +- hscontrol/db/ip_test.go | 19 +- hscontrol/db/node.go | 201 +-- hscontrol/db/node_test.go | 235 ++-- hscontrol/db/routes.go | 676 --------- hscontrol/db/routes_test.go | 1233 ----------------- hscontrol/debug.go | 5 + hscontrol/grpcv1.go | 151 +- hscontrol/mapper/mapper.go | 30 +- hscontrol/mapper/mapper_test.go | 164 +-- hscontrol/mapper/tail.go | 20 +- hscontrol/mapper/tail_test.go | 47 +- hscontrol/policy/acls.go | 13 +- hscontrol/policy/acls_test.go | 36 +- hscontrol/policy/matcher/matcher.go | 36 +- hscontrol/policy/pm.go | 32 + hscontrol/poll.go | 106 +- hscontrol/routes/primary.go | 186 +++ hscontrol/routes/primary_test.go | 316 +++++ hscontrol/types/node.go | 78 +- hscontrol/types/routes.go | 93 +- hscontrol/types/routes_test.go | 89 -- hscontrol/types/users.go | 13 +- hscontrol/util/net.go | 39 + hscontrol/util/string.go | 18 + integration/control.go | 3 + integration/hsic/hsic.go | 28 + integration/route_test.go | 1010 ++++---------- integration/tailscale.go | 1 + integration/tsic/tsic.go | 10 + proto/headscale/v1/headscale.proto | 43 +- proto/headscale/v1/node.proto | 10 + proto/headscale/v1/routes.proto | 39 - 53 files changed, 2977 insertions(+), 6251 deletions(-) delete mode 100644 cmd/headscale/cli/routes.go delete mode 100644 gen/go/headscale/v1/routes.pb.go delete mode 100644 gen/openapiv2/headscale/v1/routes.swagger.json delete mode 100644 hscontrol/db/routes.go delete mode 100644 hscontrol/db/routes_test.go create mode 100644 hscontrol/routes/primary.go create mode 100644 hscontrol/routes/primary_test.go delete mode 100644 hscontrol/types/routes_test.go delete mode 100644 proto/headscale/v1/routes.proto diff --git a/.golangci.yaml b/.golangci.yaml index 0df9a637..c6c574ed 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -10,8 +10,6 @@ issues: linters: enable-all: true disable: - - depguard - - revive - lll - gofmt @@ -28,6 +26,7 @@ linters: - musttag # causes issues with imported libs - depguard - exportloopref + - tenv # We should strive to enable these: - wrapcheck @@ -59,6 +58,11 @@ linters-settings: - tt - tx - rx + - sb + - wg + - pr + - p + - p2 gocritic: disabled-checks: diff --git a/CHANGELOG.md b/CHANGELOG.md index 59963e03..d0571150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,36 @@ ## Next +### BREAKING + +Route internals have been rewritten, removing the dedicated route table in the database. +This was done to simplify the codebase, which had grown unnecessarily complex after +the routes were split into separate tables. The overhead of having to go via the database +and keeping the state in sync made the code very hard to reason about and prone to errors. +The majority of the route state is only relevant when headscale is running, and is now only +kept in memory. +As part of this, the CLI and API has been simplified to reflect the changes; + +```console +$ headscale nodes list-routes +ID | Hostname | Approved | Available | Serving +1 | ts-head-ruqsg8 | | 0.0.0.0/0, ::/0 | +2 | ts-unstable-fq7ob4 | | 0.0.0.0/0, ::/0 | + +$ headscale nodes approve-routes --identifier 1 --routes 0.0.0.0/0,::/0 +Node updated + +$ headscale nodes list-routes +ID | Hostname | Approved | Available | Serving +1 | ts-head-ruqsg8 | 0.0.0.0/0, ::/0 | 0.0.0.0/0, ::/0 | 0.0.0.0/0, ::/0 +2 | ts-unstable-fq7ob4 | | 0.0.0.0/0, ::/0 | +``` + +Note that if an exit route is approved (0.0.0.0/0 or ::/0), both IPv4 and IPv6 will be approved. + +- Route API and CLI has been removed [#2422](https://github.com/juanfont/headscale/pull/2422) +- Routes are now managed via the Node API [#2422](https://github.com/juanfont/headscale/pull/2422) + ### Changes - Use Go 1.24 diff --git a/cmd/headscale/cli/nodes.go b/cmd/headscale/cli/nodes.go index d6581413..a0ae4f32 100644 --- a/cmd/headscale/cli/nodes.go +++ b/cmd/headscale/cli/nodes.go @@ -27,9 +27,11 @@ func init() { listNodesNamespaceFlag := listNodesCmd.Flags().Lookup("namespace") listNodesNamespaceFlag.Deprecated = deprecateNamespaceMessage listNodesNamespaceFlag.Hidden = true - nodeCmd.AddCommand(listNodesCmd) + listNodeRoutesCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") + nodeCmd.AddCommand(listNodeRoutesCmd) + registerNodeCmd.Flags().StringP("user", "u", "", "User") registerNodeCmd.Flags().StringP("namespace", "n", "", "User") @@ -90,15 +92,15 @@ func init() { nodeCmd.AddCommand(moveNodeCmd) tagCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") - - err = tagCmd.MarkFlagRequired("identifier") - if err != nil { - log.Fatal(err.Error()) - } - tagCmd.Flags(). - StringSliceP("tags", "t", []string{}, "List of tags to add to the node") + tagCmd.MarkFlagRequired("identifier") + tagCmd.Flags().StringSliceP("tags", "t", []string{}, "List of tags to add to the node") nodeCmd.AddCommand(tagCmd) + approveRoutesCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") + approveRoutesCmd.MarkFlagRequired("identifier") + approveRoutesCmd.Flags().StringSliceP("routes", "r", []string{}, "List of routes that will be approved") + nodeCmd.AddCommand(approveRoutesCmd) + nodeCmd.AddCommand(backfillNodeIPsCmd) } @@ -206,6 +208,68 @@ var listNodesCmd = &cobra.Command{ }, } +var listNodeRoutesCmd = &cobra.Command{ + Use: "list-routes", + Short: "List routes available on nodes", + Aliases: []string{"lsr", "routes"}, + Run: func(cmd *cobra.Command, args []string) { + output, _ := cmd.Flags().GetString("output") + identifier, err := cmd.Flags().GetUint64("identifier") + if err != nil { + ErrorOutput( + err, + fmt.Sprintf("Error converting ID to integer: %s", err), + output, + ) + + return + } + + ctx, client, conn, cancel := newHeadscaleCLIWithConfig() + defer cancel() + defer conn.Close() + + request := &v1.ListNodesRequest{} + + response, err := client.ListNodes(ctx, request) + if err != nil { + ErrorOutput( + err, + "Cannot get nodes: "+status.Convert(err).Message(), + output, + ) + } + + if output != "" { + SuccessOutput(response.GetNodes(), "", output) + } + + nodes := response.GetNodes() + if identifier != 0 { + for _, node := range response.GetNodes() { + if node.GetId() == identifier { + nodes = []*v1.Node{node} + break + } + } + } + + tableData, err := nodeRoutesToPtables(nodes) + if err != nil { + ErrorOutput(err, fmt.Sprintf("Error converting to table: %s", err), output) + } + + err = pterm.DefaultTable.WithHasHeader().WithData(tableData).Render() + if err != nil { + ErrorOutput( + err, + fmt.Sprintf("Failed to render pterm table: %s", err), + output, + ) + } + }, +} + var expireNodeCmd = &cobra.Command{ Use: "expire", Short: "Expire (log out) a node in your network", @@ -657,6 +721,35 @@ func nodesToPtables( return tableData, nil } +func nodeRoutesToPtables( + nodes []*v1.Node, +) (pterm.TableData, error) { + tableHeader := []string{ + "ID", + "Hostname", + "Approved", + "Available", + "Serving", + } + tableData := pterm.TableData{tableHeader} + + for _, node := range nodes { + nodeData := []string{ + strconv.FormatUint(node.GetId(), util.Base10), + node.GetGivenName(), + strings.Join(node.GetApprovedRoutes(), ", "), + strings.Join(node.GetAvailableRoutes(), ", "), + strings.Join(node.GetSubnetRoutes(), ", "), + } + tableData = append( + tableData, + nodeData, + ) + } + + return tableData, nil +} + var tagCmd = &cobra.Command{ Use: "tag", Short: "Manage the tags of a node", @@ -714,3 +807,60 @@ var tagCmd = &cobra.Command{ } }, } + +var approveRoutesCmd = &cobra.Command{ + Use: "approve-routes", + Short: "Manage the approved routes of a node", + Run: func(cmd *cobra.Command, args []string) { + output, _ := cmd.Flags().GetString("output") + ctx, client, conn, cancel := newHeadscaleCLIWithConfig() + defer cancel() + defer conn.Close() + + // retrieve flags from CLI + identifier, err := cmd.Flags().GetUint64("identifier") + if err != nil { + ErrorOutput( + err, + fmt.Sprintf("Error converting ID to integer: %s", err), + output, + ) + + return + } + routes, err := cmd.Flags().GetStringSlice("routes") + if err != nil { + ErrorOutput( + err, + fmt.Sprintf("Error retrieving list of routes to add to node, %v", err), + output, + ) + + return + } + + // Sending tags to node + request := &v1.SetApprovedRoutesRequest{ + NodeId: identifier, + Routes: routes, + } + resp, err := client.SetApprovedRoutes(ctx, request) + if err != nil { + ErrorOutput( + err, + fmt.Sprintf("Error while sending routes to headscale: %s", err), + output, + ) + + return + } + + if resp != nil { + SuccessOutput( + resp.GetNode(), + "Node updated", + output, + ) + } + }, +} diff --git a/cmd/headscale/cli/routes.go b/cmd/headscale/cli/routes.go deleted file mode 100644 index ef289497..00000000 --- a/cmd/headscale/cli/routes.go +++ /dev/null @@ -1,271 +0,0 @@ -package cli - -import ( - "fmt" - "log" - "net/netip" - "strconv" - - v1 "github.com/juanfont/headscale/gen/go/headscale/v1" - "github.com/pterm/pterm" - "github.com/spf13/cobra" - "google.golang.org/grpc/status" - "tailscale.com/net/tsaddr" -) - -const ( - Base10 = 10 -) - -func init() { - rootCmd.AddCommand(routesCmd) - listRoutesCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") - routesCmd.AddCommand(listRoutesCmd) - - enableRouteCmd.Flags().Uint64P("route", "r", 0, "Route identifier (ID)") - err := enableRouteCmd.MarkFlagRequired("route") - if err != nil { - log.Fatal(err.Error()) - } - routesCmd.AddCommand(enableRouteCmd) - - disableRouteCmd.Flags().Uint64P("route", "r", 0, "Route identifier (ID)") - err = disableRouteCmd.MarkFlagRequired("route") - if err != nil { - log.Fatal(err.Error()) - } - routesCmd.AddCommand(disableRouteCmd) - - deleteRouteCmd.Flags().Uint64P("route", "r", 0, "Route identifier (ID)") - err = deleteRouteCmd.MarkFlagRequired("route") - if err != nil { - log.Fatal(err.Error()) - } - routesCmd.AddCommand(deleteRouteCmd) -} - -var routesCmd = &cobra.Command{ - Use: "routes", - Short: "Manage the routes of Headscale", - Aliases: []string{"r", "route"}, -} - -var listRoutesCmd = &cobra.Command{ - Use: "list", - Short: "List all routes", - Aliases: []string{"ls", "show"}, - Run: func(cmd *cobra.Command, args []string) { - output, _ := cmd.Flags().GetString("output") - - machineID, err := cmd.Flags().GetUint64("identifier") - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Error getting machine id from flag: %s", err), - output, - ) - } - - ctx, client, conn, cancel := newHeadscaleCLIWithConfig() - defer cancel() - defer conn.Close() - - var routes []*v1.Route - - if machineID == 0 { - response, err := client.GetRoutes(ctx, &v1.GetRoutesRequest{}) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Cannot get nodes: %s", status.Convert(err).Message()), - output, - ) - } - - if output != "" { - SuccessOutput(response.GetRoutes(), "", output) - } - - routes = response.GetRoutes() - } else { - response, err := client.GetNodeRoutes(ctx, &v1.GetNodeRoutesRequest{ - NodeId: machineID, - }) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Cannot get routes for node %d: %s", machineID, status.Convert(err).Message()), - output, - ) - } - - if output != "" { - SuccessOutput(response.GetRoutes(), "", output) - } - - routes = response.GetRoutes() - } - - tableData := routesToPtables(routes) - if err != nil { - ErrorOutput(err, fmt.Sprintf("Error converting to table: %s", err), output) - } - - err = pterm.DefaultTable.WithHasHeader().WithData(tableData).Render() - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Failed to render pterm table: %s", err), - output, - ) - } - }, -} - -var enableRouteCmd = &cobra.Command{ - Use: "enable", - Short: "Set a route as enabled", - Long: `This command will make as enabled a given route.`, - Run: func(cmd *cobra.Command, args []string) { - output, _ := cmd.Flags().GetString("output") - - routeID, err := cmd.Flags().GetUint64("route") - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Error getting machine id from flag: %s", err), - output, - ) - } - - ctx, client, conn, cancel := newHeadscaleCLIWithConfig() - defer cancel() - defer conn.Close() - - response, err := client.EnableRoute(ctx, &v1.EnableRouteRequest{ - RouteId: routeID, - }) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Cannot enable route %d: %s", routeID, status.Convert(err).Message()), - output, - ) - } - - if output != "" { - SuccessOutput(response, "", output) - } - }, -} - -var disableRouteCmd = &cobra.Command{ - Use: "disable", - Short: "Set as disabled a given route", - Long: `This command will make as disabled a given route.`, - Run: func(cmd *cobra.Command, args []string) { - output, _ := cmd.Flags().GetString("output") - - routeID, err := cmd.Flags().GetUint64("route") - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Error getting machine id from flag: %s", err), - output, - ) - } - - ctx, client, conn, cancel := newHeadscaleCLIWithConfig() - defer cancel() - defer conn.Close() - - response, err := client.DisableRoute(ctx, &v1.DisableRouteRequest{ - RouteId: routeID, - }) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Cannot disable route %d: %s", routeID, status.Convert(err).Message()), - output, - ) - } - - if output != "" { - SuccessOutput(response, "", output) - } - }, -} - -var deleteRouteCmd = &cobra.Command{ - Use: "delete", - Short: "Delete a given route", - Long: `This command will delete a given route.`, - Run: func(cmd *cobra.Command, args []string) { - output, _ := cmd.Flags().GetString("output") - - routeID, err := cmd.Flags().GetUint64("route") - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Error getting machine id from flag: %s", err), - output, - ) - } - - ctx, client, conn, cancel := newHeadscaleCLIWithConfig() - defer cancel() - defer conn.Close() - - response, err := client.DeleteRoute(ctx, &v1.DeleteRouteRequest{ - RouteId: routeID, - }) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Cannot delete route %d: %s", routeID, status.Convert(err).Message()), - output, - ) - } - - if output != "" { - SuccessOutput(response, "", output) - } - }, -} - -// routesToPtables converts the list of routes to a nice table. -func routesToPtables(routes []*v1.Route) pterm.TableData { - tableData := pterm.TableData{{"ID", "Node", "Prefix", "Advertised", "Enabled", "Primary"}} - - for _, route := range routes { - var isPrimaryStr string - prefix, err := netip.ParsePrefix(route.GetPrefix()) - if err != nil { - log.Printf("Error parsing prefix %s: %s", route.GetPrefix(), err) - - continue - } - if tsaddr.IsExitRoute(prefix) { - isPrimaryStr = "-" - } else { - isPrimaryStr = strconv.FormatBool(route.GetIsPrimary()) - } - - var nodeName string - if route.GetNode() != nil { - nodeName = route.GetNode().GetGivenName() - } - - tableData = append(tableData, - []string{ - strconv.FormatUint(route.GetId(), Base10), - nodeName, - route.GetPrefix(), - strconv.FormatBool(route.GetAdvertised()), - strconv.FormatBool(route.GetEnabled()), - isPrimaryStr, - }) - } - - return tableData -} diff --git a/docs/ref/exit-node.md b/docs/ref/exit-node.md index 1acd20a3..5f9ba6a7 100644 --- a/docs/ref/exit-node.md +++ b/docs/ref/exit-node.md @@ -19,25 +19,19 @@ To use a node as an exit node, IP forwarding must be enabled on the node. Check ## On the control server ```console -$ # list nodes -$ headscale routes list -ID | Node | Prefix | Advertised | Enabled | Primary -1 | | 0.0.0.0/0 | false | false | - -2 | | ::/0 | false | false | - -3 | phobos | 0.0.0.0/0 | true | false | - -4 | phobos | ::/0 | true | false | - +$ headscale nodes list-routes +ID | Hostname | Approved | Available | Serving +1 | ts-head-ruqsg8 | | 0.0.0.0/0, ::/0 | +2 | ts-unstable-fq7ob4 | | 0.0.0.0/0, ::/0 | -$ # enable routes for phobos -$ headscale routes enable -r 3 -$ headscale routes enable -r 4 +# Note that for exit nodes, it is sufficient to approve either the IPv4 or IPv6 route. The other will be added automatically. +$ headscale nodes approve-routes --identifier 1 --routes 0.0.0.0/0 +Node updated -$ # Check node list again. The routes are now enabled. -$ headscale routes list -ID | Node | Prefix | Advertised | Enabled | Primary -1 | | 0.0.0.0/0 | false | false | - -2 | | ::/0 | false | false | - -3 | phobos | 0.0.0.0/0 | true | true | - -4 | phobos | ::/0 | true | true | - +$ headscale nodes list-routes +ID | Hostname | Approved | Available | Serving +1 | ts-head-ruqsg8 | 0.0.0.0/0, ::/0 | 0.0.0.0/0, ::/0 | 0.0.0.0/0, ::/0 +2 | ts-unstable-fq7ob4 | | 0.0.0.0/0, ::/0 | ``` ## On the client diff --git a/gen/go/headscale/v1/apikey.pb.go b/gen/go/headscale/v1/apikey.pb.go index c1529c17..2fdd8094 100644 --- a/gen/go/headscale/v1/apikey.pb.go +++ b/gen/go/headscale/v1/apikey.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: headscale/v1/apikey.proto @@ -12,6 +12,7 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,15 +23,14 @@ const ( ) type ApiKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Prefix string `protobuf:"bytes,2,opt,name=prefix,proto3" json:"prefix,omitempty"` + Expiration *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expiration,proto3" json:"expiration,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + LastSeen *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=last_seen,json=lastSeen,proto3" json:"last_seen,omitempty"` unknownFields protoimpl.UnknownFields - - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Prefix string `protobuf:"bytes,2,opt,name=prefix,proto3" json:"prefix,omitempty"` - Expiration *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expiration,proto3" json:"expiration,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - LastSeen *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=last_seen,json=lastSeen,proto3" json:"last_seen,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ApiKey) Reset() { @@ -99,11 +99,10 @@ func (x *ApiKey) GetLastSeen() *timestamppb.Timestamp { } type CreateApiKeyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Expiration *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=expiration,proto3" json:"expiration,omitempty"` unknownFields protoimpl.UnknownFields - - Expiration *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=expiration,proto3" json:"expiration,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateApiKeyRequest) Reset() { @@ -144,11 +143,10 @@ func (x *CreateApiKeyRequest) GetExpiration() *timestamppb.Timestamp { } type CreateApiKeyResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ApiKey string `protobuf:"bytes,1,opt,name=api_key,json=apiKey,proto3" json:"api_key,omitempty"` unknownFields protoimpl.UnknownFields - - ApiKey string `protobuf:"bytes,1,opt,name=api_key,json=apiKey,proto3" json:"api_key,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateApiKeyResponse) Reset() { @@ -189,11 +187,10 @@ func (x *CreateApiKeyResponse) GetApiKey() string { } type ExpireApiKeyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` unknownFields protoimpl.UnknownFields - - Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ExpireApiKeyRequest) Reset() { @@ -234,9 +231,9 @@ func (x *ExpireApiKeyRequest) GetPrefix() string { } type ExpireApiKeyResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExpireApiKeyResponse) Reset() { @@ -270,9 +267,9 @@ func (*ExpireApiKeyResponse) Descriptor() ([]byte, []int) { } type ListApiKeysRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ListApiKeysRequest) Reset() { @@ -306,11 +303,10 @@ func (*ListApiKeysRequest) Descriptor() ([]byte, []int) { } type ListApiKeysResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ApiKeys []*ApiKey `protobuf:"bytes,1,rep,name=api_keys,json=apiKeys,proto3" json:"api_keys,omitempty"` unknownFields protoimpl.UnknownFields - - ApiKeys []*ApiKey `protobuf:"bytes,1,rep,name=api_keys,json=apiKeys,proto3" json:"api_keys,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListApiKeysResponse) Reset() { @@ -351,11 +347,10 @@ func (x *ListApiKeysResponse) GetApiKeys() []*ApiKey { } type DeleteApiKeyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` unknownFields protoimpl.UnknownFields - - Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DeleteApiKeyRequest) Reset() { @@ -396,9 +391,9 @@ func (x *DeleteApiKeyRequest) GetPrefix() string { } type DeleteApiKeyResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DeleteApiKeyResponse) Reset() { @@ -433,7 +428,7 @@ func (*DeleteApiKeyResponse) Descriptor() ([]byte, []int) { var File_headscale_v1_apikey_proto protoreflect.FileDescriptor -var file_headscale_v1_apikey_proto_rawDesc = []byte{ +var file_headscale_v1_apikey_proto_rawDesc = string([]byte{ 0x0a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 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, @@ -479,16 +474,16 @@ var file_headscale_v1_apikey_proto_rawDesc = []byte{ 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_apikey_proto_rawDescOnce sync.Once - file_headscale_v1_apikey_proto_rawDescData = file_headscale_v1_apikey_proto_rawDesc + file_headscale_v1_apikey_proto_rawDescData []byte ) func file_headscale_v1_apikey_proto_rawDescGZIP() []byte { file_headscale_v1_apikey_proto_rawDescOnce.Do(func() { - file_headscale_v1_apikey_proto_rawDescData = protoimpl.X.CompressGZIP(file_headscale_v1_apikey_proto_rawDescData) + file_headscale_v1_apikey_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_headscale_v1_apikey_proto_rawDesc), len(file_headscale_v1_apikey_proto_rawDesc))) }) return file_headscale_v1_apikey_proto_rawDescData } @@ -528,7 +523,7 @@ func file_headscale_v1_apikey_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_headscale_v1_apikey_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_headscale_v1_apikey_proto_rawDesc), len(file_headscale_v1_apikey_proto_rawDesc)), NumEnums: 0, NumMessages: 9, NumExtensions: 0, @@ -539,7 +534,6 @@ func file_headscale_v1_apikey_proto_init() { MessageInfos: file_headscale_v1_apikey_proto_msgTypes, }.Build() File_headscale_v1_apikey_proto = out.File - file_headscale_v1_apikey_proto_rawDesc = nil file_headscale_v1_apikey_proto_goTypes = nil file_headscale_v1_apikey_proto_depIdxs = nil } diff --git a/gen/go/headscale/v1/device.pb.go b/gen/go/headscale/v1/device.pb.go index de59736b..641f1f7c 100644 --- a/gen/go/headscale/v1/device.pb.go +++ b/gen/go/headscale/v1/device.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: headscale/v1/device.proto @@ -12,6 +12,7 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,12 +23,11 @@ const ( ) type Latency struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + LatencyMs float32 `protobuf:"fixed32,1,opt,name=latency_ms,json=latencyMs,proto3" json:"latency_ms,omitempty"` + Preferred bool `protobuf:"varint,2,opt,name=preferred,proto3" json:"preferred,omitempty"` unknownFields protoimpl.UnknownFields - - LatencyMs float32 `protobuf:"fixed32,1,opt,name=latency_ms,json=latencyMs,proto3" json:"latency_ms,omitempty"` - Preferred bool `protobuf:"varint,2,opt,name=preferred,proto3" json:"preferred,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Latency) Reset() { @@ -75,16 +75,15 @@ func (x *Latency) GetPreferred() bool { } type ClientSupports struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + HairPinning bool `protobuf:"varint,1,opt,name=hair_pinning,json=hairPinning,proto3" json:"hair_pinning,omitempty"` + Ipv6 bool `protobuf:"varint,2,opt,name=ipv6,proto3" json:"ipv6,omitempty"` + Pcp bool `protobuf:"varint,3,opt,name=pcp,proto3" json:"pcp,omitempty"` + Pmp bool `protobuf:"varint,4,opt,name=pmp,proto3" json:"pmp,omitempty"` + Udp bool `protobuf:"varint,5,opt,name=udp,proto3" json:"udp,omitempty"` + Upnp bool `protobuf:"varint,6,opt,name=upnp,proto3" json:"upnp,omitempty"` unknownFields protoimpl.UnknownFields - - HairPinning bool `protobuf:"varint,1,opt,name=hair_pinning,json=hairPinning,proto3" json:"hair_pinning,omitempty"` - Ipv6 bool `protobuf:"varint,2,opt,name=ipv6,proto3" json:"ipv6,omitempty"` - Pcp bool `protobuf:"varint,3,opt,name=pcp,proto3" json:"pcp,omitempty"` - Pmp bool `protobuf:"varint,4,opt,name=pmp,proto3" json:"pmp,omitempty"` - Udp bool `protobuf:"varint,5,opt,name=udp,proto3" json:"udp,omitempty"` - Upnp bool `protobuf:"varint,6,opt,name=upnp,proto3" json:"upnp,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ClientSupports) Reset() { @@ -160,15 +159,14 @@ func (x *ClientSupports) GetUpnp() bool { } type ClientConnectivity struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Endpoints []string `protobuf:"bytes,1,rep,name=endpoints,proto3" json:"endpoints,omitempty"` - Derp string `protobuf:"bytes,2,opt,name=derp,proto3" json:"derp,omitempty"` - MappingVariesByDestIp bool `protobuf:"varint,3,opt,name=mapping_varies_by_dest_ip,json=mappingVariesByDestIp,proto3" json:"mapping_varies_by_dest_ip,omitempty"` - Latency map[string]*Latency `protobuf:"bytes,4,rep,name=latency,proto3" json:"latency,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - ClientSupports *ClientSupports `protobuf:"bytes,5,opt,name=client_supports,json=clientSupports,proto3" json:"client_supports,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Endpoints []string `protobuf:"bytes,1,rep,name=endpoints,proto3" json:"endpoints,omitempty"` + Derp string `protobuf:"bytes,2,opt,name=derp,proto3" json:"derp,omitempty"` + MappingVariesByDestIp bool `protobuf:"varint,3,opt,name=mapping_varies_by_dest_ip,json=mappingVariesByDestIp,proto3" json:"mapping_varies_by_dest_ip,omitempty"` + Latency map[string]*Latency `protobuf:"bytes,4,rep,name=latency,proto3" json:"latency,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + ClientSupports *ClientSupports `protobuf:"bytes,5,opt,name=client_supports,json=clientSupports,proto3" json:"client_supports,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ClientConnectivity) Reset() { @@ -237,11 +235,10 @@ func (x *ClientConnectivity) GetClientSupports() *ClientSupports { } type GetDeviceRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetDeviceRequest) Reset() { @@ -282,10 +279,7 @@ func (x *GetDeviceRequest) GetId() string { } type GetDeviceResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Addresses []string `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` User string `protobuf:"bytes,3,opt,name=user,proto3" json:"user,omitempty"` @@ -306,6 +300,8 @@ type GetDeviceResponse struct { EnabledRoutes []string `protobuf:"bytes,18,rep,name=enabled_routes,json=enabledRoutes,proto3" json:"enabled_routes,omitempty"` AdvertisedRoutes []string `protobuf:"bytes,19,rep,name=advertised_routes,json=advertisedRoutes,proto3" json:"advertised_routes,omitempty"` ClientConnectivity *ClientConnectivity `protobuf:"bytes,20,opt,name=client_connectivity,json=clientConnectivity,proto3" json:"client_connectivity,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetDeviceResponse) Reset() { @@ -479,11 +475,10 @@ func (x *GetDeviceResponse) GetClientConnectivity() *ClientConnectivity { } type DeleteDeviceRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DeleteDeviceRequest) Reset() { @@ -524,9 +519,9 @@ func (x *DeleteDeviceRequest) GetId() string { } type DeleteDeviceResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DeleteDeviceResponse) Reset() { @@ -560,11 +555,10 @@ func (*DeleteDeviceResponse) Descriptor() ([]byte, []int) { } type GetDeviceRoutesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetDeviceRoutesRequest) Reset() { @@ -605,12 +599,11 @@ func (x *GetDeviceRoutesRequest) GetId() string { } type GetDeviceRoutesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - EnabledRoutes []string `protobuf:"bytes,1,rep,name=enabled_routes,json=enabledRoutes,proto3" json:"enabled_routes,omitempty"` - AdvertisedRoutes []string `protobuf:"bytes,2,rep,name=advertised_routes,json=advertisedRoutes,proto3" json:"advertised_routes,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + EnabledRoutes []string `protobuf:"bytes,1,rep,name=enabled_routes,json=enabledRoutes,proto3" json:"enabled_routes,omitempty"` + AdvertisedRoutes []string `protobuf:"bytes,2,rep,name=advertised_routes,json=advertisedRoutes,proto3" json:"advertised_routes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetDeviceRoutesResponse) Reset() { @@ -658,12 +651,11 @@ func (x *GetDeviceRoutesResponse) GetAdvertisedRoutes() []string { } type EnableDeviceRoutesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Routes []string `protobuf:"bytes,2,rep,name=routes,proto3" json:"routes,omitempty"` unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Routes []string `protobuf:"bytes,2,rep,name=routes,proto3" json:"routes,omitempty"` + sizeCache protoimpl.SizeCache } func (x *EnableDeviceRoutesRequest) Reset() { @@ -711,12 +703,11 @@ func (x *EnableDeviceRoutesRequest) GetRoutes() []string { } type EnableDeviceRoutesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - EnabledRoutes []string `protobuf:"bytes,1,rep,name=enabled_routes,json=enabledRoutes,proto3" json:"enabled_routes,omitempty"` - AdvertisedRoutes []string `protobuf:"bytes,2,rep,name=advertised_routes,json=advertisedRoutes,proto3" json:"advertised_routes,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + EnabledRoutes []string `protobuf:"bytes,1,rep,name=enabled_routes,json=enabledRoutes,proto3" json:"enabled_routes,omitempty"` + AdvertisedRoutes []string `protobuf:"bytes,2,rep,name=advertised_routes,json=advertisedRoutes,proto3" json:"advertised_routes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EnableDeviceRoutesResponse) Reset() { @@ -765,7 +756,7 @@ func (x *EnableDeviceRoutesResponse) GetAdvertisedRoutes() []string { var File_headscale_v1_device_proto protoreflect.FileDescriptor -var file_headscale_v1_device_proto_rawDesc = []byte{ +var file_headscale_v1_device_proto_rawDesc = string([]byte{ 0x0a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 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, @@ -888,16 +879,16 @@ var file_headscale_v1_device_proto_rawDesc = []byte{ 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_device_proto_rawDescOnce sync.Once - file_headscale_v1_device_proto_rawDescData = file_headscale_v1_device_proto_rawDesc + file_headscale_v1_device_proto_rawDescData []byte ) func file_headscale_v1_device_proto_rawDescGZIP() []byte { file_headscale_v1_device_proto_rawDescOnce.Do(func() { - file_headscale_v1_device_proto_rawDescData = protoimpl.X.CompressGZIP(file_headscale_v1_device_proto_rawDescData) + file_headscale_v1_device_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_headscale_v1_device_proto_rawDesc), len(file_headscale_v1_device_proto_rawDesc))) }) return file_headscale_v1_device_proto_rawDescData } @@ -942,7 +933,7 @@ func file_headscale_v1_device_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_headscale_v1_device_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_headscale_v1_device_proto_rawDesc), len(file_headscale_v1_device_proto_rawDesc)), NumEnums: 0, NumMessages: 12, NumExtensions: 0, @@ -953,7 +944,6 @@ func file_headscale_v1_device_proto_init() { MessageInfos: file_headscale_v1_device_proto_msgTypes, }.Build() File_headscale_v1_device_proto = out.File - file_headscale_v1_device_proto_rawDesc = nil file_headscale_v1_device_proto_goTypes = nil file_headscale_v1_device_proto_depIdxs = nil } diff --git a/gen/go/headscale/v1/headscale.pb.go b/gen/go/headscale/v1/headscale.pb.go index 32e97ee6..394d2c03 100644 --- a/gen/go/headscale/v1/headscale.pb.go +++ b/gen/go/headscale/v1/headscale.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: headscale/v1/headscale.proto @@ -11,6 +11,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" + unsafe "unsafe" ) const ( @@ -22,7 +23,7 @@ const ( var File_headscale_v1_headscale_proto protoreflect.FileDescriptor -var file_headscale_v1_headscale_proto_rawDesc = []byte{ +var file_headscale_v1_headscale_proto_rawDesc = string([]byte{ 0x0a, 0x1c, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x67, 0x6f, @@ -33,280 +34,242 @@ var file_headscale_v1_headscale_proto_rawDesc = []byte{ 0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x68, 0x65, 0x61, - 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, + 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, - 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xe9, 0x19, 0x0a, - 0x10, 0x48, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x68, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, - 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x32, 0xa3, 0x16, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x68, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x3a, + 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, + 0x12, 0x80, 0x01, 0x0a, 0x0a, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x12, 0x80, 0x01, 0x0a, 0x0a, - 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, - 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, - 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, - 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, - 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2f, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x27, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, - 0x73, 0x65, 0x72, 0x2f, 0x7b, 0x6f, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x65, 0x6e, - 0x61, 0x6d, 0x65, 0x2f, 0x7b, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x6a, - 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, - 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, - 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x2a, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x62, 0x0a, 0x09, 0x4c, 0x69, - 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, - 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, - 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, - 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x12, 0x80, - 0x01, 0x0a, 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, 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, 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, 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, 0x65, 0x79, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x7a, 0x0a, 0x0f, 0x4c, - 0x69, 0x73, 0x74, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x73, 0x12, 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, 0x7d, 0x0a, 0x0f, 0x44, 0x65, 0x62, 0x75, 0x67, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x24, 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, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x25, 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, 0x4e, 0x6f, 0x64, 0x65, 0x52, + 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x27, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x7b, 0x6f, 0x6c, 0x64, 0x5f, 0x69, 0x64, + 0x7d, 0x2f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x2f, 0x7b, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x7d, 0x12, 0x6a, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x2a, 0x11, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, + 0x62, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x68, + 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, + 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x75, + 0x73, 0x65, 0x72, 0x12, 0x80, 0x01, 0x0a, 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, 0x64, 0x65, 0x62, 0x75, - 0x67, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x66, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, - 0x65, 0x12, 0x1c, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1d, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x6e, - 0x0a, 0x07, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x12, 0x1c, 0x2e, 0x68, 0x65, 0x61, 0x64, - 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, - 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, - 0x2a, 0x22, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, - 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x74, 0x61, 0x67, 0x73, 0x12, 0x74, - 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x21, - 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x15, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x12, 0x6f, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, - 0x64, 0x65, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, - 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x76, 0x0a, 0x0a, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, - 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1d, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, - 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x81, 0x01, - 0x0a, 0x0a, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x2e, 0x68, - 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, - 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, - 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, - 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x22, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, - 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x2f, 0x7b, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x12, 0x62, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x1e, - 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, - 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x71, 0x0a, 0x08, 0x4d, 0x6f, 0x76, 0x65, 0x4e, 0x6f, 0x64, - 0x65, 0x12, 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, 0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x61, 0x70, + 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, 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, 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, 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, 0x65, 0x79, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, + 0x12, 0x7a, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, + 0x65, 0x79, 0x73, 0x12, 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, 0x7d, 0x0a, 0x0f, + 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, + 0x24, 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, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 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, + 0x4e, 0x6f, 0x64, 0x65, 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, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x66, 0x0a, 0x07, 0x47, + 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1c, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, + 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, - 0x69, 0x64, 0x7d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x12, 0x80, 0x01, 0x0a, 0x0f, 0x42, 0x61, 0x63, - 0x6b, 0x66, 0x69, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x50, 0x73, 0x12, 0x24, 0x2e, 0x68, - 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, - 0x66, 0x69, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x50, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x50, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x1a, 0x22, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, - 0x62, 0x61, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x6c, 0x69, 0x70, 0x73, 0x12, 0x64, 0x0a, 0x09, 0x47, - 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, - 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, - 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, - 0x73, 0x12, 0x7c, 0x0a, 0x0b, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x22, 0x20, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x72, - 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x12, - 0x80, 0x01, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x69, 0x64, 0x7d, 0x12, 0x6e, 0x0a, 0x07, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x12, 0x1c, + 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, + 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, + 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, + 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, + 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x74, + 0x61, 0x67, 0x73, 0x12, 0x96, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x41, 0x70, 0x70, 0x72, 0x6f, + 0x76, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x26, 0x2e, 0x68, 0x65, 0x61, 0x64, + 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x70, 0x70, 0x72, + 0x6f, 0x76, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x65, 0x74, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x2a, 0x3a, 0x01, 0x2a, 0x22, 0x25, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, + 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x61, 0x70, + 0x70, 0x72, 0x6f, 0x76, 0x65, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x74, 0x0a, 0x0c, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x2e, 0x68, + 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x15, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x12, 0x6f, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, + 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, + 0x69, 0x64, 0x7d, 0x12, 0x76, 0x0a, 0x0a, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, + 0x65, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1d, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, + 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x0a, + 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x2e, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, + 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x65, + 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, + 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x22, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, + 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x65, + 0x6e, 0x61, 0x6d, 0x65, 0x2f, 0x7b, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, + 0x62, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x68, + 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, + 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, + 0x6f, 0x64, 0x65, 0x12, 0x71, 0x0a, 0x08, 0x4d, 0x6f, 0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, + 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, + 0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, + 0x7d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x12, 0x80, 0x01, 0x0a, 0x0f, 0x42, 0x61, 0x63, 0x6b, 0x66, + 0x69, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x50, 0x73, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x66, 0x69, + 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x50, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x42, 0x61, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x50, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, + 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x62, 0x61, + 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x6c, 0x69, 0x70, 0x73, 0x12, 0x70, 0x0a, 0x0c, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, + 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, + 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, + 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x12, 0x77, 0x0a, 0x0c, 0x45, + 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x65, + 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, + 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, + 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2f, 0x65, 0x78, + 0x70, 0x69, 0x72, 0x65, 0x12, 0x6a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, + 0x65, 0x79, 0x73, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, + 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, + 0x12, 0x76, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x22, - 0x21, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2f, - 0x7b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x64, 0x69, 0x73, 0x61, 0x62, - 0x6c, 0x65, 0x12, 0x7f, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x6f, 0x75, - 0x74, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, - 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, - 0x64, 0x65, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x6f, 0x75, - 0x74, 0x65, 0x73, 0x12, 0x75, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x75, - 0x74, 0x65, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x2a, - 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2f, - 0x7b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x70, 0x0a, 0x0c, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, - 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, - 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x12, 0x77, 0x0a, 0x0c, - 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x68, - 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, - 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, - 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2f, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x6a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, - 0x4b, 0x65, 0x79, 0x73, 0x12, 0x20, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, - 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, - 0x79, 0x12, 0x76, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, - 0x79, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, - 0x2a, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, - 0x2f, 0x7b, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x7d, 0x12, 0x64, 0x0a, 0x09, 0x47, 0x65, 0x74, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1e, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, - 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, - 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, - 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, - 0x67, 0x0a, 0x09, 0x53, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1e, 0x2e, 0x68, - 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, - 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x1a, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 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, -} + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x2a, + 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2f, + 0x7b, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x7d, 0x12, 0x64, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1e, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x67, + 0x0a, 0x09, 0x53, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1e, 0x2e, 0x68, 0x65, + 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x65, + 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x1a, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 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 = []any{ - (*CreateUserRequest)(nil), // 0: headscale.v1.CreateUserRequest - (*RenameUserRequest)(nil), // 1: headscale.v1.RenameUserRequest - (*DeleteUserRequest)(nil), // 2: headscale.v1.DeleteUserRequest - (*ListUsersRequest)(nil), // 3: headscale.v1.ListUsersRequest - (*CreatePreAuthKeyRequest)(nil), // 4: headscale.v1.CreatePreAuthKeyRequest - (*ExpirePreAuthKeyRequest)(nil), // 5: headscale.v1.ExpirePreAuthKeyRequest - (*ListPreAuthKeysRequest)(nil), // 6: headscale.v1.ListPreAuthKeysRequest - (*DebugCreateNodeRequest)(nil), // 7: headscale.v1.DebugCreateNodeRequest - (*GetNodeRequest)(nil), // 8: headscale.v1.GetNodeRequest - (*SetTagsRequest)(nil), // 9: headscale.v1.SetTagsRequest - (*RegisterNodeRequest)(nil), // 10: headscale.v1.RegisterNodeRequest - (*DeleteNodeRequest)(nil), // 11: headscale.v1.DeleteNodeRequest - (*ExpireNodeRequest)(nil), // 12: headscale.v1.ExpireNodeRequest - (*RenameNodeRequest)(nil), // 13: headscale.v1.RenameNodeRequest - (*ListNodesRequest)(nil), // 14: headscale.v1.ListNodesRequest - (*MoveNodeRequest)(nil), // 15: headscale.v1.MoveNodeRequest - (*BackfillNodeIPsRequest)(nil), // 16: headscale.v1.BackfillNodeIPsRequest - (*GetRoutesRequest)(nil), // 17: headscale.v1.GetRoutesRequest - (*EnableRouteRequest)(nil), // 18: headscale.v1.EnableRouteRequest - (*DisableRouteRequest)(nil), // 19: headscale.v1.DisableRouteRequest - (*GetNodeRoutesRequest)(nil), // 20: headscale.v1.GetNodeRoutesRequest - (*DeleteRouteRequest)(nil), // 21: headscale.v1.DeleteRouteRequest - (*CreateApiKeyRequest)(nil), // 22: headscale.v1.CreateApiKeyRequest - (*ExpireApiKeyRequest)(nil), // 23: headscale.v1.ExpireApiKeyRequest - (*ListApiKeysRequest)(nil), // 24: headscale.v1.ListApiKeysRequest - (*DeleteApiKeyRequest)(nil), // 25: headscale.v1.DeleteApiKeyRequest - (*GetPolicyRequest)(nil), // 26: headscale.v1.GetPolicyRequest - (*SetPolicyRequest)(nil), // 27: headscale.v1.SetPolicyRequest - (*CreateUserResponse)(nil), // 28: headscale.v1.CreateUserResponse - (*RenameUserResponse)(nil), // 29: headscale.v1.RenameUserResponse - (*DeleteUserResponse)(nil), // 30: headscale.v1.DeleteUserResponse - (*ListUsersResponse)(nil), // 31: headscale.v1.ListUsersResponse - (*CreatePreAuthKeyResponse)(nil), // 32: headscale.v1.CreatePreAuthKeyResponse - (*ExpirePreAuthKeyResponse)(nil), // 33: headscale.v1.ExpirePreAuthKeyResponse - (*ListPreAuthKeysResponse)(nil), // 34: headscale.v1.ListPreAuthKeysResponse - (*DebugCreateNodeResponse)(nil), // 35: headscale.v1.DebugCreateNodeResponse - (*GetNodeResponse)(nil), // 36: headscale.v1.GetNodeResponse - (*SetTagsResponse)(nil), // 37: headscale.v1.SetTagsResponse - (*RegisterNodeResponse)(nil), // 38: headscale.v1.RegisterNodeResponse - (*DeleteNodeResponse)(nil), // 39: headscale.v1.DeleteNodeResponse - (*ExpireNodeResponse)(nil), // 40: headscale.v1.ExpireNodeResponse - (*RenameNodeResponse)(nil), // 41: headscale.v1.RenameNodeResponse - (*ListNodesResponse)(nil), // 42: headscale.v1.ListNodesResponse - (*MoveNodeResponse)(nil), // 43: headscale.v1.MoveNodeResponse - (*BackfillNodeIPsResponse)(nil), // 44: headscale.v1.BackfillNodeIPsResponse - (*GetRoutesResponse)(nil), // 45: headscale.v1.GetRoutesResponse - (*EnableRouteResponse)(nil), // 46: headscale.v1.EnableRouteResponse - (*DisableRouteResponse)(nil), // 47: headscale.v1.DisableRouteResponse - (*GetNodeRoutesResponse)(nil), // 48: headscale.v1.GetNodeRoutesResponse - (*DeleteRouteResponse)(nil), // 49: headscale.v1.DeleteRouteResponse - (*CreateApiKeyResponse)(nil), // 50: headscale.v1.CreateApiKeyResponse - (*ExpireApiKeyResponse)(nil), // 51: headscale.v1.ExpireApiKeyResponse - (*ListApiKeysResponse)(nil), // 52: headscale.v1.ListApiKeysResponse - (*DeleteApiKeyResponse)(nil), // 53: headscale.v1.DeleteApiKeyResponse - (*GetPolicyResponse)(nil), // 54: headscale.v1.GetPolicyResponse - (*SetPolicyResponse)(nil), // 55: headscale.v1.SetPolicyResponse + (*CreateUserRequest)(nil), // 0: headscale.v1.CreateUserRequest + (*RenameUserRequest)(nil), // 1: headscale.v1.RenameUserRequest + (*DeleteUserRequest)(nil), // 2: headscale.v1.DeleteUserRequest + (*ListUsersRequest)(nil), // 3: headscale.v1.ListUsersRequest + (*CreatePreAuthKeyRequest)(nil), // 4: headscale.v1.CreatePreAuthKeyRequest + (*ExpirePreAuthKeyRequest)(nil), // 5: headscale.v1.ExpirePreAuthKeyRequest + (*ListPreAuthKeysRequest)(nil), // 6: headscale.v1.ListPreAuthKeysRequest + (*DebugCreateNodeRequest)(nil), // 7: headscale.v1.DebugCreateNodeRequest + (*GetNodeRequest)(nil), // 8: headscale.v1.GetNodeRequest + (*SetTagsRequest)(nil), // 9: headscale.v1.SetTagsRequest + (*SetApprovedRoutesRequest)(nil), // 10: headscale.v1.SetApprovedRoutesRequest + (*RegisterNodeRequest)(nil), // 11: headscale.v1.RegisterNodeRequest + (*DeleteNodeRequest)(nil), // 12: headscale.v1.DeleteNodeRequest + (*ExpireNodeRequest)(nil), // 13: headscale.v1.ExpireNodeRequest + (*RenameNodeRequest)(nil), // 14: headscale.v1.RenameNodeRequest + (*ListNodesRequest)(nil), // 15: headscale.v1.ListNodesRequest + (*MoveNodeRequest)(nil), // 16: headscale.v1.MoveNodeRequest + (*BackfillNodeIPsRequest)(nil), // 17: headscale.v1.BackfillNodeIPsRequest + (*CreateApiKeyRequest)(nil), // 18: headscale.v1.CreateApiKeyRequest + (*ExpireApiKeyRequest)(nil), // 19: headscale.v1.ExpireApiKeyRequest + (*ListApiKeysRequest)(nil), // 20: headscale.v1.ListApiKeysRequest + (*DeleteApiKeyRequest)(nil), // 21: headscale.v1.DeleteApiKeyRequest + (*GetPolicyRequest)(nil), // 22: headscale.v1.GetPolicyRequest + (*SetPolicyRequest)(nil), // 23: headscale.v1.SetPolicyRequest + (*CreateUserResponse)(nil), // 24: headscale.v1.CreateUserResponse + (*RenameUserResponse)(nil), // 25: headscale.v1.RenameUserResponse + (*DeleteUserResponse)(nil), // 26: headscale.v1.DeleteUserResponse + (*ListUsersResponse)(nil), // 27: headscale.v1.ListUsersResponse + (*CreatePreAuthKeyResponse)(nil), // 28: headscale.v1.CreatePreAuthKeyResponse + (*ExpirePreAuthKeyResponse)(nil), // 29: headscale.v1.ExpirePreAuthKeyResponse + (*ListPreAuthKeysResponse)(nil), // 30: headscale.v1.ListPreAuthKeysResponse + (*DebugCreateNodeResponse)(nil), // 31: headscale.v1.DebugCreateNodeResponse + (*GetNodeResponse)(nil), // 32: headscale.v1.GetNodeResponse + (*SetTagsResponse)(nil), // 33: headscale.v1.SetTagsResponse + (*SetApprovedRoutesResponse)(nil), // 34: headscale.v1.SetApprovedRoutesResponse + (*RegisterNodeResponse)(nil), // 35: headscale.v1.RegisterNodeResponse + (*DeleteNodeResponse)(nil), // 36: headscale.v1.DeleteNodeResponse + (*ExpireNodeResponse)(nil), // 37: headscale.v1.ExpireNodeResponse + (*RenameNodeResponse)(nil), // 38: headscale.v1.RenameNodeResponse + (*ListNodesResponse)(nil), // 39: headscale.v1.ListNodesResponse + (*MoveNodeResponse)(nil), // 40: headscale.v1.MoveNodeResponse + (*BackfillNodeIPsResponse)(nil), // 41: headscale.v1.BackfillNodeIPsResponse + (*CreateApiKeyResponse)(nil), // 42: headscale.v1.CreateApiKeyResponse + (*ExpireApiKeyResponse)(nil), // 43: headscale.v1.ExpireApiKeyResponse + (*ListApiKeysResponse)(nil), // 44: headscale.v1.ListApiKeysResponse + (*DeleteApiKeyResponse)(nil), // 45: headscale.v1.DeleteApiKeyResponse + (*GetPolicyResponse)(nil), // 46: headscale.v1.GetPolicyResponse + (*SetPolicyResponse)(nil), // 47: headscale.v1.SetPolicyResponse } var file_headscale_v1_headscale_proto_depIdxs = []int32{ 0, // 0: headscale.v1.HeadscaleService.CreateUser:input_type -> headscale.v1.CreateUserRequest @@ -319,54 +282,46 @@ var file_headscale_v1_headscale_proto_depIdxs = []int32{ 7, // 7: headscale.v1.HeadscaleService.DebugCreateNode:input_type -> headscale.v1.DebugCreateNodeRequest 8, // 8: headscale.v1.HeadscaleService.GetNode:input_type -> headscale.v1.GetNodeRequest 9, // 9: headscale.v1.HeadscaleService.SetTags:input_type -> headscale.v1.SetTagsRequest - 10, // 10: headscale.v1.HeadscaleService.RegisterNode:input_type -> headscale.v1.RegisterNodeRequest - 11, // 11: headscale.v1.HeadscaleService.DeleteNode:input_type -> headscale.v1.DeleteNodeRequest - 12, // 12: headscale.v1.HeadscaleService.ExpireNode:input_type -> headscale.v1.ExpireNodeRequest - 13, // 13: headscale.v1.HeadscaleService.RenameNode:input_type -> headscale.v1.RenameNodeRequest - 14, // 14: headscale.v1.HeadscaleService.ListNodes:input_type -> headscale.v1.ListNodesRequest - 15, // 15: headscale.v1.HeadscaleService.MoveNode:input_type -> headscale.v1.MoveNodeRequest - 16, // 16: headscale.v1.HeadscaleService.BackfillNodeIPs:input_type -> headscale.v1.BackfillNodeIPsRequest - 17, // 17: headscale.v1.HeadscaleService.GetRoutes:input_type -> headscale.v1.GetRoutesRequest - 18, // 18: headscale.v1.HeadscaleService.EnableRoute:input_type -> headscale.v1.EnableRouteRequest - 19, // 19: headscale.v1.HeadscaleService.DisableRoute:input_type -> headscale.v1.DisableRouteRequest - 20, // 20: headscale.v1.HeadscaleService.GetNodeRoutes:input_type -> headscale.v1.GetNodeRoutesRequest - 21, // 21: headscale.v1.HeadscaleService.DeleteRoute:input_type -> headscale.v1.DeleteRouteRequest - 22, // 22: headscale.v1.HeadscaleService.CreateApiKey:input_type -> headscale.v1.CreateApiKeyRequest - 23, // 23: headscale.v1.HeadscaleService.ExpireApiKey:input_type -> headscale.v1.ExpireApiKeyRequest - 24, // 24: headscale.v1.HeadscaleService.ListApiKeys:input_type -> headscale.v1.ListApiKeysRequest - 25, // 25: headscale.v1.HeadscaleService.DeleteApiKey:input_type -> headscale.v1.DeleteApiKeyRequest - 26, // 26: headscale.v1.HeadscaleService.GetPolicy:input_type -> headscale.v1.GetPolicyRequest - 27, // 27: headscale.v1.HeadscaleService.SetPolicy:input_type -> headscale.v1.SetPolicyRequest - 28, // 28: headscale.v1.HeadscaleService.CreateUser:output_type -> headscale.v1.CreateUserResponse - 29, // 29: headscale.v1.HeadscaleService.RenameUser:output_type -> headscale.v1.RenameUserResponse - 30, // 30: headscale.v1.HeadscaleService.DeleteUser:output_type -> headscale.v1.DeleteUserResponse - 31, // 31: headscale.v1.HeadscaleService.ListUsers:output_type -> headscale.v1.ListUsersResponse - 32, // 32: headscale.v1.HeadscaleService.CreatePreAuthKey:output_type -> headscale.v1.CreatePreAuthKeyResponse - 33, // 33: headscale.v1.HeadscaleService.ExpirePreAuthKey:output_type -> headscale.v1.ExpirePreAuthKeyResponse - 34, // 34: headscale.v1.HeadscaleService.ListPreAuthKeys:output_type -> headscale.v1.ListPreAuthKeysResponse - 35, // 35: headscale.v1.HeadscaleService.DebugCreateNode:output_type -> headscale.v1.DebugCreateNodeResponse - 36, // 36: headscale.v1.HeadscaleService.GetNode:output_type -> headscale.v1.GetNodeResponse - 37, // 37: headscale.v1.HeadscaleService.SetTags:output_type -> headscale.v1.SetTagsResponse - 38, // 38: headscale.v1.HeadscaleService.RegisterNode:output_type -> headscale.v1.RegisterNodeResponse - 39, // 39: headscale.v1.HeadscaleService.DeleteNode:output_type -> headscale.v1.DeleteNodeResponse - 40, // 40: headscale.v1.HeadscaleService.ExpireNode:output_type -> headscale.v1.ExpireNodeResponse - 41, // 41: headscale.v1.HeadscaleService.RenameNode:output_type -> headscale.v1.RenameNodeResponse - 42, // 42: headscale.v1.HeadscaleService.ListNodes:output_type -> headscale.v1.ListNodesResponse - 43, // 43: headscale.v1.HeadscaleService.MoveNode:output_type -> headscale.v1.MoveNodeResponse - 44, // 44: headscale.v1.HeadscaleService.BackfillNodeIPs:output_type -> headscale.v1.BackfillNodeIPsResponse - 45, // 45: headscale.v1.HeadscaleService.GetRoutes:output_type -> headscale.v1.GetRoutesResponse - 46, // 46: headscale.v1.HeadscaleService.EnableRoute:output_type -> headscale.v1.EnableRouteResponse - 47, // 47: headscale.v1.HeadscaleService.DisableRoute:output_type -> headscale.v1.DisableRouteResponse - 48, // 48: headscale.v1.HeadscaleService.GetNodeRoutes:output_type -> headscale.v1.GetNodeRoutesResponse - 49, // 49: headscale.v1.HeadscaleService.DeleteRoute:output_type -> headscale.v1.DeleteRouteResponse - 50, // 50: headscale.v1.HeadscaleService.CreateApiKey:output_type -> headscale.v1.CreateApiKeyResponse - 51, // 51: headscale.v1.HeadscaleService.ExpireApiKey:output_type -> headscale.v1.ExpireApiKeyResponse - 52, // 52: headscale.v1.HeadscaleService.ListApiKeys:output_type -> headscale.v1.ListApiKeysResponse - 53, // 53: headscale.v1.HeadscaleService.DeleteApiKey:output_type -> headscale.v1.DeleteApiKeyResponse - 54, // 54: headscale.v1.HeadscaleService.GetPolicy:output_type -> headscale.v1.GetPolicyResponse - 55, // 55: headscale.v1.HeadscaleService.SetPolicy:output_type -> headscale.v1.SetPolicyResponse - 28, // [28:56] is the sub-list for method output_type - 0, // [0:28] is the sub-list for method input_type + 10, // 10: headscale.v1.HeadscaleService.SetApprovedRoutes:input_type -> headscale.v1.SetApprovedRoutesRequest + 11, // 11: headscale.v1.HeadscaleService.RegisterNode:input_type -> headscale.v1.RegisterNodeRequest + 12, // 12: headscale.v1.HeadscaleService.DeleteNode:input_type -> headscale.v1.DeleteNodeRequest + 13, // 13: headscale.v1.HeadscaleService.ExpireNode:input_type -> headscale.v1.ExpireNodeRequest + 14, // 14: headscale.v1.HeadscaleService.RenameNode:input_type -> headscale.v1.RenameNodeRequest + 15, // 15: headscale.v1.HeadscaleService.ListNodes:input_type -> headscale.v1.ListNodesRequest + 16, // 16: headscale.v1.HeadscaleService.MoveNode:input_type -> headscale.v1.MoveNodeRequest + 17, // 17: headscale.v1.HeadscaleService.BackfillNodeIPs:input_type -> headscale.v1.BackfillNodeIPsRequest + 18, // 18: headscale.v1.HeadscaleService.CreateApiKey:input_type -> headscale.v1.CreateApiKeyRequest + 19, // 19: headscale.v1.HeadscaleService.ExpireApiKey:input_type -> headscale.v1.ExpireApiKeyRequest + 20, // 20: headscale.v1.HeadscaleService.ListApiKeys:input_type -> headscale.v1.ListApiKeysRequest + 21, // 21: headscale.v1.HeadscaleService.DeleteApiKey:input_type -> headscale.v1.DeleteApiKeyRequest + 22, // 22: headscale.v1.HeadscaleService.GetPolicy:input_type -> headscale.v1.GetPolicyRequest + 23, // 23: headscale.v1.HeadscaleService.SetPolicy:input_type -> headscale.v1.SetPolicyRequest + 24, // 24: headscale.v1.HeadscaleService.CreateUser:output_type -> headscale.v1.CreateUserResponse + 25, // 25: headscale.v1.HeadscaleService.RenameUser:output_type -> headscale.v1.RenameUserResponse + 26, // 26: headscale.v1.HeadscaleService.DeleteUser:output_type -> headscale.v1.DeleteUserResponse + 27, // 27: headscale.v1.HeadscaleService.ListUsers:output_type -> headscale.v1.ListUsersResponse + 28, // 28: headscale.v1.HeadscaleService.CreatePreAuthKey:output_type -> headscale.v1.CreatePreAuthKeyResponse + 29, // 29: headscale.v1.HeadscaleService.ExpirePreAuthKey:output_type -> headscale.v1.ExpirePreAuthKeyResponse + 30, // 30: headscale.v1.HeadscaleService.ListPreAuthKeys:output_type -> headscale.v1.ListPreAuthKeysResponse + 31, // 31: headscale.v1.HeadscaleService.DebugCreateNode:output_type -> headscale.v1.DebugCreateNodeResponse + 32, // 32: headscale.v1.HeadscaleService.GetNode:output_type -> headscale.v1.GetNodeResponse + 33, // 33: headscale.v1.HeadscaleService.SetTags:output_type -> headscale.v1.SetTagsResponse + 34, // 34: headscale.v1.HeadscaleService.SetApprovedRoutes:output_type -> headscale.v1.SetApprovedRoutesResponse + 35, // 35: headscale.v1.HeadscaleService.RegisterNode:output_type -> headscale.v1.RegisterNodeResponse + 36, // 36: headscale.v1.HeadscaleService.DeleteNode:output_type -> headscale.v1.DeleteNodeResponse + 37, // 37: headscale.v1.HeadscaleService.ExpireNode:output_type -> headscale.v1.ExpireNodeResponse + 38, // 38: headscale.v1.HeadscaleService.RenameNode:output_type -> headscale.v1.RenameNodeResponse + 39, // 39: headscale.v1.HeadscaleService.ListNodes:output_type -> headscale.v1.ListNodesResponse + 40, // 40: headscale.v1.HeadscaleService.MoveNode:output_type -> headscale.v1.MoveNodeResponse + 41, // 41: headscale.v1.HeadscaleService.BackfillNodeIPs:output_type -> headscale.v1.BackfillNodeIPsResponse + 42, // 42: headscale.v1.HeadscaleService.CreateApiKey:output_type -> headscale.v1.CreateApiKeyResponse + 43, // 43: headscale.v1.HeadscaleService.ExpireApiKey:output_type -> headscale.v1.ExpireApiKeyResponse + 44, // 44: headscale.v1.HeadscaleService.ListApiKeys:output_type -> headscale.v1.ListApiKeysResponse + 45, // 45: headscale.v1.HeadscaleService.DeleteApiKey:output_type -> headscale.v1.DeleteApiKeyResponse + 46, // 46: headscale.v1.HeadscaleService.GetPolicy:output_type -> headscale.v1.GetPolicyResponse + 47, // 47: headscale.v1.HeadscaleService.SetPolicy:output_type -> headscale.v1.SetPolicyResponse + 24, // [24:48] is the sub-list for method output_type + 0, // [0:24] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name @@ -380,14 +335,13 @@ func file_headscale_v1_headscale_proto_init() { file_headscale_v1_user_proto_init() file_headscale_v1_preauthkey_proto_init() file_headscale_v1_node_proto_init() - file_headscale_v1_routes_proto_init() file_headscale_v1_apikey_proto_init() file_headscale_v1_policy_proto_init() type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_headscale_v1_headscale_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_headscale_v1_headscale_proto_rawDesc), len(file_headscale_v1_headscale_proto_rawDesc)), NumEnums: 0, NumMessages: 0, NumExtensions: 0, @@ -397,7 +351,6 @@ func file_headscale_v1_headscale_proto_init() { DependencyIndexes: file_headscale_v1_headscale_proto_depIdxs, }.Build() File_headscale_v1_headscale_proto = out.File - file_headscale_v1_headscale_proto_rawDesc = nil file_headscale_v1_headscale_proto_goTypes = nil file_headscale_v1_headscale_proto_depIdxs = nil } diff --git a/gen/go/headscale/v1/headscale.pb.gw.go b/gen/go/headscale/v1/headscale.pb.gw.go index 2d68043d..2e1cc480 100644 --- a/gen/go/headscale/v1/headscale.pb.gw.go +++ b/gen/go/headscale/v1/headscale.pb.gw.go @@ -361,6 +361,48 @@ func local_request_HeadscaleService_SetTags_0(ctx context.Context, marshaler run return msg, metadata, err } +func request_HeadscaleService_SetApprovedRoutes_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq SetApprovedRoutesRequest + metadata runtime.ServerMetadata + err error + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + val, ok := pathParams["node_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node_id") + } + protoReq.NodeId, err = runtime.Uint64(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node_id", err) + } + msg, err := client.SetApprovedRoutes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_HeadscaleService_SetApprovedRoutes_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq SetApprovedRoutesRequest + metadata runtime.ServerMetadata + err error + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + val, ok := pathParams["node_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node_id") + } + protoReq.NodeId, err = runtime.Uint64(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node_id", err) + } + msg, err := server.SetApprovedRoutes(ctx, &protoReq) + return msg, metadata, err +} + var filter_HeadscaleService_RegisterNode_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} func request_HeadscaleService_RegisterNode_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -623,168 +665,6 @@ func local_request_HeadscaleService_BackfillNodeIPs_0(ctx context.Context, marsh return msg, metadata, err } -func request_HeadscaleService_GetRoutes_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq GetRoutesRequest - metadata runtime.ServerMetadata - ) - msg, err := client.GetRoutes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err -} - -func local_request_HeadscaleService_GetRoutes_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq GetRoutesRequest - metadata runtime.ServerMetadata - ) - msg, err := server.GetRoutes(ctx, &protoReq) - return msg, metadata, err -} - -func request_HeadscaleService_EnableRoute_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq EnableRouteRequest - metadata runtime.ServerMetadata - err error - ) - val, ok := pathParams["route_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "route_id") - } - protoReq.RouteId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "route_id", err) - } - msg, err := client.EnableRoute(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err -} - -func local_request_HeadscaleService_EnableRoute_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq EnableRouteRequest - metadata runtime.ServerMetadata - err error - ) - val, ok := pathParams["route_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "route_id") - } - protoReq.RouteId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "route_id", err) - } - msg, err := server.EnableRoute(ctx, &protoReq) - return msg, metadata, err -} - -func request_HeadscaleService_DisableRoute_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq DisableRouteRequest - metadata runtime.ServerMetadata - err error - ) - val, ok := pathParams["route_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "route_id") - } - protoReq.RouteId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "route_id", err) - } - msg, err := client.DisableRoute(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err -} - -func local_request_HeadscaleService_DisableRoute_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq DisableRouteRequest - metadata runtime.ServerMetadata - err error - ) - val, ok := pathParams["route_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "route_id") - } - protoReq.RouteId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "route_id", err) - } - msg, err := server.DisableRoute(ctx, &protoReq) - return msg, metadata, err -} - -func request_HeadscaleService_GetNodeRoutes_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq GetNodeRoutesRequest - metadata runtime.ServerMetadata - err error - ) - val, ok := pathParams["node_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node_id") - } - protoReq.NodeId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node_id", err) - } - msg, err := client.GetNodeRoutes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err -} - -func local_request_HeadscaleService_GetNodeRoutes_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq GetNodeRoutesRequest - metadata runtime.ServerMetadata - err error - ) - val, ok := pathParams["node_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node_id") - } - protoReq.NodeId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node_id", err) - } - msg, err := server.GetNodeRoutes(ctx, &protoReq) - return msg, metadata, err -} - -func request_HeadscaleService_DeleteRoute_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq DeleteRouteRequest - metadata runtime.ServerMetadata - err error - ) - val, ok := pathParams["route_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "route_id") - } - protoReq.RouteId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "route_id", err) - } - msg, err := client.DeleteRoute(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err -} - -func local_request_HeadscaleService_DeleteRoute_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq DeleteRouteRequest - metadata runtime.ServerMetadata - err error - ) - val, ok := pathParams["route_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "route_id") - } - protoReq.RouteId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "route_id", err) - } - msg, err := server.DeleteRoute(ctx, &protoReq) - return msg, metadata, err -} - func request_HeadscaleService_CreateApiKey_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq CreateApiKeyRequest @@ -1135,6 +1015,26 @@ func RegisterHeadscaleServiceHandlerServer(ctx context.Context, mux *runtime.Ser } forward_HeadscaleService_SetTags_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_HeadscaleService_SetApprovedRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/SetApprovedRoutes", runtime.WithHTTPPathPattern("/api/v1/node/{node_id}/approve_routes")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_HeadscaleService_SetApprovedRoutes_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_HeadscaleService_SetApprovedRoutes_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_HeadscaleService_RegisterNode_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1275,106 +1175,6 @@ func RegisterHeadscaleServiceHandlerServer(ctx context.Context, mux *runtime.Ser } forward_HeadscaleService_BackfillNodeIPs_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodGet, pattern_HeadscaleService_GetRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/GetRoutes", runtime.WithHTTPPathPattern("/api/v1/routes")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_HeadscaleService_GetRoutes_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_HeadscaleService_GetRoutes_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodPost, pattern_HeadscaleService_EnableRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/EnableRoute", runtime.WithHTTPPathPattern("/api/v1/routes/{route_id}/enable")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_HeadscaleService_EnableRoute_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_HeadscaleService_EnableRoute_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodPost, pattern_HeadscaleService_DisableRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/DisableRoute", runtime.WithHTTPPathPattern("/api/v1/routes/{route_id}/disable")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_HeadscaleService_DisableRoute_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_HeadscaleService_DisableRoute_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodGet, pattern_HeadscaleService_GetNodeRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/GetNodeRoutes", runtime.WithHTTPPathPattern("/api/v1/node/{node_id}/routes")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_HeadscaleService_GetNodeRoutes_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_HeadscaleService_GetNodeRoutes_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodDelete, pattern_HeadscaleService_DeleteRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/DeleteRoute", runtime.WithHTTPPathPattern("/api/v1/routes/{route_id}")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_HeadscaleService_DeleteRoute_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_HeadscaleService_DeleteRoute_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) mux.Handle(http.MethodPost, pattern_HeadscaleService_CreateApiKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1705,6 +1505,23 @@ func RegisterHeadscaleServiceHandlerClient(ctx context.Context, mux *runtime.Ser } forward_HeadscaleService_SetTags_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_HeadscaleService_SetApprovedRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/SetApprovedRoutes", runtime.WithHTTPPathPattern("/api/v1/node/{node_id}/approve_routes")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_HeadscaleService_SetApprovedRoutes_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_HeadscaleService_SetApprovedRoutes_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_HeadscaleService_RegisterNode_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1824,91 +1641,6 @@ func RegisterHeadscaleServiceHandlerClient(ctx context.Context, mux *runtime.Ser } forward_HeadscaleService_BackfillNodeIPs_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodGet, pattern_HeadscaleService_GetRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/GetRoutes", runtime.WithHTTPPathPattern("/api/v1/routes")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_HeadscaleService_GetRoutes_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_HeadscaleService_GetRoutes_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodPost, pattern_HeadscaleService_EnableRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/EnableRoute", runtime.WithHTTPPathPattern("/api/v1/routes/{route_id}/enable")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_HeadscaleService_EnableRoute_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_HeadscaleService_EnableRoute_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodPost, pattern_HeadscaleService_DisableRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/DisableRoute", runtime.WithHTTPPathPattern("/api/v1/routes/{route_id}/disable")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_HeadscaleService_DisableRoute_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_HeadscaleService_DisableRoute_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodGet, pattern_HeadscaleService_GetNodeRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/GetNodeRoutes", runtime.WithHTTPPathPattern("/api/v1/node/{node_id}/routes")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_HeadscaleService_GetNodeRoutes_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_HeadscaleService_GetNodeRoutes_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodDelete, pattern_HeadscaleService_DeleteRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/DeleteRoute", runtime.WithHTTPPathPattern("/api/v1/routes/{route_id}")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_HeadscaleService_DeleteRoute_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_HeadscaleService_DeleteRoute_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) mux.Handle(http.MethodPost, pattern_HeadscaleService_CreateApiKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2015,63 +1747,55 @@ func RegisterHeadscaleServiceHandlerClient(ctx context.Context, mux *runtime.Ser } var ( - pattern_HeadscaleService_CreateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "user"}, "")) - pattern_HeadscaleService_RenameUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"api", "v1", "user", "old_id", "rename", "new_name"}, "")) - pattern_HeadscaleService_DeleteUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "user", "id"}, "")) - pattern_HeadscaleService_ListUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "user"}, "")) - pattern_HeadscaleService_CreatePreAuthKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "preauthkey"}, "")) - pattern_HeadscaleService_ExpirePreAuthKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "preauthkey", "expire"}, "")) - pattern_HeadscaleService_ListPreAuthKeys_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "preauthkey"}, "")) - pattern_HeadscaleService_DebugCreateNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "debug", "node"}, "")) - pattern_HeadscaleService_GetNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "node", "node_id"}, "")) - pattern_HeadscaleService_SetTags_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "node", "node_id", "tags"}, "")) - pattern_HeadscaleService_RegisterNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "node", "register"}, "")) - pattern_HeadscaleService_DeleteNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "node", "node_id"}, "")) - pattern_HeadscaleService_ExpireNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "node", "node_id", "expire"}, "")) - pattern_HeadscaleService_RenameNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"api", "v1", "node", "node_id", "rename", "new_name"}, "")) - pattern_HeadscaleService_ListNodes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "node"}, "")) - pattern_HeadscaleService_MoveNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "node", "node_id", "user"}, "")) - pattern_HeadscaleService_BackfillNodeIPs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "node", "backfillips"}, "")) - pattern_HeadscaleService_GetRoutes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "routes"}, "")) - pattern_HeadscaleService_EnableRoute_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "routes", "route_id", "enable"}, "")) - pattern_HeadscaleService_DisableRoute_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "routes", "route_id", "disable"}, "")) - pattern_HeadscaleService_GetNodeRoutes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "node", "node_id", "routes"}, "")) - pattern_HeadscaleService_DeleteRoute_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "routes", "route_id"}, "")) - pattern_HeadscaleService_CreateApiKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "apikey"}, "")) - pattern_HeadscaleService_ExpireApiKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "apikey", "expire"}, "")) - pattern_HeadscaleService_ListApiKeys_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "apikey"}, "")) - pattern_HeadscaleService_DeleteApiKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "apikey", "prefix"}, "")) - pattern_HeadscaleService_GetPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "policy"}, "")) - pattern_HeadscaleService_SetPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "policy"}, "")) + pattern_HeadscaleService_CreateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "user"}, "")) + pattern_HeadscaleService_RenameUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"api", "v1", "user", "old_id", "rename", "new_name"}, "")) + pattern_HeadscaleService_DeleteUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "user", "id"}, "")) + pattern_HeadscaleService_ListUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "user"}, "")) + pattern_HeadscaleService_CreatePreAuthKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "preauthkey"}, "")) + pattern_HeadscaleService_ExpirePreAuthKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "preauthkey", "expire"}, "")) + pattern_HeadscaleService_ListPreAuthKeys_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "preauthkey"}, "")) + pattern_HeadscaleService_DebugCreateNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "debug", "node"}, "")) + pattern_HeadscaleService_GetNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "node", "node_id"}, "")) + pattern_HeadscaleService_SetTags_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "node", "node_id", "tags"}, "")) + pattern_HeadscaleService_SetApprovedRoutes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "node", "node_id", "approve_routes"}, "")) + pattern_HeadscaleService_RegisterNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "node", "register"}, "")) + pattern_HeadscaleService_DeleteNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "node", "node_id"}, "")) + pattern_HeadscaleService_ExpireNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "node", "node_id", "expire"}, "")) + pattern_HeadscaleService_RenameNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"api", "v1", "node", "node_id", "rename", "new_name"}, "")) + pattern_HeadscaleService_ListNodes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "node"}, "")) + pattern_HeadscaleService_MoveNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "node", "node_id", "user"}, "")) + pattern_HeadscaleService_BackfillNodeIPs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "node", "backfillips"}, "")) + pattern_HeadscaleService_CreateApiKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "apikey"}, "")) + pattern_HeadscaleService_ExpireApiKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "apikey", "expire"}, "")) + pattern_HeadscaleService_ListApiKeys_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "apikey"}, "")) + pattern_HeadscaleService_DeleteApiKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "apikey", "prefix"}, "")) + pattern_HeadscaleService_GetPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "policy"}, "")) + pattern_HeadscaleService_SetPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "policy"}, "")) ) var ( - forward_HeadscaleService_CreateUser_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_RenameUser_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_DeleteUser_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_ListUsers_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_CreatePreAuthKey_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_ExpirePreAuthKey_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_ListPreAuthKeys_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_DebugCreateNode_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_GetNode_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_SetTags_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_RegisterNode_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_DeleteNode_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_ExpireNode_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_RenameNode_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_ListNodes_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_MoveNode_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_BackfillNodeIPs_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_GetRoutes_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_EnableRoute_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_DisableRoute_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_GetNodeRoutes_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_DeleteRoute_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_CreateApiKey_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_ExpireApiKey_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_ListApiKeys_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_DeleteApiKey_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_GetPolicy_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_SetPolicy_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_CreateUser_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_RenameUser_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_DeleteUser_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_ListUsers_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_CreatePreAuthKey_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_ExpirePreAuthKey_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_ListPreAuthKeys_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_DebugCreateNode_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_GetNode_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_SetTags_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_SetApprovedRoutes_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_RegisterNode_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_DeleteNode_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_ExpireNode_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_RenameNode_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_ListNodes_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_MoveNode_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_BackfillNodeIPs_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_CreateApiKey_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_ExpireApiKey_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_ListApiKeys_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_DeleteApiKey_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_GetPolicy_0 = runtime.ForwardResponseMessage + forward_HeadscaleService_SetPolicy_0 = runtime.ForwardResponseMessage ) diff --git a/gen/go/headscale/v1/headscale_grpc.pb.go b/gen/go/headscale/v1/headscale_grpc.pb.go index ce9b107e..f6d6687a 100644 --- a/gen/go/headscale/v1/headscale_grpc.pb.go +++ b/gen/go/headscale/v1/headscale_grpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 +// - protoc-gen-go-grpc v1.5.1 // - protoc (unknown) // source: headscale/v1/headscale.proto @@ -15,38 +15,34 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( - HeadscaleService_CreateUser_FullMethodName = "/headscale.v1.HeadscaleService/CreateUser" - HeadscaleService_RenameUser_FullMethodName = "/headscale.v1.HeadscaleService/RenameUser" - HeadscaleService_DeleteUser_FullMethodName = "/headscale.v1.HeadscaleService/DeleteUser" - HeadscaleService_ListUsers_FullMethodName = "/headscale.v1.HeadscaleService/ListUsers" - HeadscaleService_CreatePreAuthKey_FullMethodName = "/headscale.v1.HeadscaleService/CreatePreAuthKey" - HeadscaleService_ExpirePreAuthKey_FullMethodName = "/headscale.v1.HeadscaleService/ExpirePreAuthKey" - HeadscaleService_ListPreAuthKeys_FullMethodName = "/headscale.v1.HeadscaleService/ListPreAuthKeys" - HeadscaleService_DebugCreateNode_FullMethodName = "/headscale.v1.HeadscaleService/DebugCreateNode" - HeadscaleService_GetNode_FullMethodName = "/headscale.v1.HeadscaleService/GetNode" - HeadscaleService_SetTags_FullMethodName = "/headscale.v1.HeadscaleService/SetTags" - HeadscaleService_RegisterNode_FullMethodName = "/headscale.v1.HeadscaleService/RegisterNode" - HeadscaleService_DeleteNode_FullMethodName = "/headscale.v1.HeadscaleService/DeleteNode" - HeadscaleService_ExpireNode_FullMethodName = "/headscale.v1.HeadscaleService/ExpireNode" - HeadscaleService_RenameNode_FullMethodName = "/headscale.v1.HeadscaleService/RenameNode" - HeadscaleService_ListNodes_FullMethodName = "/headscale.v1.HeadscaleService/ListNodes" - HeadscaleService_MoveNode_FullMethodName = "/headscale.v1.HeadscaleService/MoveNode" - HeadscaleService_BackfillNodeIPs_FullMethodName = "/headscale.v1.HeadscaleService/BackfillNodeIPs" - HeadscaleService_GetRoutes_FullMethodName = "/headscale.v1.HeadscaleService/GetRoutes" - HeadscaleService_EnableRoute_FullMethodName = "/headscale.v1.HeadscaleService/EnableRoute" - HeadscaleService_DisableRoute_FullMethodName = "/headscale.v1.HeadscaleService/DisableRoute" - HeadscaleService_GetNodeRoutes_FullMethodName = "/headscale.v1.HeadscaleService/GetNodeRoutes" - HeadscaleService_DeleteRoute_FullMethodName = "/headscale.v1.HeadscaleService/DeleteRoute" - HeadscaleService_CreateApiKey_FullMethodName = "/headscale.v1.HeadscaleService/CreateApiKey" - HeadscaleService_ExpireApiKey_FullMethodName = "/headscale.v1.HeadscaleService/ExpireApiKey" - HeadscaleService_ListApiKeys_FullMethodName = "/headscale.v1.HeadscaleService/ListApiKeys" - HeadscaleService_DeleteApiKey_FullMethodName = "/headscale.v1.HeadscaleService/DeleteApiKey" - HeadscaleService_GetPolicy_FullMethodName = "/headscale.v1.HeadscaleService/GetPolicy" - HeadscaleService_SetPolicy_FullMethodName = "/headscale.v1.HeadscaleService/SetPolicy" + HeadscaleService_CreateUser_FullMethodName = "/headscale.v1.HeadscaleService/CreateUser" + HeadscaleService_RenameUser_FullMethodName = "/headscale.v1.HeadscaleService/RenameUser" + HeadscaleService_DeleteUser_FullMethodName = "/headscale.v1.HeadscaleService/DeleteUser" + HeadscaleService_ListUsers_FullMethodName = "/headscale.v1.HeadscaleService/ListUsers" + HeadscaleService_CreatePreAuthKey_FullMethodName = "/headscale.v1.HeadscaleService/CreatePreAuthKey" + HeadscaleService_ExpirePreAuthKey_FullMethodName = "/headscale.v1.HeadscaleService/ExpirePreAuthKey" + HeadscaleService_ListPreAuthKeys_FullMethodName = "/headscale.v1.HeadscaleService/ListPreAuthKeys" + HeadscaleService_DebugCreateNode_FullMethodName = "/headscale.v1.HeadscaleService/DebugCreateNode" + HeadscaleService_GetNode_FullMethodName = "/headscale.v1.HeadscaleService/GetNode" + HeadscaleService_SetTags_FullMethodName = "/headscale.v1.HeadscaleService/SetTags" + HeadscaleService_SetApprovedRoutes_FullMethodName = "/headscale.v1.HeadscaleService/SetApprovedRoutes" + HeadscaleService_RegisterNode_FullMethodName = "/headscale.v1.HeadscaleService/RegisterNode" + HeadscaleService_DeleteNode_FullMethodName = "/headscale.v1.HeadscaleService/DeleteNode" + HeadscaleService_ExpireNode_FullMethodName = "/headscale.v1.HeadscaleService/ExpireNode" + HeadscaleService_RenameNode_FullMethodName = "/headscale.v1.HeadscaleService/RenameNode" + HeadscaleService_ListNodes_FullMethodName = "/headscale.v1.HeadscaleService/ListNodes" + HeadscaleService_MoveNode_FullMethodName = "/headscale.v1.HeadscaleService/MoveNode" + HeadscaleService_BackfillNodeIPs_FullMethodName = "/headscale.v1.HeadscaleService/BackfillNodeIPs" + HeadscaleService_CreateApiKey_FullMethodName = "/headscale.v1.HeadscaleService/CreateApiKey" + HeadscaleService_ExpireApiKey_FullMethodName = "/headscale.v1.HeadscaleService/ExpireApiKey" + HeadscaleService_ListApiKeys_FullMethodName = "/headscale.v1.HeadscaleService/ListApiKeys" + HeadscaleService_DeleteApiKey_FullMethodName = "/headscale.v1.HeadscaleService/DeleteApiKey" + HeadscaleService_GetPolicy_FullMethodName = "/headscale.v1.HeadscaleService/GetPolicy" + HeadscaleService_SetPolicy_FullMethodName = "/headscale.v1.HeadscaleService/SetPolicy" ) // HeadscaleServiceClient is the client API for HeadscaleService service. @@ -66,6 +62,7 @@ type HeadscaleServiceClient interface { DebugCreateNode(ctx context.Context, in *DebugCreateNodeRequest, opts ...grpc.CallOption) (*DebugCreateNodeResponse, error) GetNode(ctx context.Context, in *GetNodeRequest, opts ...grpc.CallOption) (*GetNodeResponse, error) SetTags(ctx context.Context, in *SetTagsRequest, opts ...grpc.CallOption) (*SetTagsResponse, error) + SetApprovedRoutes(ctx context.Context, in *SetApprovedRoutesRequest, opts ...grpc.CallOption) (*SetApprovedRoutesResponse, error) RegisterNode(ctx context.Context, in *RegisterNodeRequest, opts ...grpc.CallOption) (*RegisterNodeResponse, error) DeleteNode(ctx context.Context, in *DeleteNodeRequest, opts ...grpc.CallOption) (*DeleteNodeResponse, error) ExpireNode(ctx context.Context, in *ExpireNodeRequest, opts ...grpc.CallOption) (*ExpireNodeResponse, error) @@ -73,12 +70,6 @@ type HeadscaleServiceClient interface { ListNodes(ctx context.Context, in *ListNodesRequest, opts ...grpc.CallOption) (*ListNodesResponse, error) MoveNode(ctx context.Context, in *MoveNodeRequest, opts ...grpc.CallOption) (*MoveNodeResponse, error) BackfillNodeIPs(ctx context.Context, in *BackfillNodeIPsRequest, opts ...grpc.CallOption) (*BackfillNodeIPsResponse, error) - // --- Route start --- - GetRoutes(ctx context.Context, in *GetRoutesRequest, opts ...grpc.CallOption) (*GetRoutesResponse, error) - EnableRoute(ctx context.Context, in *EnableRouteRequest, opts ...grpc.CallOption) (*EnableRouteResponse, error) - DisableRoute(ctx context.Context, in *DisableRouteRequest, opts ...grpc.CallOption) (*DisableRouteResponse, error) - GetNodeRoutes(ctx context.Context, in *GetNodeRoutesRequest, opts ...grpc.CallOption) (*GetNodeRoutesResponse, error) - DeleteRoute(ctx context.Context, in *DeleteRouteRequest, opts ...grpc.CallOption) (*DeleteRouteResponse, error) // --- ApiKeys start --- CreateApiKey(ctx context.Context, in *CreateApiKeyRequest, opts ...grpc.CallOption) (*CreateApiKeyResponse, error) ExpireApiKey(ctx context.Context, in *ExpireApiKeyRequest, opts ...grpc.CallOption) (*ExpireApiKeyResponse, error) @@ -98,8 +89,9 @@ func NewHeadscaleServiceClient(cc grpc.ClientConnInterface) HeadscaleServiceClie } func (c *headscaleServiceClient) CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateUserResponse) - err := c.cc.Invoke(ctx, HeadscaleService_CreateUser_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_CreateUser_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -107,8 +99,9 @@ func (c *headscaleServiceClient) CreateUser(ctx context.Context, in *CreateUserR } func (c *headscaleServiceClient) RenameUser(ctx context.Context, in *RenameUserRequest, opts ...grpc.CallOption) (*RenameUserResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(RenameUserResponse) - err := c.cc.Invoke(ctx, HeadscaleService_RenameUser_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_RenameUser_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -116,8 +109,9 @@ func (c *headscaleServiceClient) RenameUser(ctx context.Context, in *RenameUserR } func (c *headscaleServiceClient) DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*DeleteUserResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeleteUserResponse) - err := c.cc.Invoke(ctx, HeadscaleService_DeleteUser_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_DeleteUser_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -125,8 +119,9 @@ func (c *headscaleServiceClient) DeleteUser(ctx context.Context, in *DeleteUserR } func (c *headscaleServiceClient) ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListUsersResponse) - err := c.cc.Invoke(ctx, HeadscaleService_ListUsers_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_ListUsers_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -134,8 +129,9 @@ func (c *headscaleServiceClient) ListUsers(ctx context.Context, in *ListUsersReq } func (c *headscaleServiceClient) CreatePreAuthKey(ctx context.Context, in *CreatePreAuthKeyRequest, opts ...grpc.CallOption) (*CreatePreAuthKeyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreatePreAuthKeyResponse) - err := c.cc.Invoke(ctx, HeadscaleService_CreatePreAuthKey_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_CreatePreAuthKey_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -143,8 +139,9 @@ func (c *headscaleServiceClient) CreatePreAuthKey(ctx context.Context, in *Creat } func (c *headscaleServiceClient) ExpirePreAuthKey(ctx context.Context, in *ExpirePreAuthKeyRequest, opts ...grpc.CallOption) (*ExpirePreAuthKeyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ExpirePreAuthKeyResponse) - err := c.cc.Invoke(ctx, HeadscaleService_ExpirePreAuthKey_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_ExpirePreAuthKey_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -152,8 +149,9 @@ func (c *headscaleServiceClient) ExpirePreAuthKey(ctx context.Context, in *Expir } func (c *headscaleServiceClient) ListPreAuthKeys(ctx context.Context, in *ListPreAuthKeysRequest, opts ...grpc.CallOption) (*ListPreAuthKeysResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListPreAuthKeysResponse) - err := c.cc.Invoke(ctx, HeadscaleService_ListPreAuthKeys_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_ListPreAuthKeys_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -161,8 +159,9 @@ func (c *headscaleServiceClient) ListPreAuthKeys(ctx context.Context, in *ListPr } func (c *headscaleServiceClient) DebugCreateNode(ctx context.Context, in *DebugCreateNodeRequest, opts ...grpc.CallOption) (*DebugCreateNodeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DebugCreateNodeResponse) - err := c.cc.Invoke(ctx, HeadscaleService_DebugCreateNode_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_DebugCreateNode_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -170,8 +169,9 @@ func (c *headscaleServiceClient) DebugCreateNode(ctx context.Context, in *DebugC } func (c *headscaleServiceClient) GetNode(ctx context.Context, in *GetNodeRequest, opts ...grpc.CallOption) (*GetNodeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetNodeResponse) - err := c.cc.Invoke(ctx, HeadscaleService_GetNode_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_GetNode_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -179,8 +179,19 @@ func (c *headscaleServiceClient) GetNode(ctx context.Context, in *GetNodeRequest } func (c *headscaleServiceClient) SetTags(ctx context.Context, in *SetTagsRequest, opts ...grpc.CallOption) (*SetTagsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(SetTagsResponse) - err := c.cc.Invoke(ctx, HeadscaleService_SetTags_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_SetTags_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *headscaleServiceClient) SetApprovedRoutes(ctx context.Context, in *SetApprovedRoutesRequest, opts ...grpc.CallOption) (*SetApprovedRoutesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetApprovedRoutesResponse) + err := c.cc.Invoke(ctx, HeadscaleService_SetApprovedRoutes_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -188,8 +199,9 @@ func (c *headscaleServiceClient) SetTags(ctx context.Context, in *SetTagsRequest } func (c *headscaleServiceClient) RegisterNode(ctx context.Context, in *RegisterNodeRequest, opts ...grpc.CallOption) (*RegisterNodeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(RegisterNodeResponse) - err := c.cc.Invoke(ctx, HeadscaleService_RegisterNode_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_RegisterNode_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -197,8 +209,9 @@ func (c *headscaleServiceClient) RegisterNode(ctx context.Context, in *RegisterN } func (c *headscaleServiceClient) DeleteNode(ctx context.Context, in *DeleteNodeRequest, opts ...grpc.CallOption) (*DeleteNodeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeleteNodeResponse) - err := c.cc.Invoke(ctx, HeadscaleService_DeleteNode_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_DeleteNode_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -206,8 +219,9 @@ func (c *headscaleServiceClient) DeleteNode(ctx context.Context, in *DeleteNodeR } func (c *headscaleServiceClient) ExpireNode(ctx context.Context, in *ExpireNodeRequest, opts ...grpc.CallOption) (*ExpireNodeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ExpireNodeResponse) - err := c.cc.Invoke(ctx, HeadscaleService_ExpireNode_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_ExpireNode_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -215,8 +229,9 @@ func (c *headscaleServiceClient) ExpireNode(ctx context.Context, in *ExpireNodeR } func (c *headscaleServiceClient) RenameNode(ctx context.Context, in *RenameNodeRequest, opts ...grpc.CallOption) (*RenameNodeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(RenameNodeResponse) - err := c.cc.Invoke(ctx, HeadscaleService_RenameNode_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_RenameNode_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -224,8 +239,9 @@ func (c *headscaleServiceClient) RenameNode(ctx context.Context, in *RenameNodeR } func (c *headscaleServiceClient) ListNodes(ctx context.Context, in *ListNodesRequest, opts ...grpc.CallOption) (*ListNodesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListNodesResponse) - err := c.cc.Invoke(ctx, HeadscaleService_ListNodes_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_ListNodes_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -233,8 +249,9 @@ func (c *headscaleServiceClient) ListNodes(ctx context.Context, in *ListNodesReq } func (c *headscaleServiceClient) MoveNode(ctx context.Context, in *MoveNodeRequest, opts ...grpc.CallOption) (*MoveNodeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(MoveNodeResponse) - err := c.cc.Invoke(ctx, HeadscaleService_MoveNode_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_MoveNode_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -242,53 +259,9 @@ func (c *headscaleServiceClient) MoveNode(ctx context.Context, in *MoveNodeReque } func (c *headscaleServiceClient) BackfillNodeIPs(ctx context.Context, in *BackfillNodeIPsRequest, opts ...grpc.CallOption) (*BackfillNodeIPsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(BackfillNodeIPsResponse) - err := c.cc.Invoke(ctx, HeadscaleService_BackfillNodeIPs_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *headscaleServiceClient) GetRoutes(ctx context.Context, in *GetRoutesRequest, opts ...grpc.CallOption) (*GetRoutesResponse, error) { - out := new(GetRoutesResponse) - err := c.cc.Invoke(ctx, HeadscaleService_GetRoutes_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *headscaleServiceClient) EnableRoute(ctx context.Context, in *EnableRouteRequest, opts ...grpc.CallOption) (*EnableRouteResponse, error) { - out := new(EnableRouteResponse) - err := c.cc.Invoke(ctx, HeadscaleService_EnableRoute_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *headscaleServiceClient) DisableRoute(ctx context.Context, in *DisableRouteRequest, opts ...grpc.CallOption) (*DisableRouteResponse, error) { - out := new(DisableRouteResponse) - err := c.cc.Invoke(ctx, HeadscaleService_DisableRoute_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *headscaleServiceClient) GetNodeRoutes(ctx context.Context, in *GetNodeRoutesRequest, opts ...grpc.CallOption) (*GetNodeRoutesResponse, error) { - out := new(GetNodeRoutesResponse) - err := c.cc.Invoke(ctx, HeadscaleService_GetNodeRoutes_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *headscaleServiceClient) DeleteRoute(ctx context.Context, in *DeleteRouteRequest, opts ...grpc.CallOption) (*DeleteRouteResponse, error) { - out := new(DeleteRouteResponse) - err := c.cc.Invoke(ctx, HeadscaleService_DeleteRoute_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_BackfillNodeIPs_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -296,8 +269,9 @@ func (c *headscaleServiceClient) DeleteRoute(ctx context.Context, in *DeleteRout } func (c *headscaleServiceClient) CreateApiKey(ctx context.Context, in *CreateApiKeyRequest, opts ...grpc.CallOption) (*CreateApiKeyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateApiKeyResponse) - err := c.cc.Invoke(ctx, HeadscaleService_CreateApiKey_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_CreateApiKey_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -305,8 +279,9 @@ func (c *headscaleServiceClient) CreateApiKey(ctx context.Context, in *CreateApi } func (c *headscaleServiceClient) ExpireApiKey(ctx context.Context, in *ExpireApiKeyRequest, opts ...grpc.CallOption) (*ExpireApiKeyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ExpireApiKeyResponse) - err := c.cc.Invoke(ctx, HeadscaleService_ExpireApiKey_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_ExpireApiKey_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -314,8 +289,9 @@ func (c *headscaleServiceClient) ExpireApiKey(ctx context.Context, in *ExpireApi } func (c *headscaleServiceClient) ListApiKeys(ctx context.Context, in *ListApiKeysRequest, opts ...grpc.CallOption) (*ListApiKeysResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListApiKeysResponse) - err := c.cc.Invoke(ctx, HeadscaleService_ListApiKeys_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_ListApiKeys_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -323,8 +299,9 @@ func (c *headscaleServiceClient) ListApiKeys(ctx context.Context, in *ListApiKey } func (c *headscaleServiceClient) DeleteApiKey(ctx context.Context, in *DeleteApiKeyRequest, opts ...grpc.CallOption) (*DeleteApiKeyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeleteApiKeyResponse) - err := c.cc.Invoke(ctx, HeadscaleService_DeleteApiKey_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_DeleteApiKey_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -332,8 +309,9 @@ func (c *headscaleServiceClient) DeleteApiKey(ctx context.Context, in *DeleteApi } func (c *headscaleServiceClient) GetPolicy(ctx context.Context, in *GetPolicyRequest, opts ...grpc.CallOption) (*GetPolicyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetPolicyResponse) - err := c.cc.Invoke(ctx, HeadscaleService_GetPolicy_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_GetPolicy_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -341,8 +319,9 @@ func (c *headscaleServiceClient) GetPolicy(ctx context.Context, in *GetPolicyReq } func (c *headscaleServiceClient) SetPolicy(ctx context.Context, in *SetPolicyRequest, opts ...grpc.CallOption) (*SetPolicyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(SetPolicyResponse) - err := c.cc.Invoke(ctx, HeadscaleService_SetPolicy_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, HeadscaleService_SetPolicy_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -351,7 +330,7 @@ func (c *headscaleServiceClient) SetPolicy(ctx context.Context, in *SetPolicyReq // HeadscaleServiceServer is the server API for HeadscaleService service. // All implementations must embed UnimplementedHeadscaleServiceServer -// for forward compatibility +// for forward compatibility. type HeadscaleServiceServer interface { // --- User start --- CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error) @@ -366,6 +345,7 @@ type HeadscaleServiceServer interface { DebugCreateNode(context.Context, *DebugCreateNodeRequest) (*DebugCreateNodeResponse, error) GetNode(context.Context, *GetNodeRequest) (*GetNodeResponse, error) SetTags(context.Context, *SetTagsRequest) (*SetTagsResponse, error) + SetApprovedRoutes(context.Context, *SetApprovedRoutesRequest) (*SetApprovedRoutesResponse, error) RegisterNode(context.Context, *RegisterNodeRequest) (*RegisterNodeResponse, error) DeleteNode(context.Context, *DeleteNodeRequest) (*DeleteNodeResponse, error) ExpireNode(context.Context, *ExpireNodeRequest) (*ExpireNodeResponse, error) @@ -373,12 +353,6 @@ type HeadscaleServiceServer interface { ListNodes(context.Context, *ListNodesRequest) (*ListNodesResponse, error) MoveNode(context.Context, *MoveNodeRequest) (*MoveNodeResponse, error) BackfillNodeIPs(context.Context, *BackfillNodeIPsRequest) (*BackfillNodeIPsResponse, error) - // --- Route start --- - GetRoutes(context.Context, *GetRoutesRequest) (*GetRoutesResponse, error) - EnableRoute(context.Context, *EnableRouteRequest) (*EnableRouteResponse, error) - DisableRoute(context.Context, *DisableRouteRequest) (*DisableRouteResponse, error) - GetNodeRoutes(context.Context, *GetNodeRoutesRequest) (*GetNodeRoutesResponse, error) - DeleteRoute(context.Context, *DeleteRouteRequest) (*DeleteRouteResponse, error) // --- ApiKeys start --- CreateApiKey(context.Context, *CreateApiKeyRequest) (*CreateApiKeyResponse, error) ExpireApiKey(context.Context, *ExpireApiKeyRequest) (*ExpireApiKeyResponse, error) @@ -390,9 +364,12 @@ type HeadscaleServiceServer interface { mustEmbedUnimplementedHeadscaleServiceServer() } -// UnimplementedHeadscaleServiceServer must be embedded to have forward compatible implementations. -type UnimplementedHeadscaleServiceServer struct { -} +// UnimplementedHeadscaleServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedHeadscaleServiceServer struct{} func (UnimplementedHeadscaleServiceServer) CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateUser not implemented") @@ -424,6 +401,9 @@ func (UnimplementedHeadscaleServiceServer) GetNode(context.Context, *GetNodeRequ func (UnimplementedHeadscaleServiceServer) SetTags(context.Context, *SetTagsRequest) (*SetTagsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SetTags not implemented") } +func (UnimplementedHeadscaleServiceServer) SetApprovedRoutes(context.Context, *SetApprovedRoutesRequest) (*SetApprovedRoutesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetApprovedRoutes not implemented") +} func (UnimplementedHeadscaleServiceServer) RegisterNode(context.Context, *RegisterNodeRequest) (*RegisterNodeResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RegisterNode not implemented") } @@ -445,21 +425,6 @@ func (UnimplementedHeadscaleServiceServer) MoveNode(context.Context, *MoveNodeRe func (UnimplementedHeadscaleServiceServer) BackfillNodeIPs(context.Context, *BackfillNodeIPsRequest) (*BackfillNodeIPsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method BackfillNodeIPs not implemented") } -func (UnimplementedHeadscaleServiceServer) GetRoutes(context.Context, *GetRoutesRequest) (*GetRoutesResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetRoutes not implemented") -} -func (UnimplementedHeadscaleServiceServer) EnableRoute(context.Context, *EnableRouteRequest) (*EnableRouteResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method EnableRoute not implemented") -} -func (UnimplementedHeadscaleServiceServer) DisableRoute(context.Context, *DisableRouteRequest) (*DisableRouteResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method DisableRoute not implemented") -} -func (UnimplementedHeadscaleServiceServer) GetNodeRoutes(context.Context, *GetNodeRoutesRequest) (*GetNodeRoutesResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetNodeRoutes not implemented") -} -func (UnimplementedHeadscaleServiceServer) DeleteRoute(context.Context, *DeleteRouteRequest) (*DeleteRouteResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method DeleteRoute not implemented") -} func (UnimplementedHeadscaleServiceServer) CreateApiKey(context.Context, *CreateApiKeyRequest) (*CreateApiKeyResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateApiKey not implemented") } @@ -479,6 +444,7 @@ func (UnimplementedHeadscaleServiceServer) SetPolicy(context.Context, *SetPolicy return nil, status.Errorf(codes.Unimplemented, "method SetPolicy not implemented") } func (UnimplementedHeadscaleServiceServer) mustEmbedUnimplementedHeadscaleServiceServer() {} +func (UnimplementedHeadscaleServiceServer) testEmbeddedByValue() {} // UnsafeHeadscaleServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to HeadscaleServiceServer will @@ -488,6 +454,13 @@ type UnsafeHeadscaleServiceServer interface { } func RegisterHeadscaleServiceServer(s grpc.ServiceRegistrar, srv HeadscaleServiceServer) { + // If the following call pancis, it indicates UnimplementedHeadscaleServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&HeadscaleService_ServiceDesc, srv) } @@ -671,6 +644,24 @@ func _HeadscaleService_SetTags_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _HeadscaleService_SetApprovedRoutes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetApprovedRoutesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HeadscaleServiceServer).SetApprovedRoutes(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HeadscaleService_SetApprovedRoutes_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HeadscaleServiceServer).SetApprovedRoutes(ctx, req.(*SetApprovedRoutesRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _HeadscaleService_RegisterNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(RegisterNodeRequest) if err := dec(in); err != nil { @@ -797,96 +788,6 @@ func _HeadscaleService_BackfillNodeIPs_Handler(srv interface{}, ctx context.Cont return interceptor(ctx, in, info, handler) } -func _HeadscaleService_GetRoutes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetRoutesRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(HeadscaleServiceServer).GetRoutes(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: HeadscaleService_GetRoutes_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HeadscaleServiceServer).GetRoutes(ctx, req.(*GetRoutesRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _HeadscaleService_EnableRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(EnableRouteRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(HeadscaleServiceServer).EnableRoute(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: HeadscaleService_EnableRoute_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HeadscaleServiceServer).EnableRoute(ctx, req.(*EnableRouteRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _HeadscaleService_DisableRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(DisableRouteRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(HeadscaleServiceServer).DisableRoute(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: HeadscaleService_DisableRoute_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HeadscaleServiceServer).DisableRoute(ctx, req.(*DisableRouteRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _HeadscaleService_GetNodeRoutes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetNodeRoutesRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(HeadscaleServiceServer).GetNodeRoutes(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: HeadscaleService_GetNodeRoutes_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HeadscaleServiceServer).GetNodeRoutes(ctx, req.(*GetNodeRoutesRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _HeadscaleService_DeleteRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(DeleteRouteRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(HeadscaleServiceServer).DeleteRoute(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: HeadscaleService_DeleteRoute_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HeadscaleServiceServer).DeleteRoute(ctx, req.(*DeleteRouteRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _HeadscaleService_CreateApiKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CreateApiKeyRequest) if err := dec(in); err != nil { @@ -1042,6 +943,10 @@ var HeadscaleService_ServiceDesc = grpc.ServiceDesc{ MethodName: "SetTags", Handler: _HeadscaleService_SetTags_Handler, }, + { + MethodName: "SetApprovedRoutes", + Handler: _HeadscaleService_SetApprovedRoutes_Handler, + }, { MethodName: "RegisterNode", Handler: _HeadscaleService_RegisterNode_Handler, @@ -1070,26 +975,6 @@ var HeadscaleService_ServiceDesc = grpc.ServiceDesc{ MethodName: "BackfillNodeIPs", Handler: _HeadscaleService_BackfillNodeIPs_Handler, }, - { - MethodName: "GetRoutes", - Handler: _HeadscaleService_GetRoutes_Handler, - }, - { - MethodName: "EnableRoute", - Handler: _HeadscaleService_EnableRoute_Handler, - }, - { - MethodName: "DisableRoute", - Handler: _HeadscaleService_DisableRoute_Handler, - }, - { - MethodName: "GetNodeRoutes", - Handler: _HeadscaleService_GetNodeRoutes_Handler, - }, - { - MethodName: "DeleteRoute", - Handler: _HeadscaleService_DeleteRoute_Handler, - }, { MethodName: "CreateApiKey", Handler: _HeadscaleService_CreateApiKey_Handler, diff --git a/gen/go/headscale/v1/node.pb.go b/gen/go/headscale/v1/node.pb.go index 074310e5..8649cbec 100644 --- a/gen/go/headscale/v1/node.pb.go +++ b/gen/go/headscale/v1/node.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: headscale/v1/node.proto @@ -12,6 +12,7 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -74,27 +75,29 @@ func (RegisterMethod) EnumDescriptor() ([]byte, []int) { } type Node struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - MachineKey string `protobuf:"bytes,2,opt,name=machine_key,json=machineKey,proto3" json:"machine_key,omitempty"` - NodeKey string `protobuf:"bytes,3,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` - DiscoKey string `protobuf:"bytes,4,opt,name=disco_key,json=discoKey,proto3" json:"disco_key,omitempty"` - IpAddresses []string `protobuf:"bytes,5,rep,name=ip_addresses,json=ipAddresses,proto3" json:"ip_addresses,omitempty"` - Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` - User *User `protobuf:"bytes,7,opt,name=user,proto3" json:"user,omitempty"` - LastSeen *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=last_seen,json=lastSeen,proto3" json:"last_seen,omitempty"` - Expiry *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=expiry,proto3" json:"expiry,omitempty"` - PreAuthKey *PreAuthKey `protobuf:"bytes,11,opt,name=pre_auth_key,json=preAuthKey,proto3" json:"pre_auth_key,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - RegisterMethod RegisterMethod `protobuf:"varint,13,opt,name=register_method,json=registerMethod,proto3,enum=headscale.v1.RegisterMethod" json:"register_method,omitempty"` - ForcedTags []string `protobuf:"bytes,18,rep,name=forced_tags,json=forcedTags,proto3" json:"forced_tags,omitempty"` - InvalidTags []string `protobuf:"bytes,19,rep,name=invalid_tags,json=invalidTags,proto3" json:"invalid_tags,omitempty"` - ValidTags []string `protobuf:"bytes,20,rep,name=valid_tags,json=validTags,proto3" json:"valid_tags,omitempty"` - GivenName string `protobuf:"bytes,21,opt,name=given_name,json=givenName,proto3" json:"given_name,omitempty"` - Online bool `protobuf:"varint,22,opt,name=online,proto3" json:"online,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + MachineKey string `protobuf:"bytes,2,opt,name=machine_key,json=machineKey,proto3" json:"machine_key,omitempty"` + NodeKey string `protobuf:"bytes,3,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` + DiscoKey string `protobuf:"bytes,4,opt,name=disco_key,json=discoKey,proto3" json:"disco_key,omitempty"` + IpAddresses []string `protobuf:"bytes,5,rep,name=ip_addresses,json=ipAddresses,proto3" json:"ip_addresses,omitempty"` + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + User *User `protobuf:"bytes,7,opt,name=user,proto3" json:"user,omitempty"` + LastSeen *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=last_seen,json=lastSeen,proto3" json:"last_seen,omitempty"` + Expiry *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=expiry,proto3" json:"expiry,omitempty"` + PreAuthKey *PreAuthKey `protobuf:"bytes,11,opt,name=pre_auth_key,json=preAuthKey,proto3" json:"pre_auth_key,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + RegisterMethod RegisterMethod `protobuf:"varint,13,opt,name=register_method,json=registerMethod,proto3,enum=headscale.v1.RegisterMethod" json:"register_method,omitempty"` + ForcedTags []string `protobuf:"bytes,18,rep,name=forced_tags,json=forcedTags,proto3" json:"forced_tags,omitempty"` + InvalidTags []string `protobuf:"bytes,19,rep,name=invalid_tags,json=invalidTags,proto3" json:"invalid_tags,omitempty"` + ValidTags []string `protobuf:"bytes,20,rep,name=valid_tags,json=validTags,proto3" json:"valid_tags,omitempty"` + GivenName string `protobuf:"bytes,21,opt,name=given_name,json=givenName,proto3" json:"given_name,omitempty"` + Online bool `protobuf:"varint,22,opt,name=online,proto3" json:"online,omitempty"` + ApprovedRoutes []string `protobuf:"bytes,23,rep,name=approved_routes,json=approvedRoutes,proto3" json:"approved_routes,omitempty"` + AvailableRoutes []string `protobuf:"bytes,24,rep,name=available_routes,json=availableRoutes,proto3" json:"available_routes,omitempty"` + SubnetRoutes []string `protobuf:"bytes,25,rep,name=subnet_routes,json=subnetRoutes,proto3" json:"subnet_routes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Node) Reset() { @@ -246,13 +249,33 @@ func (x *Node) GetOnline() bool { return false } -type RegisterNodeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields +func (x *Node) GetApprovedRoutes() []string { + if x != nil { + return x.ApprovedRoutes + } + return nil +} - User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` +func (x *Node) GetAvailableRoutes() []string { + if x != nil { + return x.AvailableRoutes + } + return nil +} + +func (x *Node) GetSubnetRoutes() []string { + if x != nil { + return x.SubnetRoutes + } + return nil +} + +type RegisterNodeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RegisterNodeRequest) Reset() { @@ -300,11 +323,10 @@ func (x *RegisterNodeRequest) GetKey() string { } type RegisterNodeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` unknownFields protoimpl.UnknownFields - - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RegisterNodeResponse) Reset() { @@ -345,11 +367,10 @@ func (x *RegisterNodeResponse) GetNode() *Node { } type GetNodeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` unknownFields protoimpl.UnknownFields - - NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetNodeRequest) Reset() { @@ -390,11 +411,10 @@ func (x *GetNodeRequest) GetNodeId() uint64 { } type GetNodeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` unknownFields protoimpl.UnknownFields - - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetNodeResponse) Reset() { @@ -435,12 +455,11 @@ func (x *GetNodeResponse) GetNode() *Node { } type SetTagsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + Tags []string `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty"` unknownFields protoimpl.UnknownFields - - NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` - Tags []string `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SetTagsRequest) Reset() { @@ -488,11 +507,10 @@ func (x *SetTagsRequest) GetTags() []string { } type SetTagsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` unknownFields protoimpl.UnknownFields - - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SetTagsResponse) Reset() { @@ -532,17 +550,112 @@ func (x *SetTagsResponse) GetNode() *Node { return nil } -type DeleteNodeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache +type SetApprovedRoutesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + Routes []string `protobuf:"bytes,2,rep,name=routes,proto3" json:"routes,omitempty"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} - NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` +func (x *SetApprovedRoutesRequest) Reset() { + *x = SetApprovedRoutesRequest{} + mi := &file_headscale_v1_node_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetApprovedRoutesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetApprovedRoutesRequest) ProtoMessage() {} + +func (x *SetApprovedRoutesRequest) ProtoReflect() protoreflect.Message { + mi := &file_headscale_v1_node_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetApprovedRoutesRequest.ProtoReflect.Descriptor instead. +func (*SetApprovedRoutesRequest) Descriptor() ([]byte, []int) { + return file_headscale_v1_node_proto_rawDescGZIP(), []int{7} +} + +func (x *SetApprovedRoutesRequest) GetNodeId() uint64 { + if x != nil { + return x.NodeId + } + return 0 +} + +func (x *SetApprovedRoutesRequest) GetRoutes() []string { + if x != nil { + return x.Routes + } + return nil +} + +type SetApprovedRoutesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetApprovedRoutesResponse) Reset() { + *x = SetApprovedRoutesResponse{} + mi := &file_headscale_v1_node_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetApprovedRoutesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetApprovedRoutesResponse) ProtoMessage() {} + +func (x *SetApprovedRoutesResponse) ProtoReflect() protoreflect.Message { + mi := &file_headscale_v1_node_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetApprovedRoutesResponse.ProtoReflect.Descriptor instead. +func (*SetApprovedRoutesResponse) Descriptor() ([]byte, []int) { + return file_headscale_v1_node_proto_rawDescGZIP(), []int{8} +} + +func (x *SetApprovedRoutesResponse) GetNode() *Node { + if x != nil { + return x.Node + } + return nil +} + +type DeleteNodeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DeleteNodeRequest) Reset() { *x = DeleteNodeRequest{} - mi := &file_headscale_v1_node_proto_msgTypes[7] + mi := &file_headscale_v1_node_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -554,7 +667,7 @@ func (x *DeleteNodeRequest) String() string { func (*DeleteNodeRequest) ProtoMessage() {} func (x *DeleteNodeRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[7] + mi := &file_headscale_v1_node_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -567,7 +680,7 @@ func (x *DeleteNodeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteNodeRequest.ProtoReflect.Descriptor instead. func (*DeleteNodeRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{7} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{9} } func (x *DeleteNodeRequest) GetNodeId() uint64 { @@ -578,14 +691,14 @@ func (x *DeleteNodeRequest) GetNodeId() uint64 { } type DeleteNodeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DeleteNodeResponse) Reset() { *x = DeleteNodeResponse{} - mi := &file_headscale_v1_node_proto_msgTypes[8] + mi := &file_headscale_v1_node_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -597,7 +710,7 @@ func (x *DeleteNodeResponse) String() string { func (*DeleteNodeResponse) ProtoMessage() {} func (x *DeleteNodeResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[8] + mi := &file_headscale_v1_node_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -610,20 +723,19 @@ func (x *DeleteNodeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteNodeResponse.ProtoReflect.Descriptor instead. func (*DeleteNodeResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{8} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{10} } type ExpireNodeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` unknownFields protoimpl.UnknownFields - - NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ExpireNodeRequest) Reset() { *x = ExpireNodeRequest{} - mi := &file_headscale_v1_node_proto_msgTypes[9] + mi := &file_headscale_v1_node_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -635,7 +747,7 @@ func (x *ExpireNodeRequest) String() string { func (*ExpireNodeRequest) ProtoMessage() {} func (x *ExpireNodeRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[9] + mi := &file_headscale_v1_node_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -648,7 +760,7 @@ func (x *ExpireNodeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExpireNodeRequest.ProtoReflect.Descriptor instead. func (*ExpireNodeRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{9} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{11} } func (x *ExpireNodeRequest) GetNodeId() uint64 { @@ -659,16 +771,15 @@ func (x *ExpireNodeRequest) GetNodeId() uint64 { } type ExpireNodeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` unknownFields protoimpl.UnknownFields - - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ExpireNodeResponse) Reset() { *x = ExpireNodeResponse{} - mi := &file_headscale_v1_node_proto_msgTypes[10] + mi := &file_headscale_v1_node_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -680,7 +791,7 @@ func (x *ExpireNodeResponse) String() string { func (*ExpireNodeResponse) ProtoMessage() {} func (x *ExpireNodeResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[10] + mi := &file_headscale_v1_node_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -693,7 +804,7 @@ func (x *ExpireNodeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ExpireNodeResponse.ProtoReflect.Descriptor instead. func (*ExpireNodeResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{10} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{12} } func (x *ExpireNodeResponse) GetNode() *Node { @@ -704,17 +815,16 @@ func (x *ExpireNodeResponse) GetNode() *Node { } type RenameNodeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + NewName string `protobuf:"bytes,2,opt,name=new_name,json=newName,proto3" json:"new_name,omitempty"` unknownFields protoimpl.UnknownFields - - NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` - NewName string `protobuf:"bytes,2,opt,name=new_name,json=newName,proto3" json:"new_name,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RenameNodeRequest) Reset() { *x = RenameNodeRequest{} - mi := &file_headscale_v1_node_proto_msgTypes[11] + mi := &file_headscale_v1_node_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -726,7 +836,7 @@ func (x *RenameNodeRequest) String() string { func (*RenameNodeRequest) ProtoMessage() {} func (x *RenameNodeRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[11] + mi := &file_headscale_v1_node_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -739,7 +849,7 @@ func (x *RenameNodeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RenameNodeRequest.ProtoReflect.Descriptor instead. func (*RenameNodeRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{11} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{13} } func (x *RenameNodeRequest) GetNodeId() uint64 { @@ -757,16 +867,15 @@ func (x *RenameNodeRequest) GetNewName() string { } type RenameNodeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` unknownFields protoimpl.UnknownFields - - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RenameNodeResponse) Reset() { *x = RenameNodeResponse{} - mi := &file_headscale_v1_node_proto_msgTypes[12] + mi := &file_headscale_v1_node_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -778,7 +887,7 @@ func (x *RenameNodeResponse) String() string { func (*RenameNodeResponse) ProtoMessage() {} func (x *RenameNodeResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[12] + mi := &file_headscale_v1_node_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -791,7 +900,7 @@ func (x *RenameNodeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RenameNodeResponse.ProtoReflect.Descriptor instead. func (*RenameNodeResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{12} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{14} } func (x *RenameNodeResponse) GetNode() *Node { @@ -802,16 +911,15 @@ func (x *RenameNodeResponse) GetNode() *Node { } type ListNodesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` unknownFields protoimpl.UnknownFields - - User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListNodesRequest) Reset() { *x = ListNodesRequest{} - mi := &file_headscale_v1_node_proto_msgTypes[13] + mi := &file_headscale_v1_node_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -823,7 +931,7 @@ func (x *ListNodesRequest) String() string { func (*ListNodesRequest) ProtoMessage() {} func (x *ListNodesRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[13] + mi := &file_headscale_v1_node_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -836,7 +944,7 @@ func (x *ListNodesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListNodesRequest.ProtoReflect.Descriptor instead. func (*ListNodesRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{13} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{15} } func (x *ListNodesRequest) GetUser() string { @@ -847,16 +955,15 @@ func (x *ListNodesRequest) GetUser() string { } type ListNodesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Nodes []*Node `protobuf:"bytes,1,rep,name=nodes,proto3" json:"nodes,omitempty"` unknownFields protoimpl.UnknownFields - - Nodes []*Node `protobuf:"bytes,1,rep,name=nodes,proto3" json:"nodes,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListNodesResponse) Reset() { *x = ListNodesResponse{} - mi := &file_headscale_v1_node_proto_msgTypes[14] + mi := &file_headscale_v1_node_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -868,7 +975,7 @@ func (x *ListNodesResponse) String() string { func (*ListNodesResponse) ProtoMessage() {} func (x *ListNodesResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[14] + mi := &file_headscale_v1_node_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -881,7 +988,7 @@ func (x *ListNodesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListNodesResponse.ProtoReflect.Descriptor instead. func (*ListNodesResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{14} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{16} } func (x *ListNodesResponse) GetNodes() []*Node { @@ -892,17 +999,16 @@ func (x *ListNodesResponse) GetNodes() []*Node { } type MoveNodeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + User string `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"` unknownFields protoimpl.UnknownFields - - NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` - User string `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"` + sizeCache protoimpl.SizeCache } func (x *MoveNodeRequest) Reset() { *x = MoveNodeRequest{} - mi := &file_headscale_v1_node_proto_msgTypes[15] + mi := &file_headscale_v1_node_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -914,7 +1020,7 @@ func (x *MoveNodeRequest) String() string { func (*MoveNodeRequest) ProtoMessage() {} func (x *MoveNodeRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[15] + mi := &file_headscale_v1_node_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -927,7 +1033,7 @@ func (x *MoveNodeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MoveNodeRequest.ProtoReflect.Descriptor instead. func (*MoveNodeRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{15} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{17} } func (x *MoveNodeRequest) GetNodeId() uint64 { @@ -945,16 +1051,15 @@ func (x *MoveNodeRequest) GetUser() string { } type MoveNodeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` unknownFields protoimpl.UnknownFields - - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + sizeCache protoimpl.SizeCache } func (x *MoveNodeResponse) Reset() { *x = MoveNodeResponse{} - mi := &file_headscale_v1_node_proto_msgTypes[16] + mi := &file_headscale_v1_node_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -966,7 +1071,7 @@ func (x *MoveNodeResponse) String() string { func (*MoveNodeResponse) ProtoMessage() {} func (x *MoveNodeResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[16] + mi := &file_headscale_v1_node_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -979,7 +1084,7 @@ func (x *MoveNodeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MoveNodeResponse.ProtoReflect.Descriptor instead. func (*MoveNodeResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{16} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{18} } func (x *MoveNodeResponse) GetNode() *Node { @@ -990,19 +1095,18 @@ func (x *MoveNodeResponse) GetNode() *Node { } type DebugCreateNodeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Routes []string `protobuf:"bytes,4,rep,name=routes,proto3" json:"routes,omitempty"` unknownFields protoimpl.UnknownFields - - User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - Routes []string `protobuf:"bytes,4,rep,name=routes,proto3" json:"routes,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DebugCreateNodeRequest) Reset() { *x = DebugCreateNodeRequest{} - mi := &file_headscale_v1_node_proto_msgTypes[17] + mi := &file_headscale_v1_node_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1014,7 +1118,7 @@ func (x *DebugCreateNodeRequest) String() string { func (*DebugCreateNodeRequest) ProtoMessage() {} func (x *DebugCreateNodeRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[17] + mi := &file_headscale_v1_node_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1027,7 +1131,7 @@ func (x *DebugCreateNodeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DebugCreateNodeRequest.ProtoReflect.Descriptor instead. func (*DebugCreateNodeRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{17} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{19} } func (x *DebugCreateNodeRequest) GetUser() string { @@ -1059,16 +1163,15 @@ func (x *DebugCreateNodeRequest) GetRoutes() []string { } type DebugCreateNodeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` unknownFields protoimpl.UnknownFields - - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DebugCreateNodeResponse) Reset() { *x = DebugCreateNodeResponse{} - mi := &file_headscale_v1_node_proto_msgTypes[18] + mi := &file_headscale_v1_node_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1080,7 +1183,7 @@ func (x *DebugCreateNodeResponse) String() string { func (*DebugCreateNodeResponse) ProtoMessage() {} func (x *DebugCreateNodeResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[18] + mi := &file_headscale_v1_node_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1093,7 +1196,7 @@ func (x *DebugCreateNodeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DebugCreateNodeResponse.ProtoReflect.Descriptor instead. func (*DebugCreateNodeResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{18} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{20} } func (x *DebugCreateNodeResponse) GetNode() *Node { @@ -1104,16 +1207,15 @@ func (x *DebugCreateNodeResponse) GetNode() *Node { } type BackfillNodeIPsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Confirmed bool `protobuf:"varint,1,opt,name=confirmed,proto3" json:"confirmed,omitempty"` unknownFields protoimpl.UnknownFields - - Confirmed bool `protobuf:"varint,1,opt,name=confirmed,proto3" json:"confirmed,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BackfillNodeIPsRequest) Reset() { *x = BackfillNodeIPsRequest{} - mi := &file_headscale_v1_node_proto_msgTypes[19] + mi := &file_headscale_v1_node_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1125,7 +1227,7 @@ func (x *BackfillNodeIPsRequest) String() string { func (*BackfillNodeIPsRequest) ProtoMessage() {} func (x *BackfillNodeIPsRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[19] + mi := &file_headscale_v1_node_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1138,7 +1240,7 @@ func (x *BackfillNodeIPsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BackfillNodeIPsRequest.ProtoReflect.Descriptor instead. func (*BackfillNodeIPsRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{19} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{21} } func (x *BackfillNodeIPsRequest) GetConfirmed() bool { @@ -1149,16 +1251,15 @@ func (x *BackfillNodeIPsRequest) GetConfirmed() bool { } type BackfillNodeIPsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Changes []string `protobuf:"bytes,1,rep,name=changes,proto3" json:"changes,omitempty"` unknownFields protoimpl.UnknownFields - - Changes []string `protobuf:"bytes,1,rep,name=changes,proto3" json:"changes,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BackfillNodeIPsResponse) Reset() { *x = BackfillNodeIPsResponse{} - mi := &file_headscale_v1_node_proto_msgTypes[20] + mi := &file_headscale_v1_node_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1170,7 +1271,7 @@ func (x *BackfillNodeIPsResponse) String() string { func (*BackfillNodeIPsResponse) ProtoMessage() {} func (x *BackfillNodeIPsResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_node_proto_msgTypes[20] + mi := &file_headscale_v1_node_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1183,7 +1284,7 @@ func (x *BackfillNodeIPsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BackfillNodeIPsResponse.ProtoReflect.Descriptor instead. func (*BackfillNodeIPsResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_node_proto_rawDescGZIP(), []int{20} + return file_headscale_v1_node_proto_rawDescGZIP(), []int{22} } func (x *BackfillNodeIPsResponse) GetChanges() []string { @@ -1195,7 +1296,7 @@ func (x *BackfillNodeIPsResponse) GetChanges() []string { var File_headscale_v1_node_proto protoreflect.FileDescriptor -var file_headscale_v1_node_proto_rawDesc = []byte{ +var file_headscale_v1_node_proto_rawDesc = string([]byte{ 0x0a, 0x17, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 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, 0x65, 0x2f, @@ -1204,7 +1305,7 @@ var file_headscale_v1_node_proto_rawDesc = []byte{ 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x9f, 0x05, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x22, 0x98, 0x06, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, @@ -1245,155 +1346,175 @@ var file_headscale_v1_node_proto_rawDesc = []byte{ 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, - 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0e, - 0x10, 0x12, 0x22, 0x3b, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, - 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, - 0x3e, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, - 0x29, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x22, 0x39, 0x0a, 0x0f, 0x47, 0x65, - 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, - 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, - 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, - 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x3d, 0x0a, 0x0e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x61, 0x67, 0x73, 0x22, 0x39, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, - 0x2c, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x22, 0x14, 0x0a, - 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x0a, 0x11, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, - 0x64, 0x22, 0x3c, 0x0a, 0x12, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, - 0x47, 0x0a, 0x11, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x19, 0x0a, - 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6e, 0x65, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3c, 0x0a, 0x12, 0x52, 0x65, 0x6e, 0x61, - 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, - 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, - 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, - 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x26, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, - 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x3d, - 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x3e, 0x0a, - 0x0f, 0x4d, 0x6f, 0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x3a, 0x0a, - 0x10, 0x4d, 0x6f, 0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x26, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, - 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x6a, 0x0a, 0x16, 0x44, 0x65, 0x62, - 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x72, - 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x41, 0x0a, 0x17, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, + 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x17, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, + 0x29, 0x0a, 0x10, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x18, 0x18, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x19, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x4a, + 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x12, 0x22, 0x3b, 0x0a, 0x13, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x3e, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, - 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x36, 0x0a, 0x16, 0x42, 0x61, 0x63, 0x6b, - 0x66, 0x69, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x50, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, - 0x22, 0x33, 0x0a, 0x17, 0x42, 0x61, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, - 0x49, 0x50, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x73, 0x2a, 0x82, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x47, 0x49, - 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x47, - 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x41, 0x55, 0x54, - 0x48, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x47, 0x49, 0x53, - 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x43, 0x4c, 0x49, 0x10, 0x02, - 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, - 0x48, 0x4f, 0x44, 0x5f, 0x4f, 0x49, 0x44, 0x43, 0x10, 0x03, 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, -} + 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, + 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, + 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, + 0x65, 0x49, 0x64, 0x22, 0x39, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x3d, + 0x0a, 0x0e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0x39, 0x0a, + 0x0f, 0x53, 0x65, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x26, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, + 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x4b, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x41, + 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x72, + 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x43, 0x0a, 0x19, 0x53, 0x65, 0x74, 0x41, 0x70, 0x70, 0x72, + 0x6f, 0x76, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x2c, 0x0a, 0x11, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, + 0x0a, 0x11, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x22, 0x3c, 0x0a, 0x12, + 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x47, 0x0a, 0x11, 0x52, 0x65, + 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x4e, + 0x61, 0x6d, 0x65, 0x22, 0x3c, 0x0a, 0x12, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x6e, 0x6f, 0x64, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, + 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, + 0x65, 0x22, 0x26, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x3d, 0x0a, 0x11, 0x4c, 0x69, 0x73, + 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, + 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, + 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x3e, 0x0a, 0x0f, 0x4d, 0x6f, 0x76, 0x65, + 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, + 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, + 0x64, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x3a, 0x0a, 0x10, 0x4d, 0x6f, 0x76, 0x65, + 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, + 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, + 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x6a, 0x0a, 0x16, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, + 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, + 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, + 0x22, 0x41, 0x0a, 0x17, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, + 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x6e, + 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, 0x61, 0x64, + 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, + 0x6f, 0x64, 0x65, 0x22, 0x36, 0x0a, 0x16, 0x42, 0x61, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x6c, 0x4e, + 0x6f, 0x64, 0x65, 0x49, 0x50, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, + 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x22, 0x33, 0x0a, 0x17, 0x42, + 0x61, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x50, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, + 0x2a, 0x82, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, + 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, + 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x4b, 0x45, 0x59, + 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, + 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x43, 0x4c, 0x49, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x52, + 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4f, + 0x49, 0x44, 0x43, 0x10, 0x03, 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_node_proto_rawDescOnce sync.Once - file_headscale_v1_node_proto_rawDescData = file_headscale_v1_node_proto_rawDesc + file_headscale_v1_node_proto_rawDescData []byte ) func file_headscale_v1_node_proto_rawDescGZIP() []byte { file_headscale_v1_node_proto_rawDescOnce.Do(func() { - file_headscale_v1_node_proto_rawDescData = protoimpl.X.CompressGZIP(file_headscale_v1_node_proto_rawDescData) + file_headscale_v1_node_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_headscale_v1_node_proto_rawDesc), len(file_headscale_v1_node_proto_rawDesc))) }) return file_headscale_v1_node_proto_rawDescData } var file_headscale_v1_node_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_headscale_v1_node_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_headscale_v1_node_proto_msgTypes = make([]protoimpl.MessageInfo, 23) var file_headscale_v1_node_proto_goTypes = []any{ - (RegisterMethod)(0), // 0: headscale.v1.RegisterMethod - (*Node)(nil), // 1: headscale.v1.Node - (*RegisterNodeRequest)(nil), // 2: headscale.v1.RegisterNodeRequest - (*RegisterNodeResponse)(nil), // 3: headscale.v1.RegisterNodeResponse - (*GetNodeRequest)(nil), // 4: headscale.v1.GetNodeRequest - (*GetNodeResponse)(nil), // 5: headscale.v1.GetNodeResponse - (*SetTagsRequest)(nil), // 6: headscale.v1.SetTagsRequest - (*SetTagsResponse)(nil), // 7: headscale.v1.SetTagsResponse - (*DeleteNodeRequest)(nil), // 8: headscale.v1.DeleteNodeRequest - (*DeleteNodeResponse)(nil), // 9: headscale.v1.DeleteNodeResponse - (*ExpireNodeRequest)(nil), // 10: headscale.v1.ExpireNodeRequest - (*ExpireNodeResponse)(nil), // 11: headscale.v1.ExpireNodeResponse - (*RenameNodeRequest)(nil), // 12: headscale.v1.RenameNodeRequest - (*RenameNodeResponse)(nil), // 13: headscale.v1.RenameNodeResponse - (*ListNodesRequest)(nil), // 14: headscale.v1.ListNodesRequest - (*ListNodesResponse)(nil), // 15: headscale.v1.ListNodesResponse - (*MoveNodeRequest)(nil), // 16: headscale.v1.MoveNodeRequest - (*MoveNodeResponse)(nil), // 17: headscale.v1.MoveNodeResponse - (*DebugCreateNodeRequest)(nil), // 18: headscale.v1.DebugCreateNodeRequest - (*DebugCreateNodeResponse)(nil), // 19: headscale.v1.DebugCreateNodeResponse - (*BackfillNodeIPsRequest)(nil), // 20: headscale.v1.BackfillNodeIPsRequest - (*BackfillNodeIPsResponse)(nil), // 21: headscale.v1.BackfillNodeIPsResponse - (*User)(nil), // 22: headscale.v1.User - (*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp - (*PreAuthKey)(nil), // 24: headscale.v1.PreAuthKey + (RegisterMethod)(0), // 0: headscale.v1.RegisterMethod + (*Node)(nil), // 1: headscale.v1.Node + (*RegisterNodeRequest)(nil), // 2: headscale.v1.RegisterNodeRequest + (*RegisterNodeResponse)(nil), // 3: headscale.v1.RegisterNodeResponse + (*GetNodeRequest)(nil), // 4: headscale.v1.GetNodeRequest + (*GetNodeResponse)(nil), // 5: headscale.v1.GetNodeResponse + (*SetTagsRequest)(nil), // 6: headscale.v1.SetTagsRequest + (*SetTagsResponse)(nil), // 7: headscale.v1.SetTagsResponse + (*SetApprovedRoutesRequest)(nil), // 8: headscale.v1.SetApprovedRoutesRequest + (*SetApprovedRoutesResponse)(nil), // 9: headscale.v1.SetApprovedRoutesResponse + (*DeleteNodeRequest)(nil), // 10: headscale.v1.DeleteNodeRequest + (*DeleteNodeResponse)(nil), // 11: headscale.v1.DeleteNodeResponse + (*ExpireNodeRequest)(nil), // 12: headscale.v1.ExpireNodeRequest + (*ExpireNodeResponse)(nil), // 13: headscale.v1.ExpireNodeResponse + (*RenameNodeRequest)(nil), // 14: headscale.v1.RenameNodeRequest + (*RenameNodeResponse)(nil), // 15: headscale.v1.RenameNodeResponse + (*ListNodesRequest)(nil), // 16: headscale.v1.ListNodesRequest + (*ListNodesResponse)(nil), // 17: headscale.v1.ListNodesResponse + (*MoveNodeRequest)(nil), // 18: headscale.v1.MoveNodeRequest + (*MoveNodeResponse)(nil), // 19: headscale.v1.MoveNodeResponse + (*DebugCreateNodeRequest)(nil), // 20: headscale.v1.DebugCreateNodeRequest + (*DebugCreateNodeResponse)(nil), // 21: headscale.v1.DebugCreateNodeResponse + (*BackfillNodeIPsRequest)(nil), // 22: headscale.v1.BackfillNodeIPsRequest + (*BackfillNodeIPsResponse)(nil), // 23: headscale.v1.BackfillNodeIPsResponse + (*User)(nil), // 24: headscale.v1.User + (*timestamppb.Timestamp)(nil), // 25: google.protobuf.Timestamp + (*PreAuthKey)(nil), // 26: headscale.v1.PreAuthKey } var file_headscale_v1_node_proto_depIdxs = []int32{ - 22, // 0: headscale.v1.Node.user:type_name -> headscale.v1.User - 23, // 1: headscale.v1.Node.last_seen:type_name -> google.protobuf.Timestamp - 23, // 2: headscale.v1.Node.expiry:type_name -> google.protobuf.Timestamp - 24, // 3: headscale.v1.Node.pre_auth_key:type_name -> headscale.v1.PreAuthKey - 23, // 4: headscale.v1.Node.created_at:type_name -> google.protobuf.Timestamp + 24, // 0: headscale.v1.Node.user:type_name -> headscale.v1.User + 25, // 1: headscale.v1.Node.last_seen:type_name -> google.protobuf.Timestamp + 25, // 2: headscale.v1.Node.expiry:type_name -> google.protobuf.Timestamp + 26, // 3: headscale.v1.Node.pre_auth_key:type_name -> headscale.v1.PreAuthKey + 25, // 4: headscale.v1.Node.created_at:type_name -> google.protobuf.Timestamp 0, // 5: headscale.v1.Node.register_method:type_name -> headscale.v1.RegisterMethod 1, // 6: headscale.v1.RegisterNodeResponse.node:type_name -> headscale.v1.Node 1, // 7: headscale.v1.GetNodeResponse.node:type_name -> headscale.v1.Node 1, // 8: headscale.v1.SetTagsResponse.node:type_name -> headscale.v1.Node - 1, // 9: headscale.v1.ExpireNodeResponse.node:type_name -> headscale.v1.Node - 1, // 10: headscale.v1.RenameNodeResponse.node:type_name -> headscale.v1.Node - 1, // 11: headscale.v1.ListNodesResponse.nodes:type_name -> headscale.v1.Node - 1, // 12: headscale.v1.MoveNodeResponse.node:type_name -> headscale.v1.Node - 1, // 13: headscale.v1.DebugCreateNodeResponse.node:type_name -> headscale.v1.Node - 14, // [14:14] is the sub-list for method output_type - 14, // [14:14] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 1, // 9: headscale.v1.SetApprovedRoutesResponse.node:type_name -> headscale.v1.Node + 1, // 10: headscale.v1.ExpireNodeResponse.node:type_name -> headscale.v1.Node + 1, // 11: headscale.v1.RenameNodeResponse.node:type_name -> headscale.v1.Node + 1, // 12: headscale.v1.ListNodesResponse.nodes:type_name -> headscale.v1.Node + 1, // 13: headscale.v1.MoveNodeResponse.node:type_name -> headscale.v1.Node + 1, // 14: headscale.v1.DebugCreateNodeResponse.node:type_name -> headscale.v1.Node + 15, // [15:15] is the sub-list for method output_type + 15, // [15:15] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_headscale_v1_node_proto_init() } @@ -1407,9 +1528,9 @@ func file_headscale_v1_node_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_headscale_v1_node_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_headscale_v1_node_proto_rawDesc), len(file_headscale_v1_node_proto_rawDesc)), NumEnums: 1, - NumMessages: 21, + NumMessages: 23, NumExtensions: 0, NumServices: 0, }, @@ -1419,7 +1540,6 @@ func file_headscale_v1_node_proto_init() { MessageInfos: file_headscale_v1_node_proto_msgTypes, }.Build() File_headscale_v1_node_proto = out.File - file_headscale_v1_node_proto_rawDesc = nil file_headscale_v1_node_proto_goTypes = nil file_headscale_v1_node_proto_depIdxs = nil } diff --git a/gen/go/headscale/v1/policy.pb.go b/gen/go/headscale/v1/policy.pb.go index ca169b8a..6ba350d3 100644 --- a/gen/go/headscale/v1/policy.pb.go +++ b/gen/go/headscale/v1/policy.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: headscale/v1/policy.proto @@ -12,6 +12,7 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,11 +23,10 @@ const ( ) type SetPolicyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Policy string `protobuf:"bytes,1,opt,name=policy,proto3" json:"policy,omitempty"` unknownFields protoimpl.UnknownFields - - Policy string `protobuf:"bytes,1,opt,name=policy,proto3" json:"policy,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SetPolicyRequest) Reset() { @@ -67,12 +67,11 @@ func (x *SetPolicyRequest) GetPolicy() string { } type SetPolicyResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Policy string `protobuf:"bytes,1,opt,name=policy,proto3" json:"policy,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` unknownFields protoimpl.UnknownFields - - Policy string `protobuf:"bytes,1,opt,name=policy,proto3" json:"policy,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SetPolicyResponse) Reset() { @@ -120,9 +119,9 @@ func (x *SetPolicyResponse) GetUpdatedAt() *timestamppb.Timestamp { } type GetPolicyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetPolicyRequest) Reset() { @@ -156,12 +155,11 @@ func (*GetPolicyRequest) Descriptor() ([]byte, []int) { } type GetPolicyResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Policy string `protobuf:"bytes,1,opt,name=policy,proto3" json:"policy,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` unknownFields protoimpl.UnknownFields - - Policy string `protobuf:"bytes,1,opt,name=policy,proto3" json:"policy,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetPolicyResponse) Reset() { @@ -210,7 +208,7 @@ func (x *GetPolicyResponse) GetUpdatedAt() *timestamppb.Timestamp { var File_headscale_v1_policy_proto protoreflect.FileDescriptor -var file_headscale_v1_policy_proto_rawDesc = []byte{ +var file_headscale_v1_policy_proto_rawDesc = string([]byte{ 0x0a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 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, @@ -236,16 +234,16 @@ var file_headscale_v1_policy_proto_rawDesc = []byte{ 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_policy_proto_rawDescOnce sync.Once - file_headscale_v1_policy_proto_rawDescData = file_headscale_v1_policy_proto_rawDesc + file_headscale_v1_policy_proto_rawDescData []byte ) func file_headscale_v1_policy_proto_rawDescGZIP() []byte { file_headscale_v1_policy_proto_rawDescOnce.Do(func() { - file_headscale_v1_policy_proto_rawDescData = protoimpl.X.CompressGZIP(file_headscale_v1_policy_proto_rawDescData) + file_headscale_v1_policy_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_headscale_v1_policy_proto_rawDesc), len(file_headscale_v1_policy_proto_rawDesc))) }) return file_headscale_v1_policy_proto_rawDescData } @@ -277,7 +275,7 @@ func file_headscale_v1_policy_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_headscale_v1_policy_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_headscale_v1_policy_proto_rawDesc), len(file_headscale_v1_policy_proto_rawDesc)), NumEnums: 0, NumMessages: 4, NumExtensions: 0, @@ -288,7 +286,6 @@ func file_headscale_v1_policy_proto_init() { MessageInfos: file_headscale_v1_policy_proto_msgTypes, }.Build() File_headscale_v1_policy_proto = out.File - file_headscale_v1_policy_proto_rawDesc = nil file_headscale_v1_policy_proto_goTypes = nil file_headscale_v1_policy_proto_depIdxs = nil } diff --git a/gen/go/headscale/v1/preauthkey.pb.go b/gen/go/headscale/v1/preauthkey.pb.go index 4aef49b0..acdb38e5 100644 --- a/gen/go/headscale/v1/preauthkey.pb.go +++ b/gen/go/headscale/v1/preauthkey.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: headscale/v1/preauthkey.proto @@ -12,6 +12,7 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,19 +23,18 @@ const ( ) type PreAuthKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + Reusable bool `protobuf:"varint,4,opt,name=reusable,proto3" json:"reusable,omitempty"` + Ephemeral bool `protobuf:"varint,5,opt,name=ephemeral,proto3" json:"ephemeral,omitempty"` + Used bool `protobuf:"varint,6,opt,name=used,proto3" json:"used,omitempty"` + Expiration *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=expiration,proto3" json:"expiration,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + AclTags []string `protobuf:"bytes,9,rep,name=acl_tags,json=aclTags,proto3" json:"acl_tags,omitempty"` unknownFields protoimpl.UnknownFields - - User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` - Reusable bool `protobuf:"varint,4,opt,name=reusable,proto3" json:"reusable,omitempty"` - Ephemeral bool `protobuf:"varint,5,opt,name=ephemeral,proto3" json:"ephemeral,omitempty"` - Used bool `protobuf:"varint,6,opt,name=used,proto3" json:"used,omitempty"` - Expiration *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=expiration,proto3" json:"expiration,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - AclTags []string `protobuf:"bytes,9,rep,name=acl_tags,json=aclTags,proto3" json:"acl_tags,omitempty"` + sizeCache protoimpl.SizeCache } func (x *PreAuthKey) Reset() { @@ -131,15 +131,14 @@ func (x *PreAuthKey) GetAclTags() []string { } type CreatePreAuthKeyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Reusable bool `protobuf:"varint,2,opt,name=reusable,proto3" json:"reusable,omitempty"` + Ephemeral bool `protobuf:"varint,3,opt,name=ephemeral,proto3" json:"ephemeral,omitempty"` + Expiration *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=expiration,proto3" json:"expiration,omitempty"` + AclTags []string `protobuf:"bytes,5,rep,name=acl_tags,json=aclTags,proto3" json:"acl_tags,omitempty"` unknownFields protoimpl.UnknownFields - - User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` - Reusable bool `protobuf:"varint,2,opt,name=reusable,proto3" json:"reusable,omitempty"` - Ephemeral bool `protobuf:"varint,3,opt,name=ephemeral,proto3" json:"ephemeral,omitempty"` - Expiration *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=expiration,proto3" json:"expiration,omitempty"` - AclTags []string `protobuf:"bytes,5,rep,name=acl_tags,json=aclTags,proto3" json:"acl_tags,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreatePreAuthKeyRequest) Reset() { @@ -208,11 +207,10 @@ func (x *CreatePreAuthKeyRequest) GetAclTags() []string { } type CreatePreAuthKeyResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + PreAuthKey *PreAuthKey `protobuf:"bytes,1,opt,name=pre_auth_key,json=preAuthKey,proto3" json:"pre_auth_key,omitempty"` unknownFields protoimpl.UnknownFields - - PreAuthKey *PreAuthKey `protobuf:"bytes,1,opt,name=pre_auth_key,json=preAuthKey,proto3" json:"pre_auth_key,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreatePreAuthKeyResponse) Reset() { @@ -253,12 +251,11 @@ func (x *CreatePreAuthKeyResponse) GetPreAuthKey() *PreAuthKey { } type ExpirePreAuthKeyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` unknownFields protoimpl.UnknownFields - - User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ExpirePreAuthKeyRequest) Reset() { @@ -306,9 +303,9 @@ func (x *ExpirePreAuthKeyRequest) GetKey() string { } type ExpirePreAuthKeyResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExpirePreAuthKeyResponse) Reset() { @@ -342,11 +339,10 @@ func (*ExpirePreAuthKeyResponse) Descriptor() ([]byte, []int) { } type ListPreAuthKeysRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` unknownFields protoimpl.UnknownFields - - User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListPreAuthKeysRequest) Reset() { @@ -387,11 +383,10 @@ func (x *ListPreAuthKeysRequest) GetUser() string { } type ListPreAuthKeysResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + PreAuthKeys []*PreAuthKey `protobuf:"bytes,1,rep,name=pre_auth_keys,json=preAuthKeys,proto3" json:"pre_auth_keys,omitempty"` unknownFields protoimpl.UnknownFields - - PreAuthKeys []*PreAuthKey `protobuf:"bytes,1,rep,name=pre_auth_keys,json=preAuthKeys,proto3" json:"pre_auth_keys,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListPreAuthKeysResponse) Reset() { @@ -433,7 +428,7 @@ func (x *ListPreAuthKeysResponse) GetPreAuthKeys() []*PreAuthKey { var File_headscale_v1_preauthkey_proto protoreflect.FileDescriptor -var file_headscale_v1_preauthkey_proto_rawDesc = []byte{ +var file_headscale_v1_preauthkey_proto_rawDesc = string([]byte{ 0x0a, 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, 0x74, 0x6f, 0x12, 0x0c, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, @@ -493,16 +488,16 @@ var file_headscale_v1_preauthkey_proto_rawDesc = []byte{ 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_preauthkey_proto_rawDescOnce sync.Once - file_headscale_v1_preauthkey_proto_rawDescData = file_headscale_v1_preauthkey_proto_rawDesc + file_headscale_v1_preauthkey_proto_rawDescData []byte ) func file_headscale_v1_preauthkey_proto_rawDescGZIP() []byte { file_headscale_v1_preauthkey_proto_rawDescOnce.Do(func() { - file_headscale_v1_preauthkey_proto_rawDescData = protoimpl.X.CompressGZIP(file_headscale_v1_preauthkey_proto_rawDescData) + file_headscale_v1_preauthkey_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_headscale_v1_preauthkey_proto_rawDesc), len(file_headscale_v1_preauthkey_proto_rawDesc))) }) return file_headscale_v1_preauthkey_proto_rawDescData } @@ -540,7 +535,7 @@ func file_headscale_v1_preauthkey_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_headscale_v1_preauthkey_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_headscale_v1_preauthkey_proto_rawDesc), len(file_headscale_v1_preauthkey_proto_rawDesc)), NumEnums: 0, NumMessages: 7, NumExtensions: 0, @@ -551,7 +546,6 @@ func file_headscale_v1_preauthkey_proto_init() { MessageInfos: file_headscale_v1_preauthkey_proto_msgTypes, }.Build() File_headscale_v1_preauthkey_proto = out.File - file_headscale_v1_preauthkey_proto_rawDesc = nil file_headscale_v1_preauthkey_proto_goTypes = nil file_headscale_v1_preauthkey_proto_depIdxs = nil } diff --git a/gen/go/headscale/v1/routes.pb.go b/gen/go/headscale/v1/routes.pb.go deleted file mode 100644 index dea86494..00000000 --- a/gen/go/headscale/v1/routes.pb.go +++ /dev/null @@ -1,677 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.35.2 -// protoc (unknown) -// source: headscale/v1/routes.proto - -package v1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type Route struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,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"` - Advertised bool `protobuf:"varint,4,opt,name=advertised,proto3" json:"advertised,omitempty"` - Enabled bool `protobuf:"varint,5,opt,name=enabled,proto3" json:"enabled,omitempty"` - IsPrimary bool `protobuf:"varint,6,opt,name=is_primary,json=isPrimary,proto3" json:"is_primary,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - DeletedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=deleted_at,json=deletedAt,proto3" json:"deleted_at,omitempty"` -} - -func (x *Route) Reset() { - *x = Route{} - mi := &file_headscale_v1_routes_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Route) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Route) ProtoMessage() {} - -func (x *Route) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[0] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Route.ProtoReflect.Descriptor instead. -func (*Route) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{0} -} - -func (x *Route) GetId() uint64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *Route) GetNode() *Node { - if x != nil { - return x.Node - } - return nil -} - -func (x *Route) GetPrefix() string { - if x != nil { - return x.Prefix - } - return "" -} - -func (x *Route) GetAdvertised() bool { - if x != nil { - return x.Advertised - } - return false -} - -func (x *Route) GetEnabled() bool { - if x != nil { - return x.Enabled - } - return false -} - -func (x *Route) GetIsPrimary() bool { - if x != nil { - return x.IsPrimary - } - return false -} - -func (x *Route) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -func (x *Route) GetUpdatedAt() *timestamppb.Timestamp { - if x != nil { - return x.UpdatedAt - } - return nil -} - -func (x *Route) GetDeletedAt() *timestamppb.Timestamp { - if x != nil { - return x.DeletedAt - } - return nil -} - -type GetRoutesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetRoutesRequest) Reset() { - *x = GetRoutesRequest{} - mi := &file_headscale_v1_routes_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetRoutesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetRoutesRequest) ProtoMessage() {} - -func (x *GetRoutesRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[1] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetRoutesRequest.ProtoReflect.Descriptor instead. -func (*GetRoutesRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{1} -} - -type GetRoutesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` -} - -func (x *GetRoutesResponse) Reset() { - *x = GetRoutesResponse{} - mi := &file_headscale_v1_routes_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetRoutesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetRoutesResponse) ProtoMessage() {} - -func (x *GetRoutesResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[2] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetRoutesResponse.ProtoReflect.Descriptor instead. -func (*GetRoutesResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{2} -} - -func (x *GetRoutesResponse) GetRoutes() []*Route { - if x != nil { - return x.Routes - } - return nil -} - -type EnableRouteRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RouteId uint64 `protobuf:"varint,1,opt,name=route_id,json=routeId,proto3" json:"route_id,omitempty"` -} - -func (x *EnableRouteRequest) Reset() { - *x = EnableRouteRequest{} - mi := &file_headscale_v1_routes_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *EnableRouteRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EnableRouteRequest) ProtoMessage() {} - -func (x *EnableRouteRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[3] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EnableRouteRequest.ProtoReflect.Descriptor instead. -func (*EnableRouteRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{3} -} - -func (x *EnableRouteRequest) GetRouteId() uint64 { - if x != nil { - return x.RouteId - } - return 0 -} - -type EnableRouteResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *EnableRouteResponse) Reset() { - *x = EnableRouteResponse{} - mi := &file_headscale_v1_routes_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *EnableRouteResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EnableRouteResponse) ProtoMessage() {} - -func (x *EnableRouteResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[4] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EnableRouteResponse.ProtoReflect.Descriptor instead. -func (*EnableRouteResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{4} -} - -type DisableRouteRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RouteId uint64 `protobuf:"varint,1,opt,name=route_id,json=routeId,proto3" json:"route_id,omitempty"` -} - -func (x *DisableRouteRequest) Reset() { - *x = DisableRouteRequest{} - mi := &file_headscale_v1_routes_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DisableRouteRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DisableRouteRequest) ProtoMessage() {} - -func (x *DisableRouteRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[5] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DisableRouteRequest.ProtoReflect.Descriptor instead. -func (*DisableRouteRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{5} -} - -func (x *DisableRouteRequest) GetRouteId() uint64 { - if x != nil { - return x.RouteId - } - return 0 -} - -type DisableRouteResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *DisableRouteResponse) Reset() { - *x = DisableRouteResponse{} - mi := &file_headscale_v1_routes_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DisableRouteResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DisableRouteResponse) ProtoMessage() {} - -func (x *DisableRouteResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[6] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DisableRouteResponse.ProtoReflect.Descriptor instead. -func (*DisableRouteResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{6} -} - -type GetNodeRoutesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - NodeId uint64 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` -} - -func (x *GetNodeRoutesRequest) Reset() { - *x = GetNodeRoutesRequest{} - mi := &file_headscale_v1_routes_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetNodeRoutesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetNodeRoutesRequest) ProtoMessage() {} - -func (x *GetNodeRoutesRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[7] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetNodeRoutesRequest.ProtoReflect.Descriptor instead. -func (*GetNodeRoutesRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{7} -} - -func (x *GetNodeRoutesRequest) GetNodeId() uint64 { - if x != nil { - return x.NodeId - } - return 0 -} - -type GetNodeRoutesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` -} - -func (x *GetNodeRoutesResponse) Reset() { - *x = GetNodeRoutesResponse{} - mi := &file_headscale_v1_routes_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetNodeRoutesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetNodeRoutesResponse) ProtoMessage() {} - -func (x *GetNodeRoutesResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[8] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetNodeRoutesResponse.ProtoReflect.Descriptor instead. -func (*GetNodeRoutesResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{8} -} - -func (x *GetNodeRoutesResponse) GetRoutes() []*Route { - if x != nil { - return x.Routes - } - return nil -} - -type DeleteRouteRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RouteId uint64 `protobuf:"varint,1,opt,name=route_id,json=routeId,proto3" json:"route_id,omitempty"` -} - -func (x *DeleteRouteRequest) Reset() { - *x = DeleteRouteRequest{} - mi := &file_headscale_v1_routes_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DeleteRouteRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteRouteRequest) ProtoMessage() {} - -func (x *DeleteRouteRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[9] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteRouteRequest.ProtoReflect.Descriptor instead. -func (*DeleteRouteRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{9} -} - -func (x *DeleteRouteRequest) GetRouteId() uint64 { - if x != nil { - return x.RouteId - } - return 0 -} - -type DeleteRouteResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *DeleteRouteResponse) Reset() { - *x = DeleteRouteResponse{} - mi := &file_headscale_v1_routes_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DeleteRouteResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteRouteResponse) ProtoMessage() {} - -func (x *DeleteRouteResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_routes_proto_msgTypes[10] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteRouteResponse.ProtoReflect.Descriptor instead. -func (*DeleteRouteResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_routes_proto_rawDescGZIP(), []int{10} -} - -var File_headscale_v1_routes_proto protoreflect.FileDescriptor - -var file_headscale_v1_routes_proto_rawDesc = []byte{ - 0x0a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x72, - 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, - 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, 0x17, 0x68, 0x65, 0x61, 0x64, - 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0xe1, 0x02, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, - 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x68, 0x65, - 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, - 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1e, 0x0a, - 0x0a, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0a, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x12, 0x18, 0x0a, - 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x70, 0x72, - 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x50, - 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, - 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, - 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x40, 0x0a, 0x11, 0x47, - 0x65, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x2b, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x2f, 0x0a, - 0x12, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x22, 0x15, - 0x0a, 0x13, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x0a, 0x13, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, - 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x69, 0x73, 0x61, 0x62, - 0x6c, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x2f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, - 0x22, 0x44, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x72, 0x6f, 0x75, - 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x68, 0x65, 0x61, 0x64, - 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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_routes_proto_rawDescOnce sync.Once - file_headscale_v1_routes_proto_rawDescData = file_headscale_v1_routes_proto_rawDesc -) - -func file_headscale_v1_routes_proto_rawDescGZIP() []byte { - file_headscale_v1_routes_proto_rawDescOnce.Do(func() { - file_headscale_v1_routes_proto_rawDescData = protoimpl.X.CompressGZIP(file_headscale_v1_routes_proto_rawDescData) - }) - return file_headscale_v1_routes_proto_rawDescData -} - -var file_headscale_v1_routes_proto_msgTypes = make([]protoimpl.MessageInfo, 11) -var file_headscale_v1_routes_proto_goTypes = []any{ - (*Route)(nil), // 0: headscale.v1.Route - (*GetRoutesRequest)(nil), // 1: headscale.v1.GetRoutesRequest - (*GetRoutesResponse)(nil), // 2: headscale.v1.GetRoutesResponse - (*EnableRouteRequest)(nil), // 3: headscale.v1.EnableRouteRequest - (*EnableRouteResponse)(nil), // 4: headscale.v1.EnableRouteResponse - (*DisableRouteRequest)(nil), // 5: headscale.v1.DisableRouteRequest - (*DisableRouteResponse)(nil), // 6: headscale.v1.DisableRouteResponse - (*GetNodeRoutesRequest)(nil), // 7: headscale.v1.GetNodeRoutesRequest - (*GetNodeRoutesResponse)(nil), // 8: headscale.v1.GetNodeRoutesResponse - (*DeleteRouteRequest)(nil), // 9: headscale.v1.DeleteRouteRequest - (*DeleteRouteResponse)(nil), // 10: headscale.v1.DeleteRouteResponse - (*Node)(nil), // 11: headscale.v1.Node - (*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp -} -var file_headscale_v1_routes_proto_depIdxs = []int32{ - 11, // 0: headscale.v1.Route.node:type_name -> headscale.v1.Node - 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, // 3: headscale.v1.Route.deleted_at:type_name -> google.protobuf.Timestamp - 0, // 4: headscale.v1.GetRoutesResponse.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 input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name -} - -func init() { file_headscale_v1_routes_proto_init() } -func file_headscale_v1_routes_proto_init() { - if File_headscale_v1_routes_proto != nil { - return - } - file_headscale_v1_node_proto_init() - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_headscale_v1_routes_proto_rawDesc, - NumEnums: 0, - NumMessages: 11, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_headscale_v1_routes_proto_goTypes, - DependencyIndexes: file_headscale_v1_routes_proto_depIdxs, - MessageInfos: file_headscale_v1_routes_proto_msgTypes, - }.Build() - File_headscale_v1_routes_proto = out.File - file_headscale_v1_routes_proto_rawDesc = nil - file_headscale_v1_routes_proto_goTypes = nil - file_headscale_v1_routes_proto_depIdxs = nil -} diff --git a/gen/go/headscale/v1/user.pb.go b/gen/go/headscale/v1/user.pb.go index 9b44d3d3..a8a238f1 100644 --- a/gen/go/headscale/v1/user.pb.go +++ b/gen/go/headscale/v1/user.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: headscale/v1/user.proto @@ -12,6 +12,7 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,10 +23,7 @@ const ( ) type User struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` CreatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` @@ -34,6 +32,8 @@ type User struct { ProviderId string `protobuf:"bytes,6,opt,name=provider_id,json=providerId,proto3" json:"provider_id,omitempty"` Provider string `protobuf:"bytes,7,opt,name=provider,proto3" json:"provider,omitempty"` ProfilePicUrl string `protobuf:"bytes,8,opt,name=profile_pic_url,json=profilePicUrl,proto3" json:"profile_pic_url,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *User) Reset() { @@ -123,14 +123,13 @@ func (x *User) GetProfilePicUrl() string { } type CreateUserRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + PictureUrl string `protobuf:"bytes,4,opt,name=picture_url,json=pictureUrl,proto3" json:"picture_url,omitempty"` unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` - PictureUrl string `protobuf:"bytes,4,opt,name=picture_url,json=pictureUrl,proto3" json:"picture_url,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateUserRequest) Reset() { @@ -192,11 +191,10 @@ func (x *CreateUserRequest) GetPictureUrl() string { } type CreateUserResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` unknownFields protoimpl.UnknownFields - - User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateUserResponse) Reset() { @@ -237,12 +235,11 @@ func (x *CreateUserResponse) GetUser() *User { } type RenameUserRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + OldId uint64 `protobuf:"varint,1,opt,name=old_id,json=oldId,proto3" json:"old_id,omitempty"` + NewName string `protobuf:"bytes,2,opt,name=new_name,json=newName,proto3" json:"new_name,omitempty"` unknownFields protoimpl.UnknownFields - - OldId uint64 `protobuf:"varint,1,opt,name=old_id,json=oldId,proto3" json:"old_id,omitempty"` - NewName string `protobuf:"bytes,2,opt,name=new_name,json=newName,proto3" json:"new_name,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RenameUserRequest) Reset() { @@ -290,11 +287,10 @@ func (x *RenameUserRequest) GetNewName() string { } type RenameUserResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` unknownFields protoimpl.UnknownFields - - User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RenameUserResponse) Reset() { @@ -335,11 +331,10 @@ func (x *RenameUserResponse) GetUser() *User { } type DeleteUserRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields - - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DeleteUserRequest) Reset() { @@ -380,9 +375,9 @@ func (x *DeleteUserRequest) GetId() uint64 { } type DeleteUserResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DeleteUserResponse) Reset() { @@ -416,13 +411,12 @@ func (*DeleteUserResponse) Descriptor() ([]byte, []int) { } type ListUsersRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` unknownFields protoimpl.UnknownFields - - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListUsersRequest) Reset() { @@ -477,11 +471,10 @@ func (x *ListUsersRequest) GetEmail() string { } type ListUsersResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Users []*User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"` unknownFields protoimpl.UnknownFields - - Users []*User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListUsersResponse) Reset() { @@ -523,7 +516,7 @@ func (x *ListUsersResponse) GetUsers() []*User { var File_headscale_v1_user_proto protoreflect.FileDescriptor -var file_headscale_v1_user_proto_rawDesc = []byte{ +var file_headscale_v1_user_proto_rawDesc = string([]byte{ 0x0a, 0x17, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 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, 0x65, 0x2f, @@ -581,16 +574,16 @@ var file_headscale_v1_user_proto_rawDesc = []byte{ 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_user_proto_rawDescOnce sync.Once - file_headscale_v1_user_proto_rawDescData = file_headscale_v1_user_proto_rawDesc + file_headscale_v1_user_proto_rawDescData []byte ) func file_headscale_v1_user_proto_rawDescGZIP() []byte { file_headscale_v1_user_proto_rawDescOnce.Do(func() { - file_headscale_v1_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_headscale_v1_user_proto_rawDescData) + file_headscale_v1_user_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_headscale_v1_user_proto_rawDesc), len(file_headscale_v1_user_proto_rawDesc))) }) return file_headscale_v1_user_proto_rawDescData } @@ -629,7 +622,7 @@ func file_headscale_v1_user_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_headscale_v1_user_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_headscale_v1_user_proto_rawDesc), len(file_headscale_v1_user_proto_rawDesc)), NumEnums: 0, NumMessages: 9, NumExtensions: 0, @@ -640,7 +633,6 @@ func file_headscale_v1_user_proto_init() { MessageInfos: file_headscale_v1_user_proto_msgTypes, }.Build() File_headscale_v1_user_proto = out.File - file_headscale_v1_user_proto_rawDesc = nil file_headscale_v1_user_proto_goTypes = nil file_headscale_v1_user_proto_depIdxs = nil } diff --git a/gen/openapiv2/headscale/v1/headscale.swagger.json b/gen/openapiv2/headscale/v1/headscale.swagger.json index f6813391..ef35ff11 100644 --- a/gen/openapiv2/headscale/v1/headscale.swagger.json +++ b/gen/openapiv2/headscale/v1/headscale.swagger.json @@ -320,6 +320,45 @@ ] } }, + "/api/v1/node/{nodeId}/approve_routes": { + "post": { + "operationId": "HeadscaleService_SetApprovedRoutes", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1SetApprovedRoutesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "nodeId", + "in": "path", + "required": true, + "type": "string", + "format": "uint64" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/HeadscaleServiceSetApprovedRoutesBody" + } + } + ], + "tags": [ + "HeadscaleService" + ] + } + }, "/api/v1/node/{nodeId}/expire": { "post": { "operationId": "HeadscaleService_ExpireNode", @@ -388,37 +427,6 @@ ] } }, - "/api/v1/node/{nodeId}/routes": { - "get": { - "operationId": "HeadscaleService_GetNodeRoutes", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetNodeRoutesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "nodeId", - "in": "path", - "required": true, - "type": "string", - "format": "uint64" - } - ], - "tags": [ - "HeadscaleService" - ] - } - }, "/api/v1/node/{nodeId}/tags": { "post": { "operationId": "HeadscaleService_SetTags", @@ -643,122 +651,6 @@ ] } }, - "/api/v1/routes": { - "get": { - "summary": "--- Route start ---", - "operationId": "HeadscaleService_GetRoutes", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetRoutesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "HeadscaleService" - ] - } - }, - "/api/v1/routes/{routeId}": { - "delete": { - "operationId": "HeadscaleService_DeleteRoute", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1DeleteRouteResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "routeId", - "in": "path", - "required": true, - "type": "string", - "format": "uint64" - } - ], - "tags": [ - "HeadscaleService" - ] - } - }, - "/api/v1/routes/{routeId}/disable": { - "post": { - "operationId": "HeadscaleService_DisableRoute", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1DisableRouteResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "routeId", - "in": "path", - "required": true, - "type": "string", - "format": "uint64" - } - ], - "tags": [ - "HeadscaleService" - ] - } - }, - "/api/v1/routes/{routeId}/enable": { - "post": { - "operationId": "HeadscaleService_EnableRoute", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1EnableRouteResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "routeId", - "in": "path", - "required": true, - "type": "string", - "format": "uint64" - } - ], - "tags": [ - "HeadscaleService" - ] - } - }, "/api/v1/user": { "get": { "operationId": "HeadscaleService_ListUsers", @@ -911,6 +803,17 @@ } } }, + "HeadscaleServiceSetApprovedRoutesBody": { + "type": "object", + "properties": { + "routes": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "HeadscaleServiceSetTagsBody": { "type": "object", "properties": { @@ -1093,18 +996,9 @@ "v1DeleteNodeResponse": { "type": "object" }, - "v1DeleteRouteResponse": { - "type": "object" - }, "v1DeleteUserResponse": { "type": "object" }, - "v1DisableRouteResponse": { - "type": "object" - }, - "v1EnableRouteResponse": { - "type": "object" - }, "v1ExpireApiKeyRequest": { "type": "object", "properties": { @@ -1146,18 +1040,6 @@ } } }, - "v1GetNodeRoutesResponse": { - "type": "object", - "properties": { - "routes": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Route" - } - } - } - }, "v1GetPolicyResponse": { "type": "object", "properties": { @@ -1170,18 +1052,6 @@ } } }, - "v1GetRoutesResponse": { - "type": "object", - "properties": { - "routes": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Route" - } - } - } - }, "v1ListApiKeysResponse": { "type": "object", "properties": { @@ -1307,6 +1177,24 @@ }, "online": { "type": "boolean" + }, + "approvedRoutes": { + "type": "array", + "items": { + "type": "string" + } + }, + "availableRoutes": { + "type": "array", + "items": { + "type": "string" + } + }, + "subnetRoutes": { + "type": "array", + "items": { + "type": "string" + } } } }, @@ -1381,39 +1269,11 @@ } } }, - "v1Route": { + "v1SetApprovedRoutesResponse": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uint64" - }, "node": { "$ref": "#/definitions/v1Node" - }, - "prefix": { - "type": "string" - }, - "advertised": { - "type": "boolean" - }, - "enabled": { - "type": "boolean" - }, - "isPrimary": { - "type": "boolean" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "deletedAt": { - "type": "string", - "format": "date-time" } } }, diff --git a/gen/openapiv2/headscale/v1/routes.swagger.json b/gen/openapiv2/headscale/v1/routes.swagger.json deleted file mode 100644 index 11087f2a..00000000 --- a/gen/openapiv2/headscale/v1/routes.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "headscale/v1/routes.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/hscontrol/app.go b/hscontrol/app.go index 48f375fa..c37e1e89 100644 --- a/hscontrol/app.go +++ b/hscontrol/app.go @@ -32,6 +32,7 @@ import ( "github.com/juanfont/headscale/hscontrol/mapper" "github.com/juanfont/headscale/hscontrol/notifier" "github.com/juanfont/headscale/hscontrol/policy" + "github.com/juanfont/headscale/hscontrol/routes" "github.com/juanfont/headscale/hscontrol/types" "github.com/juanfont/headscale/hscontrol/util" zerolog "github.com/philip-bui/grpc-zerolog" @@ -92,6 +93,7 @@ type Headscale struct { polManOnce sync.Once polMan policy.PolicyManager extraRecordMan *dns.ExtraRecordsMan + primaryRoutes *routes.PrimaryRoutes mapper *mapper.Mapper nodeNotifier *notifier.Notifier @@ -134,6 +136,7 @@ func NewHeadscale(cfg *types.Config) (*Headscale, error) { registrationCache: registrationCache, pollNetMapStreamWG: sync.WaitGroup{}, nodeNotifier: notifier.NewNotifier(cfg), + primaryRoutes: routes.New(), } app.db, err = db.NewHeadscaleDatabase( @@ -495,6 +498,8 @@ func (h *Headscale) createRouter(grpcMux *grpcRuntime.ServeMux) *mux.Router { // TODO(kradalby): Do a variant of this, and polman which only updates the node that has changed. // Maybe we should attempt a new in memory state and not go via the DB? +// Maybe this should be implemented as an event bus? +// A bool is returned indicating if a full update was sent to all nodes func usersChangedHook(db *db.HSDatabase, polMan policy.PolicyManager, notif *notifier.Notifier) error { users, err := db.ListUsers() if err != nil { @@ -516,6 +521,7 @@ func usersChangedHook(db *db.HSDatabase, polMan policy.PolicyManager, notif *not // TODO(kradalby): Do a variant of this, and polman which only updates the node that has changed. // Maybe we should attempt a new in memory state and not go via the DB? +// Maybe this should be implemented as an event bus? // A bool is returned indicating if a full update was sent to all nodes func nodesChangedHook(db *db.HSDatabase, polMan policy.PolicyManager, notif *notifier.Notifier) (bool, error) { nodes, err := db.ListNodes() @@ -566,7 +572,7 @@ func (h *Headscale) Serve() error { // Fetch an initial DERP Map before we start serving h.DERPMap = derp.GetDERPMap(h.cfg.DERP) - h.mapper = mapper.NewMapper(h.db, h.cfg, h.DERPMap, h.nodeNotifier, h.polMan) + h.mapper = mapper.NewMapper(h.db, h.cfg, h.DERPMap, h.nodeNotifier, h.polMan, h.primaryRoutes) if h.cfg.DERP.ServerEnabled { // When embedded DERP is enabled we always need a STUN server diff --git a/hscontrol/auth.go b/hscontrol/auth.go index 0a8602cd..da7cd8a9 100644 --- a/hscontrol/auth.go +++ b/hscontrol/auth.go @@ -84,16 +84,13 @@ func (h *Headscale) handleExistingNode( // If the request expiry is in the past, we consider it a logout. if requestExpiry.Before(time.Now()) { if node.IsEphemeral() { - changedNodes, err := h.db.DeleteNode(node, h.nodeNotifier.LikelyConnectedMap()) + err := h.db.DeleteNode(node) if err != nil { return nil, fmt.Errorf("deleting ephemeral node: %w", err) } ctx := types.NotifyCtx(context.Background(), "logout-ephemeral", "na") h.nodeNotifier.NotifyAll(ctx, types.UpdatePeerRemoved(node.ID)) - if changedNodes != nil { - h.nodeNotifier.NotifyAll(ctx, types.UpdatePeerChanged(changedNodes...)) - } } expired = true diff --git a/hscontrol/db/db.go b/hscontrol/db/db.go index 7f4ecb32..a130f876 100644 --- a/hscontrol/db/db.go +++ b/hscontrol/db/db.go @@ -8,6 +8,7 @@ import ( "fmt" "net/netip" "path/filepath" + "slices" "strconv" "strings" "time" @@ -622,6 +623,62 @@ AND auth_key_id NOT IN ( }, Rollback: func(db *gorm.DB) error { return nil }, }, + // Migrate all routes from the Route table to the new field ApprovedRoutes + // in the Node table. Then drop the Route table. + { + ID: "202502131714", + Migrate: func(tx *gorm.DB) error { + if !tx.Migrator().HasColumn(&types.Node{}, "approved_routes") { + err := tx.Migrator().AddColumn(&types.Node{}, "approved_routes") + if err != nil { + return fmt.Errorf("adding column types.Node: %w", err) + } + } + // Ensure the ApprovedRoutes exist. + // err := tx.AutoMigrate(&types.Node{}) + // if err != nil { + // return fmt.Errorf("automigrating types.Node: %w", err) + // } + + nodeRoutes := map[uint64][]netip.Prefix{} + + var routes []types.Route + err = tx.Find(&routes).Error + if err != nil { + return fmt.Errorf("fetching routes: %w", err) + } + + for _, route := range routes { + if route.Enabled { + nodeRoutes[route.NodeID] = append(nodeRoutes[route.NodeID], route.Prefix) + } + } + + for nodeID, routes := range nodeRoutes { + slices.SortFunc(routes, util.ComparePrefix) + slices.Compact(routes) + + data, err := json.Marshal(routes) + + err = tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("approved_routes", data).Error + if err != nil { + return fmt.Errorf("saving approved routes to new column: %w", err) + } + } + + return nil + }, + Rollback: func(db *gorm.DB) error { return nil }, + }, + { + ID: "202502171819", + Migrate: func(tx *gorm.DB) error { + _ = tx.Migrator().DropColumn(&types.Node{}, "last_seen") + + return nil + }, + Rollback: func(db *gorm.DB) error { return nil }, + }, }, ) diff --git a/hscontrol/db/db_test.go b/hscontrol/db/db_test.go index 079f632f..10781c7b 100644 --- a/hscontrol/db/db_test.go +++ b/hscontrol/db/db_test.go @@ -48,25 +48,43 @@ func TestMigrationsSQLite(t *testing.T) { { dbPath: "testdata/0-22-3-to-0-23-0-routes-are-dropped-2063.sqlite", wantFunc: func(t *testing.T, h *HSDatabase) { - routes, err := Read(h.DB, func(rx *gorm.DB) (types.Routes, error) { - return GetRoutes(rx) + nodes, err := Read(h.DB, func(rx *gorm.DB) (types.Nodes, error) { + n1, err := GetNodeByID(rx, 1) + n26, err := GetNodeByID(rx, 26) + n31, err := GetNodeByID(rx, 31) + n32, err := GetNodeByID(rx, 32) + if err != nil { + return nil, err + } + + return types.Nodes{n1, n26, n31, n32}, nil }) require.NoError(t, err) - assert.Len(t, routes, 10) - want := types.Routes{ - r(1, "0.0.0.0/0", true, true, false), - r(1, "::/0", true, true, false), - r(1, "10.9.110.0/24", true, true, true), - r(26, "172.100.100.0/24", true, true, true), - r(26, "172.100.100.0/24", true, false, false), - r(31, "0.0.0.0/0", true, true, false), - r(31, "0.0.0.0/0", true, false, false), - r(31, "::/0", true, true, false), - r(31, "::/0", true, false, false), - r(32, "192.168.0.24/32", true, true, true), + // want := types.Routes{ + // r(1, "0.0.0.0/0", true, false), + // r(1, "::/0", true, false), + // r(1, "10.9.110.0/24", true, true), + // r(26, "172.100.100.0/24", true, true), + // r(26, "172.100.100.0/24", true, false, false), + // r(31, "0.0.0.0/0", true, false), + // r(31, "0.0.0.0/0", true, false, false), + // r(31, "::/0", true, false), + // r(31, "::/0", true, false, false), + // r(32, "192.168.0.24/32", true, true), + // } + want := [][]netip.Prefix{ + {ipp("0.0.0.0/0"), ipp("10.9.110.0/24"), ipp("::/0")}, + {ipp("172.100.100.0/24")}, + {ipp("0.0.0.0/0"), ipp("::/0")}, + {ipp("192.168.0.24/32")}, } - if diff := cmp.Diff(want, routes, cmpopts.IgnoreFields(types.Route{}, "Model", "Node"), util.PrefixComparer); diff != "" { + var got [][]netip.Prefix + for _, node := range nodes { + got = append(got, node.ApprovedRoutes) + } + + if diff := cmp.Diff(want, got, util.PrefixComparer); diff != "" { t.Errorf("TestMigrations() mismatch (-want +got):\n%s", diff) } }, @@ -74,13 +92,13 @@ func TestMigrationsSQLite(t *testing.T) { { dbPath: "testdata/0-22-3-to-0-23-0-routes-fail-foreign-key-2076.sqlite", wantFunc: func(t *testing.T, h *HSDatabase) { - routes, err := Read(h.DB, func(rx *gorm.DB) (types.Routes, error) { - return GetRoutes(rx) + node, err := Read(h.DB, func(rx *gorm.DB) (*types.Node, error) { + return GetNodeByID(rx, 13) }) require.NoError(t, err) - assert.Len(t, routes, 4) - want := types.Routes{ + assert.Len(t, node.ApprovedRoutes, 3) + _ = types.Routes{ // These routes exists, but have no nodes associated with them // when the migration starts. // r(1, "0.0.0.0/0", true, true, false), @@ -111,7 +129,8 @@ func TestMigrationsSQLite(t *testing.T) { r(13, "::/0", true, true, false), r(13, "10.18.80.2/32", true, true, true), } - if diff := cmp.Diff(want, routes, cmpopts.IgnoreFields(types.Route{}, "Model", "Node"), util.PrefixComparer); diff != "" { + want := []netip.Prefix{ipp("0.0.0.0/0"), ipp("10.18.80.2/32"), ipp("::/0")} + if diff := cmp.Diff(want, node.ApprovedRoutes, util.PrefixComparer); diff != "" { t.Errorf("TestMigrations() mismatch (-want +got):\n%s", diff) } }, @@ -225,7 +244,7 @@ func TestMigrationsSQLite(t *testing.T) { for _, tt := range tests { t.Run(tt.dbPath, func(t *testing.T) { - dbPath, err := testCopyOfDatabase(tt.dbPath) + dbPath, err := testCopyOfDatabase(t, tt.dbPath) if err != nil { t.Fatalf("copying db for test: %s", err) } @@ -247,7 +266,7 @@ func TestMigrationsSQLite(t *testing.T) { } } -func testCopyOfDatabase(src string) (string, error) { +func testCopyOfDatabase(t *testing.T, src string) (string, error) { sourceFileStat, err := os.Stat(src) if err != nil { return "", err @@ -263,11 +282,7 @@ func testCopyOfDatabase(src string) (string, error) { } defer source.Close() - tmpDir, err := os.MkdirTemp("", "hsdb-test-*") - if err != nil { - return "", err - } - + tmpDir := t.TempDir() fn := filepath.Base(src) dst := filepath.Join(tmpDir, fn) @@ -454,3 +469,27 @@ func TestMigrationsPostgres(t *testing.T) { }) } } + +func dbForTest(t *testing.T) *HSDatabase { + t.Helper() + + dbPath := t.TempDir() + "/headscale_test.db" + + db, err := NewHeadscaleDatabase( + types.DatabaseConfig{ + Type: "sqlite3", + Sqlite: types.SqliteConfig{ + Path: dbPath, + }, + }, + "", + emptyCache(), + ) + if err != nil { + t.Fatalf("setting up database: %s", err) + } + + t.Logf("database set up at: %s", dbPath) + + return db +} diff --git a/hscontrol/db/ip_test.go b/hscontrol/db/ip_test.go index 0e5b6ad4..f558cdf7 100644 --- a/hscontrol/db/ip_test.go +++ b/hscontrol/db/ip_test.go @@ -91,7 +91,7 @@ func TestIPAllocatorSequential(t *testing.T) { { name: "simple-with-db", dbFunc: func() *HSDatabase { - db := dbForTest(t, "simple-with-db") + db := dbForTest(t) user := types.User{Name: ""} db.DB.Save(&user) @@ -119,7 +119,7 @@ func TestIPAllocatorSequential(t *testing.T) { { name: "before-after-free-middle-in-db", dbFunc: func() *HSDatabase { - db := dbForTest(t, "before-after-free-middle-in-db") + db := dbForTest(t) user := types.User{Name: ""} db.DB.Save(&user) @@ -309,7 +309,7 @@ func TestBackfillIPAddresses(t *testing.T) { { name: "simple-backfill-ipv6", dbFunc: func() *HSDatabase { - db := dbForTest(t, "simple-backfill-ipv6") + db := dbForTest(t) user := types.User{Name: ""} db.DB.Save(&user) @@ -334,7 +334,7 @@ func TestBackfillIPAddresses(t *testing.T) { { name: "simple-backfill-ipv4", dbFunc: func() *HSDatabase { - db := dbForTest(t, "simple-backfill-ipv4") + db := dbForTest(t) user := types.User{Name: ""} db.DB.Save(&user) @@ -359,7 +359,7 @@ func TestBackfillIPAddresses(t *testing.T) { { name: "simple-backfill-remove-ipv6", dbFunc: func() *HSDatabase { - db := dbForTest(t, "simple-backfill-remove-ipv6") + db := dbForTest(t) user := types.User{Name: ""} db.DB.Save(&user) @@ -383,7 +383,7 @@ func TestBackfillIPAddresses(t *testing.T) { { name: "simple-backfill-remove-ipv4", dbFunc: func() *HSDatabase { - db := dbForTest(t, "simple-backfill-remove-ipv4") + db := dbForTest(t) user := types.User{Name: ""} db.DB.Save(&user) @@ -407,7 +407,7 @@ func TestBackfillIPAddresses(t *testing.T) { { name: "multi-backfill-ipv6", dbFunc: func() *HSDatabase { - db := dbForTest(t, "simple-backfill-ipv6") + db := dbForTest(t) user := types.User{Name: ""} db.DB.Save(&user) @@ -449,7 +449,6 @@ func TestBackfillIPAddresses(t *testing.T) { "UserID", "Endpoints", "Hostinfo", - "Routes", "CreatedAt", "UpdatedAt", )) @@ -488,6 +487,10 @@ func TestBackfillIPAddresses(t *testing.T) { } func TestIPAllocatorNextNoReservedIPs(t *testing.T) { + db, err := newSQLiteTestDB() + require.NoError(t, err) + defer db.Close() + alloc, err := NewIPAllocator( db, ptr.To(tsaddr.CGNATRange()), diff --git a/hscontrol/db/node.go b/hscontrol/db/node.go index 74cd7a9f..f36f66b7 100644 --- a/hscontrol/db/node.go +++ b/hscontrol/db/node.go @@ -12,12 +12,10 @@ import ( "github.com/juanfont/headscale/hscontrol/types" "github.com/juanfont/headscale/hscontrol/util" - "github.com/puzpuzpuz/xsync/v3" "github.com/rs/zerolog/log" "gorm.io/gorm" "tailscale.com/tailcfg" "tailscale.com/types/key" - "tailscale.com/types/ptr" ) const ( @@ -50,7 +48,6 @@ func ListPeers(tx *gorm.DB, nodeID types.NodeID) (types.Nodes, error) { Preload("AuthKey"). Preload("AuthKey.User"). Preload("User"). - Preload("Routes"). Where("id <> ?", nodeID).Find(&nodes).Error; err != nil { return types.Nodes{}, err @@ -73,7 +70,6 @@ func ListNodes(tx *gorm.DB) (types.Nodes, error) { Preload("AuthKey"). Preload("AuthKey.User"). Preload("User"). - Preload("Routes"). Find(&nodes).Error; err != nil { return nil, err } @@ -127,7 +123,6 @@ func GetNodeByID(tx *gorm.DB, id types.NodeID) (*types.Node, error) { Preload("AuthKey"). Preload("AuthKey.User"). Preload("User"). - Preload("Routes"). Find(&types.Node{ID: id}).First(&mach); result.Error != nil { return nil, result.Error } @@ -151,7 +146,6 @@ func GetNodeByMachineKey( Preload("AuthKey"). Preload("AuthKey.User"). Preload("User"). - Preload("Routes"). First(&mach, "machine_key = ?", machineKey.String()); result.Error != nil { return nil, result.Error } @@ -175,7 +169,6 @@ func GetNodeByNodeKey( Preload("AuthKey"). Preload("AuthKey.User"). Preload("User"). - Preload("Routes"). First(&mach, "node_key = ?", nodeKey.String()); result.Error != nil { return nil, result.Error } @@ -201,7 +194,7 @@ func SetTags( if len(tags) == 0 { // if no tags are provided, we remove all forced tags if err := tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("forced_tags", "[]").Error; err != nil { - return fmt.Errorf("failed to remove tags for node in the database: %w", err) + return fmt.Errorf("removing tags: %w", err) } return nil @@ -220,7 +213,34 @@ func SetTags( } if err := tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("forced_tags", string(b)).Error; err != nil { - return fmt.Errorf("failed to update tags for node in the database: %w", err) + return fmt.Errorf("updating tags: %w", err) + } + + return nil +} + +// SetTags takes a Node struct pointer and update the forced tags. +func SetApprovedRoutes( + tx *gorm.DB, + nodeID types.NodeID, + routes []netip.Prefix, +) error { + if len(routes) == 0 { + // if no routes are provided, we remove all + if err := tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("approved_routes", "[]").Error; err != nil { + return fmt.Errorf("removing approved routes: %w", err) + } + + return nil + } + + b, err := json.Marshal(routes) + if err != nil { + return err + } + + if err := tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("approved_routes", string(b)).Error; err != nil { + return fmt.Errorf("updating approved routes: %w", err) } return nil @@ -267,9 +287,9 @@ func NodeSetExpiry(tx *gorm.DB, return tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("expiry", expiry).Error } -func (hsdb *HSDatabase) DeleteNode(node *types.Node, isLikelyConnected *xsync.MapOf[types.NodeID, bool]) ([]types.NodeID, error) { - return Write(hsdb.DB, func(tx *gorm.DB) ([]types.NodeID, error) { - return DeleteNode(tx, node, isLikelyConnected) +func (hsdb *HSDatabase) DeleteNode(node *types.Node) error { + return hsdb.Write(func(tx *gorm.DB) error { + return DeleteNode(tx, node) }) } @@ -277,19 +297,13 @@ func (hsdb *HSDatabase) DeleteNode(node *types.Node, isLikelyConnected *xsync.Ma // Caller is responsible for notifying all of change. func DeleteNode(tx *gorm.DB, node *types.Node, - isLikelyConnected *xsync.MapOf[types.NodeID, bool], -) ([]types.NodeID, error) { - changed, err := deleteNodeRoutes(tx, node, isLikelyConnected) - if err != nil { - return changed, err - } - +) error { // Unscoped causes the node to be fully removed from the database. if err := tx.Unscoped().Delete(&types.Node{}, node.ID).Error; err != nil { - return changed, err + return err } - return changed, nil + return nil } // DeleteEphemeralNode deletes a Node from the database, note that this method @@ -306,12 +320,6 @@ func (hsdb *HSDatabase) DeleteEphemeralNode( }) } -// SetLastSeen sets a node's last seen field indicating that we -// have recently communicating with this node. -func SetLastSeen(tx *gorm.DB, nodeID types.NodeID, lastSeen time.Time) error { - return tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("last_seen", lastSeen).Error -} - // HandleNodeFromAuthPath is called from the OIDC or CLI auth path // with a registrationID to register or reauthenticate a node. // If the node found in the registration cache is not already registered, @@ -458,10 +466,6 @@ func RegisterNode(tx *gorm.DB, node types.Node, ipv4 *netip.Addr, ipv6 *netip.Ad return nil, fmt.Errorf("failed register(save) node in the database: %w", err) } - if _, err := SaveNodeRoutes(tx, &node); err != nil { - return nil, fmt.Errorf("failed to save node routes: %w", err) - } - log.Trace(). Caller(). Str("node", node.Hostname). @@ -504,141 +508,6 @@ func NodeSave(tx *gorm.DB, node *types.Node) error { return tx.Save(node).Error } -func (hsdb *HSDatabase) GetAdvertisedRoutes(node *types.Node) ([]netip.Prefix, error) { - return Read(hsdb.DB, func(rx *gorm.DB) ([]netip.Prefix, error) { - return GetAdvertisedRoutes(rx, node) - }) -} - -// GetAdvertisedRoutes returns the routes that are be advertised by the given node. -func GetAdvertisedRoutes(tx *gorm.DB, node *types.Node) ([]netip.Prefix, error) { - routes := types.Routes{} - - err := tx. - Preload("Node"). - Where("node_id = ? AND advertised = ?", node.ID, true).Find(&routes).Error - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, fmt.Errorf("getting advertised routes for node(%d): %w", node.ID, err) - } - - var prefixes []netip.Prefix - for _, route := range routes { - prefixes = append(prefixes, netip.Prefix(route.Prefix)) - } - - return prefixes, nil -} - -func (hsdb *HSDatabase) GetEnabledRoutes(node *types.Node) ([]netip.Prefix, error) { - return Read(hsdb.DB, func(rx *gorm.DB) ([]netip.Prefix, error) { - return GetEnabledRoutes(rx, node) - }) -} - -// GetEnabledRoutes returns the routes that are enabled for the node. -func GetEnabledRoutes(tx *gorm.DB, node *types.Node) ([]netip.Prefix, error) { - routes := types.Routes{} - - err := tx. - Preload("Node"). - Where("node_id = ? AND advertised = ? AND enabled = ?", node.ID, true, true). - Find(&routes).Error - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, fmt.Errorf("getting enabled routes for node(%d): %w", node.ID, err) - } - - var prefixes []netip.Prefix - for _, route := range routes { - prefixes = append(prefixes, netip.Prefix(route.Prefix)) - } - - return prefixes, nil -} - -func IsRoutesEnabled(tx *gorm.DB, node *types.Node, routeStr string) bool { - route, err := netip.ParsePrefix(routeStr) - if err != nil { - return false - } - - enabledRoutes, err := GetEnabledRoutes(tx, node) - if err != nil { - return false - } - - for _, enabledRoute := range enabledRoutes { - if route == enabledRoute { - return true - } - } - - return false -} - -func (hsdb *HSDatabase) enableRoutes( - node *types.Node, - newRoutes ...netip.Prefix, -) (*types.StateUpdate, error) { - return Write(hsdb.DB, func(tx *gorm.DB) (*types.StateUpdate, error) { - return enableRoutes(tx, node, newRoutes...) - }) -} - -// enableRoutes enables new routes based on a list of new routes. -func enableRoutes(tx *gorm.DB, - node *types.Node, newRoutes ...netip.Prefix, -) (*types.StateUpdate, error) { - advertisedRoutes, err := GetAdvertisedRoutes(tx, node) - if err != nil { - return nil, err - } - - for _, newRoute := range newRoutes { - if !slices.Contains(advertisedRoutes, newRoute) { - return nil, 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 := tx.Preload("Node"). - Where("node_id = ? AND prefix = ?", node.ID, prefix.String()). - 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 = isUniquePrefix(tx, route) - } - - err = tx.Save(&route).Error - if err != nil { - return nil, fmt.Errorf("failed to enable route: %w", err) - } - } else { - return nil, fmt.Errorf("failed to find route: %w", err) - } - } - - // Ensure the node has the latest routes when notifying the other - // nodes - nRoutes, err := GetNodeRoutes(tx, node) - if err != nil { - return nil, fmt.Errorf("failed to read back routes: %w", err) - } - - node.Routes = nRoutes - - return ptr.To(types.UpdatePeerChanged(node.ID)), nil -} - func generateGivenName(suppliedName string, randomSuffix bool) (string, error) { suppliedName = util.ConvertWithFQDNRules(suppliedName) if len(suppliedName) > util.LabelHostnameLength { diff --git a/hscontrol/db/node_test.go b/hscontrol/db/node_test.go index fc5f6ac3..c3924bbe 100644 --- a/hscontrol/db/node_test.go +++ b/hscontrol/db/node_test.go @@ -15,12 +15,10 @@ import ( "github.com/juanfont/headscale/hscontrol/policy" "github.com/juanfont/headscale/hscontrol/types" "github.com/juanfont/headscale/hscontrol/util" - "github.com/puzpuzpuz/xsync/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/check.v1" "gorm.io/gorm" - "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" "tailscale.com/types/key" "tailscale.com/types/ptr" @@ -102,7 +100,7 @@ func (s *Suite) TestHardDeleteNode(c *check.C) { trx := db.DB.Save(&node) c.Assert(trx.Error, check.IsNil) - _, err = db.DeleteNode(&node, xsync.NewMapOf[types.NodeID, bool]()) + err = db.DeleteNode(&node) c.Assert(err, check.IsNil) _, err = db.getNode(types.UserID(user.ID), "testnode3") @@ -458,142 +456,143 @@ func TestHeadscale_generateGivenName(t *testing.T) { } } -func TestAutoApproveRoutes(t *testing.T) { - tests := []struct { - name string - acl string - routes []netip.Prefix - want []netip.Prefix - }{ - { - name: "2068-approve-issue-sub", - acl: ` -{ - "groups": { - "group:k8s": ["test"] - }, +// TODO(kradalby): replace this test +// func TestAutoApproveRoutes(t *testing.T) { +// tests := []struct { +// name string +// acl string +// routes []netip.Prefix +// want []netip.Prefix +// }{ +// { +// name: "2068-approve-issue-sub", +// acl: ` +// { +// "groups": { +// "group:k8s": ["test"] +// }, - "acls": [ - {"action": "accept", "users": ["*"], "ports": ["*:*"]}, - ], +// "acls": [ +// {"action": "accept", "users": ["*"], "ports": ["*:*"]}, +// ], - "autoApprovers": { - "routes": { - "10.42.0.0/16": ["test"], - } - } -}`, - routes: []netip.Prefix{netip.MustParsePrefix("10.42.7.0/24")}, - want: []netip.Prefix{netip.MustParsePrefix("10.42.7.0/24")}, - }, - { - name: "2068-approve-issue-sub", - acl: ` -{ - "tagOwners": { - "tag:exit": ["test"], - }, +// "autoApprovers": { +// "routes": { +// "10.42.0.0/16": ["test"], +// } +// } +// }`, +// routes: []netip.Prefix{netip.MustParsePrefix("10.42.7.0/24")}, +// want: []netip.Prefix{netip.MustParsePrefix("10.42.7.0/24")}, +// }, +// { +// name: "2068-approve-issue-sub", +// acl: ` +// { +// "tagOwners": { +// "tag:exit": ["test"], +// }, - "groups": { - "group:test": ["test"] - }, +// "groups": { +// "group:test": ["test"] +// }, - "acls": [ - {"action": "accept", "users": ["*"], "ports": ["*:*"]}, - ], +// "acls": [ +// {"action": "accept", "users": ["*"], "ports": ["*:*"]}, +// ], - "autoApprovers": { - "exitNode": ["tag:exit"], - "routes": { - "10.10.0.0/16": ["group:test"], - "10.11.0.0/16": ["test"], - } - } -}`, - routes: []netip.Prefix{ - tsaddr.AllIPv4(), - tsaddr.AllIPv6(), - netip.MustParsePrefix("10.10.0.0/16"), - netip.MustParsePrefix("10.11.0.0/24"), - }, - want: []netip.Prefix{ - tsaddr.AllIPv4(), - netip.MustParsePrefix("10.10.0.0/16"), - netip.MustParsePrefix("10.11.0.0/24"), - tsaddr.AllIPv6(), - }, - }, - } +// "autoApprovers": { +// "exitNode": ["tag:exit"], +// "routes": { +// "10.10.0.0/16": ["group:test"], +// "10.11.0.0/16": ["test"], +// } +// } +// }`, +// routes: []netip.Prefix{ +// tsaddr.AllIPv4(), +// tsaddr.AllIPv6(), +// netip.MustParsePrefix("10.10.0.0/16"), +// netip.MustParsePrefix("10.11.0.0/24"), +// }, +// want: []netip.Prefix{ +// tsaddr.AllIPv4(), +// netip.MustParsePrefix("10.10.0.0/16"), +// netip.MustParsePrefix("10.11.0.0/24"), +// tsaddr.AllIPv6(), +// }, +// }, +// } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - adb, err := newSQLiteTestDB() - require.NoError(t, err) - pol, err := policy.LoadACLPolicyFromBytes([]byte(tt.acl)) +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// adb, err := newSQLiteTestDB() +// require.NoError(t, err) +// pol, err := policy.LoadACLPolicyFromBytes([]byte(tt.acl)) - require.NoError(t, err) - require.NotNil(t, pol) +// require.NoError(t, err) +// require.NotNil(t, pol) - user, err := adb.CreateUser(types.User{Name: "test"}) - require.NoError(t, err) +// user, err := adb.CreateUser(types.User{Name: "test"}) +// require.NoError(t, err) - pak, err := adb.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) - require.NoError(t, err) +// pak, err := adb.CreatePreAuthKey(types.UserID(user.ID), false, nil, nil) +// require.NoError(t, err) - nodeKey := key.NewNode() - machineKey := key.NewMachine() +// nodeKey := key.NewNode() +// machineKey := key.NewMachine() - v4 := netip.MustParseAddr("100.64.0.1") - node := types.Node{ - ID: 0, - MachineKey: machineKey.Public(), - NodeKey: nodeKey.Public(), - Hostname: "test", - UserID: user.ID, - RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: ptr.To(pak.ID), - Hostinfo: &tailcfg.Hostinfo{ - RequestTags: []string{"tag:exit"}, - RoutableIPs: tt.routes, - }, - IPv4: &v4, - } +// v4 := netip.MustParseAddr("100.64.0.1") +// node := types.Node{ +// ID: 0, +// MachineKey: machineKey.Public(), +// NodeKey: nodeKey.Public(), +// Hostname: "test", +// UserID: user.ID, +// RegisterMethod: util.RegisterMethodAuthKey, +// AuthKeyID: ptr.To(pak.ID), +// Hostinfo: &tailcfg.Hostinfo{ +// RequestTags: []string{"tag:exit"}, +// RoutableIPs: tt.routes, +// }, +// IPv4: &v4, +// } - trx := adb.DB.Save(&node) - require.NoError(t, trx.Error) +// trx := adb.DB.Save(&node) +// require.NoError(t, trx.Error) - sendUpdate, err := adb.SaveNodeRoutes(&node) - require.NoError(t, err) - assert.False(t, sendUpdate) +// sendUpdate, err := adb.SaveNodeRoutes(&node) +// require.NoError(t, err) +// assert.False(t, sendUpdate) - node0ByID, err := adb.GetNodeByID(0) - require.NoError(t, err) +// node0ByID, err := adb.GetNodeByID(0) +// require.NoError(t, err) - users, err := adb.ListUsers() - assert.NoError(t, err) +// users, err := adb.ListUsers() +// assert.NoError(t, err) - nodes, err := adb.ListNodes() - assert.NoError(t, err) +// nodes, err := adb.ListNodes() +// assert.NoError(t, err) - pm, err := policy.NewPolicyManager([]byte(tt.acl), users, nodes) - assert.NoError(t, err) +// pm, err := policy.NewPolicyManager([]byte(tt.acl), users, nodes) +// assert.NoError(t, err) - // TODO(kradalby): Check state update - err = adb.EnableAutoApprovedRoutes(pm, node0ByID) - require.NoError(t, err) +// // TODO(kradalby): Check state update +// err = adb.EnableAutoApprovedRoutes(pm, node0ByID) +// require.NoError(t, err) - enabledRoutes, err := adb.GetEnabledRoutes(node0ByID) - require.NoError(t, err) - assert.Len(t, enabledRoutes, len(tt.want)) +// enabledRoutes, err := adb.GetEnabledRoutes(node0ByID) +// require.NoError(t, err) +// assert.Len(t, enabledRoutes, len(tt.want)) - tsaddr.SortPrefixes(enabledRoutes) +// tsaddr.SortPrefixes(enabledRoutes) - if diff := cmp.Diff(tt.want, enabledRoutes, util.Comparers...); diff != "" { - t.Errorf("unexpected enabled routes (-want +got):\n%s", diff) - } - }) - } -} +// if diff := cmp.Diff(tt.want, enabledRoutes, util.Comparers...); diff != "" { +// t.Errorf("unexpected enabled routes (-want +got):\n%s", diff) +// } +// }) +// } +// } func TestEphemeralGarbageCollectorOrder(t *testing.T) { want := []types.NodeID{1, 3} diff --git a/hscontrol/db/routes.go b/hscontrol/db/routes.go deleted file mode 100644 index b2bda26b..00000000 --- a/hscontrol/db/routes.go +++ /dev/null @@ -1,676 +0,0 @@ -package db - -import ( - "errors" - "fmt" - "net/netip" - "sort" - - "github.com/juanfont/headscale/hscontrol/policy" - "github.com/juanfont/headscale/hscontrol/types" - "github.com/puzpuzpuz/xsync/v3" - "github.com/rs/zerolog/log" - "gorm.io/gorm" - "tailscale.com/net/tsaddr" - "tailscale.com/types/ptr" - "tailscale.com/util/set" -) - -var ErrRouteIsNotAvailable = errors.New("route is not available") - -func GetRoutes(tx *gorm.DB) (types.Routes, error) { - var routes types.Routes - err := tx. - Preload("Node"). - Preload("Node.User"). - Find(&routes).Error - if err != nil { - return nil, err - } - - return routes, nil -} - -func getAdvertisedAndEnabledRoutes(tx *gorm.DB) (types.Routes, error) { - var routes types.Routes - err := tx. - Preload("Node"). - Preload("Node.User"). - Where("advertised = ? AND enabled = ?", true, true). - Find(&routes).Error - if err != nil { - return nil, err - } - - return routes, nil -} - -func getRoutesByPrefix(tx *gorm.DB, pref netip.Prefix) (types.Routes, error) { - var routes types.Routes - err := tx. - Preload("Node"). - Preload("Node.User"). - Where("prefix = ?", pref.String()). - Find(&routes).Error - if err != nil { - return nil, err - } - - return routes, nil -} - -func GetNodeAdvertisedRoutes(tx *gorm.DB, node *types.Node) (types.Routes, error) { - var routes types.Routes - err := tx. - Preload("Node"). - Preload("Node.User"). - Where("node_id = ? AND advertised = true", node.ID). - Find(&routes).Error - if err != nil { - return nil, err - } - - return routes, nil -} - -func (hsdb *HSDatabase) GetNodeRoutes(node *types.Node) (types.Routes, error) { - return Read(hsdb.DB, func(rx *gorm.DB) (types.Routes, error) { - return GetNodeRoutes(rx, node) - }) -} - -func GetNodeRoutes(tx *gorm.DB, node *types.Node) (types.Routes, error) { - var routes types.Routes - err := tx. - Preload("Node"). - Preload("Node.User"). - Where("node_id = ?", node.ID). - Find(&routes).Error - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, err - } - - return routes, nil -} - -func GetRoute(tx *gorm.DB, id uint64) (*types.Route, error) { - var route types.Route - err := tx. - Preload("Node"). - Preload("Node.User"). - First(&route, id).Error - if err != nil { - return nil, err - } - - return &route, nil -} - -func EnableRoute(tx *gorm.DB, id uint64) (*types.StateUpdate, error) { - route, err := GetRoute(tx, id) - if err != nil { - return nil, err - } - - // Tailscale requires both IPv4 and IPv6 exit routes to - // be enabled at the same time, as per - // https://github.com/juanfont/headscale/issues/804#issuecomment-1399314002 - if route.IsExitRoute() { - return enableRoutes( - tx, - route.Node, - tsaddr.AllIPv4(), - tsaddr.AllIPv6(), - ) - } - - return enableRoutes(tx, route.Node, netip.Prefix(route.Prefix)) -} - -func DisableRoute(tx *gorm.DB, - id uint64, - isLikelyConnected *xsync.MapOf[types.NodeID, bool], -) ([]types.NodeID, error) { - route, err := GetRoute(tx, id) - if err != nil { - return nil, err - } - - var routes types.Routes - node := route.Node - - // Tailscale requires both IPv4 and IPv6 exit routes to - // be enabled at the same time, as per - // https://github.com/juanfont/headscale/issues/804#issuecomment-1399314002 - var update []types.NodeID - if !route.IsExitRoute() { - route.Enabled = false - err = tx.Save(route).Error - if err != nil { - return nil, err - } - - update, err = failoverRouteTx(tx, isLikelyConnected, route) - if err != nil { - return nil, err - } - } else { - routes, err = GetNodeRoutes(tx, node) - if err != nil { - return nil, err - } - - for i := range routes { - if routes[i].IsExitRoute() { - routes[i].Enabled = false - routes[i].IsPrimary = false - - err = tx.Save(&routes[i]).Error - if err != nil { - return nil, err - } - } - } - } - - // If update is empty, it means that one was not created - // by failover (as a failover was not necessary), create - // one and return to the caller. - if update == nil { - update = []types.NodeID{node.ID} - } - - return update, nil -} - -func (hsdb *HSDatabase) DeleteRoute( - id uint64, - isLikelyConnected *xsync.MapOf[types.NodeID, bool], -) ([]types.NodeID, error) { - return Write(hsdb.DB, func(tx *gorm.DB) ([]types.NodeID, error) { - return DeleteRoute(tx, id, isLikelyConnected) - }) -} - -func DeleteRoute( - tx *gorm.DB, - id uint64, - isLikelyConnected *xsync.MapOf[types.NodeID, bool], -) ([]types.NodeID, error) { - route, err := GetRoute(tx, id) - if err != nil { - return nil, err - } - - if route.Node == nil { - // If the route is not assigned to a node, just delete it, - // there are no updates to be sent as no nodes are - // dependent on it - if err := tx.Unscoped().Delete(&route).Error; err != nil { - return nil, err - } - return nil, nil - } - - var routes types.Routes - node := route.Node - - // Tailscale requires both IPv4 and IPv6 exit routes to - // be enabled at the same time, as per - // https://github.com/juanfont/headscale/issues/804#issuecomment-1399314002 - // This means that if we delete a route which is an exit route, delete both. - var update []types.NodeID - if route.IsExitRoute() { - routes, err = GetNodeRoutes(tx, node) - if err != nil { - return nil, err - } - - var routesToDelete types.Routes - for _, r := range routes { - if r.IsExitRoute() { - routesToDelete = append(routesToDelete, r) - } - } - - if err := tx.Unscoped().Delete(&routesToDelete).Error; err != nil { - return nil, err - } - } else { - update, err = failoverRouteTx(tx, isLikelyConnected, route) - if err != nil { - return nil, nil - } - - if err := tx.Unscoped().Delete(&route).Error; err != nil { - return nil, err - } - } - - // If update is empty, it means that one was not created - // by failover (as a failover was not necessary), create - // one and return to the caller. - if routes == nil { - routes, err = GetNodeRoutes(tx, node) - if err != nil { - return nil, err - } - } - - node.Routes = routes - - if update == nil { - update = []types.NodeID{node.ID} - } - - return update, nil -} - -func deleteNodeRoutes(tx *gorm.DB, node *types.Node, isLikelyConnected *xsync.MapOf[types.NodeID, bool]) ([]types.NodeID, error) { - routes, err := GetNodeRoutes(tx, node) - if err != nil { - return nil, fmt.Errorf("getting node routes: %w", err) - } - - var changed []types.NodeID - for i := range routes { - if err := tx.Unscoped().Delete(&routes[i]).Error; err != nil { - return nil, fmt.Errorf("deleting route(%d): %w", &routes[i].ID, err) - } - - // TODO(kradalby): This is a bit too aggressive, we could probably - // figure out which routes needs to be failed over rather than all. - chn, err := failoverRouteTx(tx, isLikelyConnected, &routes[i]) - if err != nil { - return changed, fmt.Errorf("failing over route after delete: %w", err) - } - - if chn != nil { - changed = append(changed, chn...) - } - } - - return changed, nil -} - -// isUniquePrefix returns if there is another node providing the same route already. -func isUniquePrefix(tx *gorm.DB, route types.Route) bool { - var count int64 - tx.Model(&types.Route{}). - Where("prefix = ? AND node_id != ? AND advertised = ? AND enabled = ?", - route.Prefix.String(), - route.NodeID, - true, true).Count(&count) - - return count == 0 -} - -func getPrimaryRoute(tx *gorm.DB, prefix netip.Prefix) (*types.Route, error) { - var route types.Route - err := tx. - Preload("Node"). - Where("prefix = ? AND advertised = ? AND enabled = ? AND is_primary = ?", prefix.String(), true, true, true). - First(&route).Error - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, err - } - - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, gorm.ErrRecordNotFound - } - - return &route, nil -} - -func (hsdb *HSDatabase) GetNodePrimaryRoutes(node *types.Node) (types.Routes, error) { - return Read(hsdb.DB, func(rx *gorm.DB) (types.Routes, error) { - return GetNodePrimaryRoutes(rx, node) - }) -} - -// 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. -func GetNodePrimaryRoutes(tx *gorm.DB, node *types.Node) (types.Routes, error) { - var routes types.Routes - err := tx. - Preload("Node"). - Where("node_id = ? AND advertised = ? AND enabled = ? AND is_primary = ?", node.ID, true, true, true). - Find(&routes).Error - if err != nil { - return nil, err - } - - return routes, nil -} - -func (hsdb *HSDatabase) SaveNodeRoutes(node *types.Node) (bool, error) { - return Write(hsdb.DB, func(tx *gorm.DB) (bool, error) { - return SaveNodeRoutes(tx, node) - }) -} - -// SaveNodeRoutes takes a node and updates the database with -// the new routes. -// It returns a bool whether an update should be sent as the -// saved route impacts nodes. -func SaveNodeRoutes(tx *gorm.DB, node *types.Node) (bool, error) { - sendUpdate := false - - currentRoutes := types.Routes{} - err := tx.Where("node_id = ?", node.ID).Find(¤tRoutes).Error - if err != nil { - return sendUpdate, err - } - - advertisedRoutes := map[netip.Prefix]bool{} - for _, prefix := range node.Hostinfo.RoutableIPs { - advertisedRoutes[prefix] = false - } - - log.Trace(). - Str("node", node.Hostname). - Interface("advertisedRoutes", advertisedRoutes). - Interface("currentRoutes", currentRoutes). - Msg("updating routes") - - for pos, route := range currentRoutes { - if _, ok := advertisedRoutes[netip.Prefix(route.Prefix)]; ok { - if !route.Advertised { - currentRoutes[pos].Advertised = true - err := tx.Save(¤tRoutes[pos]).Error - if err != nil { - return sendUpdate, err - } - - // If a route that is newly "saved" is already - // enabled, set sendUpdate to true as it is now - // available. - if route.Enabled { - sendUpdate = true - } - } - advertisedRoutes[netip.Prefix(route.Prefix)] = true - } else if route.Advertised { - currentRoutes[pos].Advertised = false - currentRoutes[pos].Enabled = false - err := tx.Save(¤tRoutes[pos]).Error - if err != nil { - return sendUpdate, err - } - } - } - - for prefix, exists := range advertisedRoutes { - if !exists { - route := types.Route{ - NodeID: node.ID.Uint64(), - Prefix: prefix, - Advertised: true, - Enabled: false, - } - err := tx.Create(&route).Error - if err != nil { - return sendUpdate, err - } - } - } - - return sendUpdate, nil -} - -// FailoverNodeRoutesIfNecessary takes a node and checks if the node's route -// need to be failed over to another host. -// If needed, the failover will be attempted. -func FailoverNodeRoutesIfNecessary( - tx *gorm.DB, - isLikelyConnected *xsync.MapOf[types.NodeID, bool], - node *types.Node, -) (*types.StateUpdate, error) { - nodeRoutes, err := GetNodeRoutes(tx, node) - if err != nil { - return nil, nil - } - - changedNodes := make(set.Set[types.NodeID]) - -nodeRouteLoop: - for _, nodeRoute := range nodeRoutes { - routes, err := getRoutesByPrefix(tx, netip.Prefix(nodeRoute.Prefix)) - if err != nil { - return nil, fmt.Errorf("getting routes by prefix: %w", err) - } - - for _, route := range routes { - if route.IsPrimary { - // if we have a primary route, and the node is connected - // nothing needs to be done. - if val, ok := isLikelyConnected.Load(route.Node.ID); ok && val { - continue nodeRouteLoop - } - - // if not, we need to failover the route - failover := failoverRoute(isLikelyConnected, &route, routes) - if failover != nil { - err := failover.save(tx) - if err != nil { - return nil, fmt.Errorf("saving failover routes: %w", err) - } - - changedNodes.Add(failover.old.Node.ID) - changedNodes.Add(failover.new.Node.ID) - - continue nodeRouteLoop - } - } - } - } - - chng := changedNodes.Slice() - sort.SliceStable(chng, func(i, j int) bool { - return chng[i] < chng[j] - }) - - if len(changedNodes) != 0 { - return ptr.To(types.UpdatePeerChanged(chng...)), nil - } - - return nil, nil -} - -// failoverRouteTx takes a route that is no longer available, -// this can be either from: -// - being disabled -// - being deleted -// - host going offline -// -// and tries to find a new route to take over its place. -// If the given route was not primary, it returns early. -func failoverRouteTx( - tx *gorm.DB, - isLikelyConnected *xsync.MapOf[types.NodeID, bool], - r *types.Route, -) ([]types.NodeID, error) { - if r == nil { - return nil, nil - } - - // This route is not a primary route, and it is not - // being served to nodes. - if !r.IsPrimary { - return nil, nil - } - - // We do not have to failover exit nodes - if r.IsExitRoute() { - return nil, nil - } - - routes, err := getRoutesByPrefix(tx, netip.Prefix(r.Prefix)) - if err != nil { - return nil, fmt.Errorf("getting routes by prefix: %w", err) - } - - fo := failoverRoute(isLikelyConnected, r, routes) - if fo == nil { - return nil, nil - } - - err = fo.save(tx) - if err != nil { - return nil, fmt.Errorf("saving failover route: %w", err) - } - - log.Trace(). - Str("hostname", fo.new.Node.Hostname). - Msgf("set primary to new route, was: id(%d), host(%s), now: id(%d), host(%s)", fo.old.ID, fo.old.Node.Hostname, fo.new.ID, fo.new.Node.Hostname) - - // Return a list of the machinekeys of the changed nodes. - return []types.NodeID{fo.old.Node.ID, fo.new.Node.ID}, nil -} - -type failover struct { - old *types.Route - new *types.Route -} - -func (f *failover) save(tx *gorm.DB) error { - err := tx.Save(f.old).Error - if err != nil { - return fmt.Errorf("saving old primary: %w", err) - } - - err = tx.Save(f.new).Error - if err != nil { - return fmt.Errorf("saving new primary: %w", err) - } - - return nil -} - -func failoverRoute( - isLikelyConnected *xsync.MapOf[types.NodeID, bool], - routeToReplace *types.Route, - altRoutes types.Routes, -) *failover { - if routeToReplace == nil { - return nil - } - - // This route is not a primary route, and it is not - // being served to nodes. - if !routeToReplace.IsPrimary { - return nil - } - - // We do not have to failover exit nodes - if routeToReplace.IsExitRoute() { - return nil - } - - var newPrimary *types.Route - - // Find a new suitable route - for idx, route := range altRoutes { - if routeToReplace.ID == route.ID { - continue - } - - if !route.Enabled { - continue - } - - if isLikelyConnected != nil { - if val, ok := isLikelyConnected.Load(route.Node.ID); ok && val { - newPrimary = &altRoutes[idx] - break - } - } - } - - // If a new route was not found/available, - // return without an error. - // We do not want to update the database as - // the one currently marked as primary is the - // best we got. - if newPrimary == nil { - return nil - } - - routeToReplace.IsPrimary = false - newPrimary.IsPrimary = true - - return &failover{ - old: routeToReplace, - new: newPrimary, - } -} - -func (hsdb *HSDatabase) EnableAutoApprovedRoutes( - polMan policy.PolicyManager, - node *types.Node, -) error { - return hsdb.Write(func(tx *gorm.DB) error { - return EnableAutoApprovedRoutes(tx, polMan, node) - }) -} - -// EnableAutoApprovedRoutes enables any routes advertised by a node that match the ACL autoApprovers policy. -func EnableAutoApprovedRoutes( - tx *gorm.DB, - polMan policy.PolicyManager, - node *types.Node, -) error { - if node.IPv4 == nil && node.IPv6 == nil { - return nil // This node has no IPAddresses, so can't possibly match any autoApprovers ACLs - } - - routes, err := GetNodeAdvertisedRoutes(tx, node) - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return fmt.Errorf("getting advertised routes for node(%s %d): %w", node.Hostname, node.ID, err) - } - - log.Trace().Interface("routes", routes).Msg("routes for autoapproving") - - var approvedRoutes types.Routes - - for _, advertisedRoute := range routes { - if advertisedRoute.Enabled { - continue - } - - routeApprovers := polMan.ApproversForRoute(netip.Prefix(advertisedRoute.Prefix)) - - log.Trace(). - Str("node", node.Hostname). - Uint("user.id", node.User.ID). - Strs("routeApprovers", routeApprovers). - Str("prefix", netip.Prefix(advertisedRoute.Prefix).String()). - Msg("looking up route for autoapproving") - - for _, approvedAlias := range routeApprovers { - if approvedAlias == node.User.Username() { - approvedRoutes = append(approvedRoutes, advertisedRoute) - } else { - // TODO(kradalby): figure out how to get this to depend on less stuff - approvedIps, err := polMan.ExpandAlias(approvedAlias) - if err != nil { - return fmt.Errorf("expanding alias %q for autoApprovers: %w", approvedAlias, err) - } - - // approvedIPs should contain all of node's IPs if it matches the rule, so check for first - if approvedIps.Contains(*node.IPv4) { - approvedRoutes = append(approvedRoutes, advertisedRoute) - } - } - } - } - - for _, approvedRoute := range approvedRoutes { - _, err := EnableRoute(tx, uint64(approvedRoute.ID)) - if err != nil { - return fmt.Errorf("enabling approved route(%d): %w", approvedRoute.ID, err) - } - } - - return nil -} diff --git a/hscontrol/db/routes_test.go b/hscontrol/db/routes_test.go deleted file mode 100644 index 4547339a..00000000 --- a/hscontrol/db/routes_test.go +++ /dev/null @@ -1,1233 +0,0 @@ -package db - -import ( - "net/netip" - "os" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/juanfont/headscale/hscontrol/types" - "github.com/juanfont/headscale/hscontrol/util" - "github.com/puzpuzpuz/xsync/v3" - "gopkg.in/check.v1" - "gorm.io/gorm" - "tailscale.com/tailcfg" - "tailscale.com/types/ptr" -) - -var smap = func(m map[types.NodeID]bool) *xsync.MapOf[types.NodeID, bool] { - s := xsync.NewMapOf[types.NodeID, bool]() - - for k, v := range m { - s.Store(k, v) - } - - return s -} - -var mp = func(p string) netip.Prefix { - return netip.MustParsePrefix(p) -} - -func (s *Suite) TestGetRoutes(c *check.C) { - user, err := db.CreateUser(types.User{Name: "test"}) - c.Assert(err, check.IsNil) - - pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) - c.Assert(err, check.IsNil) - - _, err = db.getNode(types.UserID(user.ID), "test_get_route_node") - c.Assert(err, check.NotNil) - - route, err := netip.ParsePrefix("10.0.0.0/24") - c.Assert(err, check.IsNil) - - hostInfo := tailcfg.Hostinfo{ - RoutableIPs: []netip.Prefix{route}, - } - - node := types.Node{ - ID: 0, - Hostname: "test_get_route_node", - UserID: user.ID, - RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: ptr.To(pak.ID), - Hostinfo: &hostInfo, - } - trx := db.DB.Save(&node) - c.Assert(trx.Error, check.IsNil) - - su, err := db.SaveNodeRoutes(&node) - c.Assert(err, check.IsNil) - c.Assert(su, check.Equals, false) - - advertisedRoutes, err := db.GetAdvertisedRoutes(&node) - c.Assert(err, check.IsNil) - c.Assert(len(advertisedRoutes), check.Equals, 1) - - // TODO(kradalby): check state update - _, err = db.enableRoutes(&node, mp("192.168.0.0/24")) - c.Assert(err, check.NotNil) - - _, err = db.enableRoutes(&node, mp("10.0.0.0/24")) - c.Assert(err, check.IsNil) -} - -func (s *Suite) TestGetEnableRoutes(c *check.C) { - user, err := db.CreateUser(types.User{Name: "test"}) - c.Assert(err, check.IsNil) - - pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) - c.Assert(err, check.IsNil) - - _, err = db.getNode(types.UserID(user.ID), "test_enable_route_node") - c.Assert(err, check.NotNil) - - route, err := netip.ParsePrefix( - "10.0.0.0/24", - ) - c.Assert(err, check.IsNil) - - route2, err := netip.ParsePrefix( - "150.0.10.0/25", - ) - c.Assert(err, check.IsNil) - - hostInfo := tailcfg.Hostinfo{ - RoutableIPs: []netip.Prefix{route, route2}, - } - - node := types.Node{ - ID: 0, - Hostname: "test_enable_route_node", - UserID: user.ID, - RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: ptr.To(pak.ID), - Hostinfo: &hostInfo, - } - trx := db.DB.Save(&node) - c.Assert(trx.Error, check.IsNil) - - sendUpdate, err := db.SaveNodeRoutes(&node) - c.Assert(err, check.IsNil) - c.Assert(sendUpdate, check.Equals, false) - - availableRoutes, err := db.GetAdvertisedRoutes(&node) - c.Assert(err, check.IsNil) - c.Assert(err, check.IsNil) - c.Assert(len(availableRoutes), check.Equals, 2) - - noEnabledRoutes, err := db.GetEnabledRoutes(&node) - c.Assert(err, check.IsNil) - c.Assert(len(noEnabledRoutes), check.Equals, 0) - - _, err = db.enableRoutes(&node, mp("192.168.0.0/24")) - c.Assert(err, check.NotNil) - - _, err = db.enableRoutes(&node, mp("10.0.0.0/24")) - c.Assert(err, check.IsNil) - - enabledRoutes, err := db.GetEnabledRoutes(&node) - c.Assert(err, check.IsNil) - c.Assert(len(enabledRoutes), check.Equals, 1) - - // Adding it twice will just let it pass through - _, err = db.enableRoutes(&node, mp("10.0.0.0/24")) - c.Assert(err, check.IsNil) - - enableRoutesAfterDoubleApply, err := db.GetEnabledRoutes(&node) - c.Assert(err, check.IsNil) - c.Assert(len(enableRoutesAfterDoubleApply), check.Equals, 1) - - _, err = db.enableRoutes(&node, mp("150.0.10.0/25")) - c.Assert(err, check.IsNil) - - enabledRoutesWithAdditionalRoute, err := db.GetEnabledRoutes(&node) - c.Assert(err, check.IsNil) - c.Assert(len(enabledRoutesWithAdditionalRoute), check.Equals, 2) -} - -func (s *Suite) TestIsUniquePrefix(c *check.C) { - user, err := db.CreateUser(types.User{Name: "test"}) - c.Assert(err, check.IsNil) - - pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) - c.Assert(err, check.IsNil) - - _, err = db.getNode(types.UserID(user.ID), "test_enable_route_node") - c.Assert(err, check.NotNil) - - route, err := netip.ParsePrefix( - "10.0.0.0/24", - ) - c.Assert(err, check.IsNil) - - route2, err := netip.ParsePrefix( - "150.0.10.0/25", - ) - c.Assert(err, check.IsNil) - - hostInfo1 := tailcfg.Hostinfo{ - RoutableIPs: []netip.Prefix{route, route2}, - } - node1 := types.Node{ - ID: 1, - Hostname: "test_enable_route_node", - UserID: user.ID, - RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: ptr.To(pak.ID), - Hostinfo: &hostInfo1, - } - trx := db.DB.Save(&node1) - c.Assert(trx.Error, check.IsNil) - - sendUpdate, err := db.SaveNodeRoutes(&node1) - c.Assert(err, check.IsNil) - c.Assert(sendUpdate, check.Equals, false) - - _, err = db.enableRoutes(&node1, route) - c.Assert(err, check.IsNil) - - _, err = db.enableRoutes(&node1, route2) - c.Assert(err, check.IsNil) - - hostInfo2 := tailcfg.Hostinfo{ - RoutableIPs: []netip.Prefix{route2}, - } - node2 := types.Node{ - ID: 2, - Hostname: "test_enable_route_node", - UserID: user.ID, - RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: ptr.To(pak.ID), - Hostinfo: &hostInfo2, - } - db.DB.Save(&node2) - - sendUpdate, err = db.SaveNodeRoutes(&node2) - c.Assert(err, check.IsNil) - c.Assert(sendUpdate, check.Equals, false) - - _, err = db.enableRoutes(&node2, route2) - c.Assert(err, check.IsNil) - - enabledRoutes1, err := db.GetEnabledRoutes(&node1) - c.Assert(err, check.IsNil) - c.Assert(len(enabledRoutes1), check.Equals, 2) - - enabledRoutes2, err := db.GetEnabledRoutes(&node2) - c.Assert(err, check.IsNil) - c.Assert(len(enabledRoutes2), check.Equals, 1) - - routes, err := db.GetNodePrimaryRoutes(&node1) - c.Assert(err, check.IsNil) - c.Assert(len(routes), check.Equals, 2) - - routes, err = db.GetNodePrimaryRoutes(&node2) - c.Assert(err, check.IsNil) - c.Assert(len(routes), check.Equals, 0) -} - -func (s *Suite) TestDeleteRoutes(c *check.C) { - user, err := db.CreateUser(types.User{Name: "test"}) - c.Assert(err, check.IsNil) - - pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) - c.Assert(err, check.IsNil) - - _, err = db.getNode(types.UserID(user.ID), "test_enable_route_node") - c.Assert(err, check.NotNil) - - prefix, err := netip.ParsePrefix( - "10.0.0.0/24", - ) - c.Assert(err, check.IsNil) - - prefix2, err := netip.ParsePrefix( - "150.0.10.0/25", - ) - c.Assert(err, check.IsNil) - - hostInfo1 := tailcfg.Hostinfo{ - RoutableIPs: []netip.Prefix{prefix, prefix2}, - } - - now := time.Now() - node1 := types.Node{ - ID: 1, - Hostname: "test_enable_route_node", - UserID: user.ID, - RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: ptr.To(pak.ID), - Hostinfo: &hostInfo1, - LastSeen: &now, - } - trx := db.DB.Save(&node1) - c.Assert(trx.Error, check.IsNil) - - sendUpdate, err := db.SaveNodeRoutes(&node1) - c.Assert(err, check.IsNil) - c.Assert(sendUpdate, check.Equals, false) - - _, err = db.enableRoutes(&node1, prefix) - c.Assert(err, check.IsNil) - - _, err = db.enableRoutes(&node1, prefix2) - c.Assert(err, check.IsNil) - - routes, err := db.GetNodeRoutes(&node1) - c.Assert(err, check.IsNil) - - // TODO(kradalby): check stateupdate - _, err = db.DeleteRoute(uint64(routes[0].ID), nil) - c.Assert(err, check.IsNil) - - enabledRoutes1, err := db.GetEnabledRoutes(&node1) - c.Assert(err, check.IsNil) - c.Assert(len(enabledRoutes1), check.Equals, 1) -} - -var ( - ipp = func(s string) netip.Prefix { return netip.MustParsePrefix(s) } - np = func(nid types.NodeID) *types.Node { - return &types.Node{ID: nid} - } -) - -var r = func(id uint, nid types.NodeID, prefix netip.Prefix, enabled, primary bool) types.Route { - return types.Route{ - Model: gorm.Model{ - ID: id, - }, - Node: np(nid), - Prefix: prefix, - Enabled: enabled, - IsPrimary: primary, - } -} - -var rp = func(id uint, nid types.NodeID, prefix netip.Prefix, enabled, primary bool) *types.Route { - ro := r(id, nid, prefix, enabled, primary) - return &ro -} - -func dbForTest(t *testing.T, testName string) *HSDatabase { - t.Helper() - - tmpDir, err := os.MkdirTemp("", testName) - if err != nil { - t.Fatalf("creating tempdir: %s", err) - } - - dbPath := tmpDir + "/headscale_test.db" - - db, err = NewHeadscaleDatabase( - types.DatabaseConfig{ - Type: "sqlite3", - Sqlite: types.SqliteConfig{ - Path: dbPath, - }, - }, - "", - emptyCache(), - ) - if err != nil { - t.Fatalf("setting up database: %s", err) - } - - t.Logf("database set up at: %s", dbPath) - - return db -} - -func TestFailoverNodeRoutesIfNecessary(t *testing.T) { - su := func(nids ...types.NodeID) *types.StateUpdate { - return &types.StateUpdate{ - ChangeNodes: nids, - } - } - tests := []struct { - name string - nodes types.Nodes - routes types.Routes - isConnected []map[types.NodeID]bool - want []*types.StateUpdate - wantErr bool - }{ - { - name: "n1-down-n2-down-n1-up", - nodes: types.Nodes{ - np(1), - np(2), - np(1), - }, - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(2, 2, ipp("10.0.0.0/24"), true, false), - }, - isConnected: []map[types.NodeID]bool{ - // n1 goes down - { - 1: false, - 2: true, - }, - // n2 goes down - { - 1: false, - 2: false, - }, - // n1 comes up - { - 1: true, - 2: false, - }, - }, - want: []*types.StateUpdate{ - // route changes from 1 -> 2 - su(1, 2), - // both down, no change - nil, - // route changes from 2 -> 1 - su(1, 2), - }, - }, - { - name: "n1-recon-n2-down-n1-recon-n2-up", - nodes: types.Nodes{ - np(1), - np(2), - np(1), - np(2), - }, - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(2, 2, ipp("10.0.0.0/24"), true, false), - }, - isConnected: []map[types.NodeID]bool{ - // n1 up recon = noop - { - 1: true, - 2: true, - }, - // n2 goes down - { - 1: true, - 2: false, - }, - // n1 up recon = noop - { - 1: true, - 2: false, - }, - // n2 comes back up - { - 1: true, - 2: false, - }, - }, - want: []*types.StateUpdate{ - nil, - nil, - nil, - nil, - }, - }, - { - name: "n1-recon-n2-down-n1-recon-n2-up", - nodes: types.Nodes{ - np(1), - np(1), - np(3), - np(3), - np(2), - np(1), - }, - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(2, 2, ipp("10.0.0.0/24"), true, false), - r(3, 3, ipp("10.0.0.0/24"), true, false), - }, - isConnected: []map[types.NodeID]bool{ - // n1 goes down - { - 1: false, - 2: false, - 3: true, - }, - // n1 comes up - { - 1: true, - 2: false, - 3: true, - }, - // n3 goes down - { - 1: true, - 2: false, - 3: false, - }, - // n3 comes up - { - 1: true, - 2: false, - 3: true, - }, - // n2 comes up - { - 1: true, - 2: true, - 3: true, - }, - // n1 goes down - { - 1: false, - 2: true, - 3: true, - }, - }, - want: []*types.StateUpdate{ - su(1, 3), // n1 -> n3 - nil, - su(1, 3), // n3 -> n1 - nil, - nil, - su(1, 2), // n1 -> n2 - }, - }, - { - name: "n1-recon-n2-dis-n3-take", - nodes: types.Nodes{ - np(1), - np(3), - }, - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(2, 2, ipp("10.0.0.0/24"), false, false), - r(3, 3, ipp("10.0.0.0/24"), true, false), - }, - isConnected: []map[types.NodeID]bool{ - // n1 goes down - { - 1: false, - 2: true, - 3: true, - }, - // n3 goes down - { - 1: false, - 2: true, - 3: false, - }, - }, - want: []*types.StateUpdate{ - su(1, 3), // n1 -> n3 - nil, - }, - }, - { - name: "multi-n1-oneforeach-n2-n3", - nodes: types.Nodes{ - np(1), - }, - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(4, 1, ipp("10.1.0.0/24"), true, true), - r(2, 2, ipp("10.0.0.0/24"), true, false), - r(3, 3, ipp("10.1.0.0/24"), true, false), - }, - isConnected: []map[types.NodeID]bool{ - // n1 goes down - { - 1: false, - 2: true, - 3: true, - }, - }, - want: []*types.StateUpdate{ - su(1, 2, 3), // n1 -> n2,n3 - }, - }, - { - name: "multi-n1-onefor-n2-disabled-n3", - nodes: types.Nodes{ - np(1), - }, - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(4, 1, ipp("10.1.0.0/24"), true, true), - r(2, 2, ipp("10.0.0.0/24"), true, false), - r(3, 3, ipp("10.1.0.0/24"), false, false), - }, - isConnected: []map[types.NodeID]bool{ - // n1 goes down - { - 1: false, - 2: true, - 3: true, - }, - }, - want: []*types.StateUpdate{ - su(1, 2), // n1 -> n2, n3 is not enabled - }, - }, - { - name: "multi-n1-onefor-n2-offline-n3", - nodes: types.Nodes{ - np(1), - }, - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(4, 1, ipp("10.1.0.0/24"), true, true), - r(2, 2, ipp("10.0.0.0/24"), true, false), - r(3, 3, ipp("10.1.0.0/24"), true, false), - }, - isConnected: []map[types.NodeID]bool{ - // n1 goes down - { - 1: false, - 2: true, - 3: false, - }, - }, - want: []*types.StateUpdate{ - su(1, 2), // n1 -> n2, n3 is offline - }, - }, - { - name: "multi-n2-back-to-multi-n1", - nodes: types.Nodes{ - np(1), - }, - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, false), - r(4, 1, ipp("10.1.0.0/24"), true, true), - r(2, 2, ipp("10.0.0.0/24"), true, true), - r(3, 3, ipp("10.1.0.0/24"), true, false), - }, - isConnected: []map[types.NodeID]bool{ - // n1 goes down - { - 1: true, - 2: false, - 3: true, - }, - }, - want: []*types.StateUpdate{ - su(1, 2), // n2 -> n1 - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if (len(tt.isConnected) != len(tt.want)) && len(tt.want) != len(tt.nodes) { - t.Fatalf("nodes (%d), isConnected updates (%d), wants (%d) must be equal", len(tt.nodes), len(tt.isConnected), len(tt.want)) - } - - db := dbForTest(t, tt.name) - - user := types.User{Name: tt.name} - if err := db.DB.Save(&user).Error; err != nil { - t.Fatalf("failed to create user: %s", err) - } - - for _, route := range tt.routes { - route.Node.User = user - if err := db.DB.Save(&route.Node).Error; err != nil { - t.Fatalf("failed to create node: %s", err) - } - if err := db.DB.Save(&route).Error; err != nil { - t.Fatalf("failed to create route: %s", err) - } - } - - for step := range len(tt.isConnected) { - node := tt.nodes[step] - isConnected := tt.isConnected[step] - want := tt.want[step] - - got, err := Write(db.DB, func(tx *gorm.DB) (*types.StateUpdate, error) { - return FailoverNodeRoutesIfNecessary(tx, smap(isConnected), node) - }) - - if (err != nil) != tt.wantErr { - t.Errorf("failoverRoute() error = %v, wantErr %v", err, tt.wantErr) - - return - } - - if diff := cmp.Diff(want, got, cmpopts.IgnoreFields(types.StateUpdate{}, "Type", "Message")); diff != "" { - t.Errorf("failoverRoute() unexpected result (-want +got):\n%s", diff) - } - } - }) - } -} - -func TestFailoverRouteTx(t *testing.T) { - tests := []struct { - name string - failingRoute types.Route - routes types.Routes - isConnected map[types.NodeID]bool - want []types.NodeID - wantErr bool - }{ - { - name: "no-route", - failingRoute: types.Route{}, - routes: types.Routes{}, - want: nil, - wantErr: false, - }, - { - name: "no-prime", - failingRoute: types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{}, - IsPrimary: false, - }, - routes: types.Routes{}, - want: nil, - wantErr: false, - }, - { - name: "exit-node", - failingRoute: types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("0.0.0.0/0"), - Node: &types.Node{}, - IsPrimary: true, - }, - routes: types.Routes{}, - want: nil, - wantErr: false, - }, - { - name: "no-failover-single-route", - failingRoute: types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - }, - routes: types.Routes{ - types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - }, - }, - want: nil, - wantErr: false, - }, - { - name: "failover-primary", - failingRoute: types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - Enabled: true, - }, - routes: types.Routes{ - types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - Enabled: true, - }, - types.Route{ - Model: gorm.Model{ - ID: 2, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 2, - }, - IsPrimary: false, - Enabled: true, - }, - }, - isConnected: map[types.NodeID]bool{ - 1: false, - 2: true, - }, - want: []types.NodeID{ - 1, - 2, - }, - wantErr: false, - }, - { - name: "failover-none-primary", - failingRoute: types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: false, - Enabled: true, - }, - routes: types.Routes{ - types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - Enabled: true, - }, - types.Route{ - Model: gorm.Model{ - ID: 2, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 2, - }, - IsPrimary: false, - Enabled: true, - }, - }, - want: nil, - wantErr: false, - }, - { - name: "failover-primary-multi-route", - failingRoute: types.Route{ - Model: gorm.Model{ - ID: 2, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 2, - }, - IsPrimary: true, - Enabled: true, - }, - routes: types.Routes{ - types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: false, - Enabled: true, - }, - types.Route{ - Model: gorm.Model{ - ID: 2, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 2, - }, - IsPrimary: true, - Enabled: true, - }, - types.Route{ - Model: gorm.Model{ - ID: 3, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 3, - }, - IsPrimary: false, - Enabled: true, - }, - }, - isConnected: map[types.NodeID]bool{ - 1: true, - 2: true, - 3: true, - }, - want: []types.NodeID{ - 2, 1, - }, - wantErr: false, - }, - { - name: "failover-primary-no-online", - failingRoute: types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - Enabled: true, - }, - routes: types.Routes{ - types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - Enabled: true, - }, - // Offline - types.Route{ - Model: gorm.Model{ - ID: 2, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 4, - }, - IsPrimary: false, - Enabled: true, - }, - }, - isConnected: map[types.NodeID]bool{ - 1: true, - 4: false, - }, - want: nil, - wantErr: false, - }, - { - name: "failover-primary-one-not-online", - failingRoute: types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - Enabled: true, - }, - routes: types.Routes{ - types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - Enabled: true, - }, - // Offline - types.Route{ - Model: gorm.Model{ - ID: 2, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 4, - }, - IsPrimary: false, - Enabled: true, - }, - types.Route{ - Model: gorm.Model{ - ID: 3, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 2, - }, - IsPrimary: true, - Enabled: true, - }, - }, - isConnected: map[types.NodeID]bool{ - 1: false, - 2: true, - 4: false, - }, - want: []types.NodeID{ - 1, - 2, - }, - wantErr: false, - }, - { - name: "failover-primary-none-enabled", - failingRoute: types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - Enabled: true, - }, - routes: types.Routes{ - types.Route{ - Model: gorm.Model{ - ID: 1, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 1, - }, - IsPrimary: true, - Enabled: true, - }, - // not enabled - types.Route{ - Model: gorm.Model{ - ID: 2, - }, - Prefix: ipp("10.0.0.0/24"), - Node: &types.Node{ - ID: 2, - }, - IsPrimary: false, - Enabled: false, - }, - }, - want: nil, - wantErr: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - db := dbForTest(t, tt.name) - user := types.User{Name: "test"} - if err := db.DB.Save(&user).Error; err != nil { - t.Fatalf("failed to create user: %s", err) - } - - for _, route := range tt.routes { - route.Node.User = user - if err := db.DB.Save(&route.Node).Error; err != nil { - t.Fatalf("failed to create node: %s", err) - } - if err := db.DB.Save(&route).Error; err != nil { - t.Fatalf("failed to create route: %s", err) - } - } - - got, err := Write(db.DB, func(tx *gorm.DB) ([]types.NodeID, error) { - return failoverRouteTx(tx, smap(tt.isConnected), &tt.failingRoute) - }) - - if (err != nil) != tt.wantErr { - t.Errorf("failoverRoute() error = %v, wantErr %v", err, tt.wantErr) - - return - } - - if diff := cmp.Diff(tt.want, got, util.Comparers...); diff != "" { - t.Errorf("failoverRoute() unexpected result (-want +got):\n%s", diff) - } - }) - } -} - -func TestFailoverRoute(t *testing.T) { - r := func(id uint, nid types.NodeID, prefix netip.Prefix, enabled, primary bool) types.Route { - return types.Route{ - Model: gorm.Model{ - ID: id, - }, - Node: &types.Node{ - ID: nid, - }, - Prefix: prefix, - Enabled: enabled, - IsPrimary: primary, - } - } - rp := func(id uint, nid types.NodeID, prefix netip.Prefix, enabled, primary bool) *types.Route { - ro := r(id, nid, prefix, enabled, primary) - return &ro - } - tests := []struct { - name string - failingRoute types.Route - routes types.Routes - isConnected map[types.NodeID]bool - want *failover - }{ - { - name: "no-route", - failingRoute: types.Route{}, - routes: types.Routes{}, - want: nil, - }, - { - name: "no-prime", - failingRoute: r(1, 1, ipp("10.0.0.0/24"), false, false), - - routes: types.Routes{}, - want: nil, - }, - { - name: "exit-node", - failingRoute: r(1, 1, ipp("0.0.0.0/0"), false, true), - routes: types.Routes{}, - want: nil, - }, - { - name: "no-failover-single-route", - failingRoute: r(1, 1, ipp("10.0.0.0/24"), false, true), - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), false, true), - }, - want: nil, - }, - { - name: "failover-primary", - failingRoute: r(1, 1, ipp("10.0.0.0/24"), true, true), - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(2, 2, ipp("10.0.0.0/24"), true, false), - }, - isConnected: map[types.NodeID]bool{ - 1: false, - 2: true, - }, - want: &failover{ - old: rp(1, 1, ipp("10.0.0.0/24"), true, false), - new: rp(2, 2, ipp("10.0.0.0/24"), true, true), - }, - }, - { - name: "failover-none-primary", - failingRoute: r(1, 1, ipp("10.0.0.0/24"), true, false), - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(2, 2, ipp("10.0.0.0/24"), true, false), - }, - want: nil, - }, - { - name: "failover-primary-multi-route", - failingRoute: r(2, 2, ipp("10.0.0.0/24"), true, true), - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, false), - r(2, 2, ipp("10.0.0.0/24"), true, true), - r(3, 3, ipp("10.0.0.0/24"), true, false), - }, - isConnected: map[types.NodeID]bool{ - 1: true, - 2: true, - 3: true, - }, - want: &failover{ - old: rp(2, 2, ipp("10.0.0.0/24"), true, false), - new: rp(1, 1, ipp("10.0.0.0/24"), true, true), - }, - }, - { - name: "failover-primary-no-online", - failingRoute: r(1, 1, ipp("10.0.0.0/24"), true, true), - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(2, 4, ipp("10.0.0.0/24"), true, false), - }, - isConnected: map[types.NodeID]bool{ - 1: true, - 4: false, - }, - want: nil, - }, - { - name: "failover-primary-one-not-online", - failingRoute: r(1, 1, ipp("10.0.0.0/24"), true, true), - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, true), - r(2, 4, ipp("10.0.0.0/24"), true, false), - r(3, 2, ipp("10.0.0.0/24"), true, false), - }, - isConnected: map[types.NodeID]bool{ - 1: false, - 2: true, - 4: false, - }, - want: &failover{ - old: rp(1, 1, ipp("10.0.0.0/24"), true, false), - new: rp(3, 2, ipp("10.0.0.0/24"), true, true), - }, - }, - { - name: "failover-primary-none-enabled", - failingRoute: r(1, 1, ipp("10.0.0.0/24"), true, true), - routes: types.Routes{ - r(1, 1, ipp("10.0.0.0/24"), true, false), - r(2, 2, ipp("10.0.0.0/24"), false, true), - }, - want: nil, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotf := failoverRoute(smap(tt.isConnected), &tt.failingRoute, tt.routes) - - if tt.want == nil && gotf != nil { - t.Fatalf("expected nil, got %+v", gotf) - } - - if gotf == nil && tt.want != nil { - t.Fatalf("expected %+v, got nil", tt.want) - } - - if tt.want != nil && gotf != nil { - want := map[string]*types.Route{ - "new": tt.want.new, - "old": tt.want.old, - } - - got := map[string]*types.Route{ - "new": gotf.new, - "old": gotf.old, - } - - if diff := cmp.Diff(want, got, util.Comparers...); diff != "" { - t.Fatalf("failoverRoute unexpected result (-want +got):\n%s", diff) - } - } - }) - } -} diff --git a/hscontrol/debug.go b/hscontrol/debug.go index f509a43c..d60aadbf 100644 --- a/hscontrol/debug.go +++ b/hscontrol/debug.go @@ -100,6 +100,11 @@ func (h *Headscale) debugHTTPServer() *http.Server { w.WriteHeader(http.StatusOK) w.Write(registrationsJSON) })) + debug.Handle("routes", "Routes", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + w.Write([]byte(h.primaryRoutes.String())) + })) err := statsviz.Register(debugMux) if err == nil { diff --git a/hscontrol/grpcv1.go b/hscontrol/grpcv1.go index 7368083c..57b46889 100644 --- a/hscontrol/grpcv1.go +++ b/hscontrol/grpcv1.go @@ -6,7 +6,9 @@ import ( "errors" "fmt" "io" + "net/netip" "os" + "slices" "sort" "strings" "time" @@ -18,6 +20,7 @@ import ( "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/timestamppb" "gorm.io/gorm" + "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" "tailscale.com/types/key" @@ -326,6 +329,51 @@ func (api headscaleV1APIServer) SetTags( return &v1.SetTagsResponse{Node: node.Proto()}, nil } +func (api headscaleV1APIServer) SetApprovedRoutes( + ctx context.Context, + request *v1.SetApprovedRoutesRequest, +) (*v1.SetApprovedRoutesResponse, error) { + var routes []netip.Prefix + for _, route := range request.GetRoutes() { + prefix, err := netip.ParsePrefix(route) + if err != nil { + return nil, fmt.Errorf("parsing route: %w", err) + } + + // If the prefix is an exit route, add both. The client expect both + // to annotate the node as an exit node. + if prefix == tsaddr.AllIPv4() || prefix == tsaddr.AllIPv6() { + routes = append(routes, tsaddr.AllIPv4(), tsaddr.AllIPv6()) + } else { + routes = append(routes, prefix) + } + } + slices.SortFunc(routes, util.ComparePrefix) + slices.Compact(routes) + + node, err := db.Write(api.h.db.DB, func(tx *gorm.DB) (*types.Node, error) { + err := db.SetApprovedRoutes(tx, types.NodeID(request.GetNodeId()), routes) + if err != nil { + return nil, err + } + + return db.GetNodeByID(tx, types.NodeID(request.GetNodeId())) + }) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + if api.h.primaryRoutes.SetRoutes(node.ID, node.SubnetRoutes()...) { + ctx := types.NotifyCtx(ctx, "poll-primary-change", node.Hostname) + api.h.nodeNotifier.NotifyAll(ctx, types.UpdateFull()) + } else { + ctx = types.NotifyCtx(ctx, "cli-approveroutes", node.Hostname) + api.h.nodeNotifier.NotifyWithIgnore(ctx, types.UpdatePeerChanged(node.ID), node.ID) + } + + return &v1.SetApprovedRoutesResponse{Node: node.Proto()}, nil +} + func validateTag(tag string) error { if strings.Index(tag, "tag:") != 0 { return errors.New("tag must start with the string 'tag:'") @@ -348,10 +396,7 @@ func (api headscaleV1APIServer) DeleteNode( return nil, err } - changedNodes, err := api.h.db.DeleteNode( - node, - api.h.nodeNotifier.LikelyConnectedMap(), - ) + err = api.h.db.DeleteNode(node) if err != nil { return nil, err } @@ -359,10 +404,6 @@ func (api headscaleV1APIServer) DeleteNode( ctx = types.NotifyCtx(ctx, "cli-deletenode", node.Hostname) api.h.nodeNotifier.NotifyAll(ctx, types.UpdatePeerRemoved(node.ID)) - if changedNodes != nil { - api.h.nodeNotifier.NotifyAll(ctx, types.UpdatePeerChanged(changedNodes...)) - } - return &v1.DeleteNodeResponse{}, nil } @@ -533,100 +574,6 @@ func (api headscaleV1APIServer) BackfillNodeIPs( return &v1.BackfillNodeIPsResponse{Changes: changes}, nil } -func (api headscaleV1APIServer) GetRoutes( - ctx context.Context, - request *v1.GetRoutesRequest, -) (*v1.GetRoutesResponse, error) { - routes, err := db.Read(api.h.db.DB, func(rx *gorm.DB) (types.Routes, error) { - return db.GetRoutes(rx) - }) - if err != nil { - return nil, err - } - - return &v1.GetRoutesResponse{ - Routes: types.Routes(routes).Proto(), - }, nil -} - -func (api headscaleV1APIServer) EnableRoute( - ctx context.Context, - request *v1.EnableRouteRequest, -) (*v1.EnableRouteResponse, error) { - update, err := db.Write(api.h.db.DB, func(tx *gorm.DB) (*types.StateUpdate, error) { - return db.EnableRoute(tx, request.GetRouteId()) - }) - if err != nil { - return nil, err - } - - if update != nil { - ctx := types.NotifyCtx(ctx, "cli-enableroute", "unknown") - api.h.nodeNotifier.NotifyAll( - ctx, *update) - } - - return &v1.EnableRouteResponse{}, nil -} - -func (api headscaleV1APIServer) DisableRoute( - ctx context.Context, - request *v1.DisableRouteRequest, -) (*v1.DisableRouteResponse, error) { - update, err := db.Write(api.h.db.DB, func(tx *gorm.DB) ([]types.NodeID, error) { - return db.DisableRoute(tx, request.GetRouteId(), api.h.nodeNotifier.LikelyConnectedMap()) - }) - if err != nil { - return nil, err - } - - if update != nil { - ctx := types.NotifyCtx(ctx, "cli-disableroute", "unknown") - api.h.nodeNotifier.NotifyAll(ctx, types.UpdatePeerChanged(update...)) - } - - return &v1.DisableRouteResponse{}, nil -} - -func (api headscaleV1APIServer) GetNodeRoutes( - ctx context.Context, - request *v1.GetNodeRoutesRequest, -) (*v1.GetNodeRoutesResponse, error) { - node, err := api.h.db.GetNodeByID(types.NodeID(request.GetNodeId())) - if err != nil { - return nil, err - } - - routes, err := api.h.db.GetNodeRoutes(node) - if err != nil { - return nil, err - } - - return &v1.GetNodeRoutesResponse{ - Routes: types.Routes(routes).Proto(), - }, nil -} - -func (api headscaleV1APIServer) DeleteRoute( - ctx context.Context, - request *v1.DeleteRouteRequest, -) (*v1.DeleteRouteResponse, error) { - isConnected := api.h.nodeNotifier.LikelyConnectedMap() - update, err := db.Write(api.h.db.DB, func(tx *gorm.DB) ([]types.NodeID, error) { - return db.DeleteRoute(tx, request.GetRouteId(), isConnected) - }) - if err != nil { - return nil, err - } - - if update != nil { - ctx := types.NotifyCtx(ctx, "cli-deleteroute", "unknown") - api.h.nodeNotifier.NotifyAll(ctx, types.UpdatePeerChanged(update...)) - } - - return &v1.DeleteRouteResponse{}, nil -} - func (api headscaleV1APIServer) CreateApiKey( ctx context.Context, request *v1.CreateApiKeyRequest, diff --git a/hscontrol/mapper/mapper.go b/hscontrol/mapper/mapper.go index 6821d5b6..705596cd 100644 --- a/hscontrol/mapper/mapper.go +++ b/hscontrol/mapper/mapper.go @@ -18,6 +18,7 @@ import ( "github.com/juanfont/headscale/hscontrol/db" "github.com/juanfont/headscale/hscontrol/notifier" "github.com/juanfont/headscale/hscontrol/policy" + "github.com/juanfont/headscale/hscontrol/routes" "github.com/juanfont/headscale/hscontrol/types" "github.com/juanfont/headscale/hscontrol/util" "github.com/klauspost/compress/zstd" @@ -56,6 +57,7 @@ type Mapper struct { derpMap *tailcfg.DERPMap notif *notifier.Notifier polMan policy.PolicyManager + primary *routes.PrimaryRoutes uid string created time.Time @@ -73,6 +75,7 @@ func NewMapper( derpMap *tailcfg.DERPMap, notif *notifier.Notifier, polMan policy.PolicyManager, + primary *routes.PrimaryRoutes, ) *Mapper { uid, _ := util.GenerateRandomStringDNSSafe(mapperIDLength) @@ -82,6 +85,7 @@ func NewMapper( derpMap: derpMap, notif: notif, polMan: polMan, + primary: primary, uid: uid, created: time.Now(), @@ -97,15 +101,22 @@ func generateUserProfiles( node *types.Node, peers types.Nodes, ) []tailcfg.UserProfile { - userMap := make(map[uint]types.User) - userMap[node.User.ID] = node.User + userMap := make(map[uint]*types.User) + ids := make([]uint, 0, len(userMap)) + userMap[node.User.ID] = &node.User + ids = append(ids, node.User.ID) for _, peer := range peers { - userMap[peer.User.ID] = peer.User // not worth checking if already is there + userMap[peer.User.ID] = &peer.User + ids = append(ids, peer.User.ID) } + slices.Sort(ids) + slices.Compact(ids) var profiles []tailcfg.UserProfile - for _, user := range userMap { - profiles = append(profiles, user.TailscaleUserProfile()) + for _, id := range ids { + if userMap[id] != nil { + profiles = append(profiles, userMap[id].TailscaleUserProfile()) + } } return profiles @@ -166,6 +177,7 @@ func (m *Mapper) fullMapResponse( resp, true, // full change m.polMan, + m.primary, node, capVer, peers, @@ -271,6 +283,7 @@ func (m *Mapper) PeerChangedResponse( &resp, false, // partial change m.polMan, + m.primary, node, mapRequest.Version, changedNodes, @@ -299,7 +312,7 @@ func (m *Mapper) PeerChangedResponse( // Add the node itself, it might have changed, and particularly // if there are no patches or changes, this is a self update. - tailnode, err := tailNode(node, mapRequest.Version, m.polMan, m.cfg) + tailnode, err := tailNode(node, mapRequest.Version, m.polMan, m.primary, m.cfg) if err != nil { return nil, err } @@ -446,7 +459,7 @@ func (m *Mapper) baseWithConfigMapResponse( ) (*tailcfg.MapResponse, error) { resp := m.baseMapResponse() - tailnode, err := tailNode(node, capVer, m.polMan, m.cfg) + tailnode, err := tailNode(node, capVer, m.polMan, m.primary, m.cfg) if err != nil { return nil, err } @@ -500,6 +513,7 @@ func appendPeerChanges( fullChange bool, polMan policy.PolicyManager, + primary *routes.PrimaryRoutes, node *types.Node, capVer tailcfg.CapabilityVersion, changed types.Nodes, @@ -522,7 +536,7 @@ func appendPeerChanges( dnsConfig := generateDNSConfig(cfg, node) - tailPeers, err := tailNodes(changed, capVer, polMan, cfg) + tailPeers, err := tailNodes(changed, capVer, polMan, primary, cfg) if err != nil { return err } diff --git a/hscontrol/mapper/mapper_test.go b/hscontrol/mapper/mapper_test.go index 955edab9..51c09411 100644 --- a/hscontrol/mapper/mapper_test.go +++ b/hscontrol/mapper/mapper_test.go @@ -6,12 +6,11 @@ import ( "testing" "time" - "github.com/davecgh/go-spew/spew" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/juanfont/headscale/hscontrol/policy" + "github.com/juanfont/headscale/hscontrol/routes" "github.com/juanfont/headscale/hscontrol/types" - "gopkg.in/check.v1" "gorm.io/gorm" "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" @@ -24,51 +23,6 @@ var iap = func(ipStr string) *netip.Addr { return &ip } -func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) { - mach := func(hostname, username string, userid uint) *types.Node { - return &types.Node{ - Hostname: hostname, - UserID: userid, - User: types.User{ - Model: gorm.Model{ - ID: userid, - }, - Name: username, - }, - } - } - - nodeInShared1 := mach("test_get_shared_nodes_1", "user1", 1) - nodeInShared2 := mach("test_get_shared_nodes_2", "user2", 2) - nodeInShared3 := mach("test_get_shared_nodes_3", "user3", 3) - node2InShared1 := mach("test_get_shared_nodes_4", "user1", 1) - - userProfiles := generateUserProfiles( - nodeInShared1, - types.Nodes{ - nodeInShared2, nodeInShared3, node2InShared1, - }, - ) - - c.Assert(len(userProfiles), check.Equals, 3) - - users := []string{ - "user1", "user2", "user3", - } - - for _, user := range users { - found := false - for _, userProfile := range userProfiles { - if userProfile.DisplayName == user { - found = true - - break - } - } - c.Assert(found, check.Equals, true) - } -} - func TestDNSConfigMapResponse(t *testing.T) { tests := []struct { magicDNS bool @@ -159,11 +113,11 @@ func Test_fullMapResponse(t *testing.T) { 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) - user1 := types.User{Model: gorm.Model{ID: 0}, Name: "mini"} - user2 := types.User{Model: gorm.Model{ID: 1}, Name: "peer2"} + user1 := types.User{Model: gorm.Model{ID: 1}, Name: "user1"} + user2 := types.User{Model: gorm.Model{ID: 2}, Name: "user2"} mini := &types.Node{ - ID: 0, + ID: 1, MachineKey: mustMK( "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", ), @@ -182,35 +136,22 @@ func Test_fullMapResponse(t *testing.T) { AuthKey: &types.PreAuthKey{}, LastSeen: &lastSeen, Expiry: &expire, - Hostinfo: &tailcfg.Hostinfo{}, - Routes: []types.Route{ - { - Prefix: tsaddr.AllIPv4(), - Advertised: true, - Enabled: true, - IsPrimary: false, - }, - { - Prefix: netip.MustParsePrefix("192.168.0.0/24"), - Advertised: true, - Enabled: true, - IsPrimary: true, - }, - { - Prefix: netip.MustParsePrefix("172.0.0.0/10"), - Advertised: true, - Enabled: false, - IsPrimary: true, + Hostinfo: &tailcfg.Hostinfo{ + RoutableIPs: []netip.Prefix{ + tsaddr.AllIPv4(), + netip.MustParsePrefix("192.168.0.0/24"), + netip.MustParsePrefix("172.0.0.0/10"), }, }, - CreatedAt: created, + ApprovedRoutes: []netip.Prefix{tsaddr.AllIPv4(), netip.MustParsePrefix("192.168.0.0/24")}, + CreatedAt: created, } tailMini := &tailcfg.Node{ - ID: 0, - StableID: "0", + ID: 1, + StableID: "1", Name: "mini", - User: 0, + User: tailcfg.UserID(user1.ID), Key: mustNK( "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", ), @@ -227,12 +168,17 @@ func Test_fullMapResponse(t *testing.T) { tsaddr.AllIPv4(), netip.MustParsePrefix("192.168.0.0/24"), }, - HomeDERP: 0, - LegacyDERPString: "127.3.3.40:0", - Hostinfo: hiview(tailcfg.Hostinfo{}), + HomeDERP: 0, + LegacyDERPString: "127.3.3.40:0", + Hostinfo: hiview(tailcfg.Hostinfo{ + RoutableIPs: []netip.Prefix{ + tsaddr.AllIPv4(), + netip.MustParsePrefix("192.168.0.0/24"), + netip.MustParsePrefix("172.0.0.0/10"), + }, + }), Created: created, Tags: []string{}, - PrimaryRoutes: []netip.Prefix{netip.MustParsePrefix("192.168.0.0/24")}, LastSeen: &lastSeen, MachineAuthorized: true, @@ -244,7 +190,7 @@ func Test_fullMapResponse(t *testing.T) { } peer1 := &types.Node{ - ID: 1, + ID: 2, MachineKey: mustMK( "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", ), @@ -257,20 +203,20 @@ func Test_fullMapResponse(t *testing.T) { IPv4: iap("100.64.0.2"), Hostname: "peer1", GivenName: "peer1", - UserID: user1.ID, - User: user1, + UserID: user2.ID, + User: user2, ForcedTags: []string{}, LastSeen: &lastSeen, Expiry: &expire, Hostinfo: &tailcfg.Hostinfo{}, - Routes: []types.Route{}, CreatedAt: created, } tailPeer1 := &tailcfg.Node{ - ID: 1, - StableID: "1", + ID: 2, + StableID: "2", Name: "peer1", + User: tailcfg.UserID(user2.ID), Key: mustNK( "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", ), @@ -288,7 +234,6 @@ func Test_fullMapResponse(t *testing.T) { Hostinfo: hiview(tailcfg.Hostinfo{}), Created: created, Tags: []string{}, - PrimaryRoutes: []netip.Prefix{}, LastSeen: &lastSeen, MachineAuthorized: true, @@ -299,30 +244,6 @@ func Test_fullMapResponse(t *testing.T) { }, } - peer2 := &types.Node{ - ID: 2, - MachineKey: mustMK( - "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", - ), - NodeKey: mustNK( - "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", - ), - DiscoKey: mustDK( - "discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", - ), - IPv4: iap("100.64.0.3"), - Hostname: "peer2", - GivenName: "peer2", - UserID: user2.ID, - User: user2, - ForcedTags: []string{}, - LastSeen: &lastSeen, - Expiry: &expire, - Hostinfo: &tailcfg.Hostinfo{}, - Routes: []types.Route{}, - CreatedAt: created, - } - tests := []struct { name string pol *policy.ACLPolicy @@ -364,7 +285,7 @@ func Test_fullMapResponse(t *testing.T) { Domain: "", CollectServices: "false", PacketFilter: []tailcfg.FilterRule{}, - UserProfiles: []tailcfg.UserProfile{{LoginName: "mini", DisplayName: "mini"}}, + UserProfiles: []tailcfg.UserProfile{{ID: tailcfg.UserID(user1.ID), LoginName: "user1", DisplayName: "user1"}}, SSHPolicy: &tailcfg.SSHPolicy{Rules: []*tailcfg.SSHRule{}}, ControlTime: &time.Time{}, Debug: &tailcfg.Debug{ @@ -398,9 +319,12 @@ func Test_fullMapResponse(t *testing.T) { Domain: "", CollectServices: "false", PacketFilter: []tailcfg.FilterRule{}, - UserProfiles: []tailcfg.UserProfile{{LoginName: "mini", DisplayName: "mini"}}, - SSHPolicy: &tailcfg.SSHPolicy{Rules: []*tailcfg.SSHRule{}}, - ControlTime: &time.Time{}, + UserProfiles: []tailcfg.UserProfile{ + {ID: tailcfg.UserID(user1.ID), LoginName: "user1", DisplayName: "user1"}, + {ID: tailcfg.UserID(user2.ID), LoginName: "user2", DisplayName: "user2"}, + }, + SSHPolicy: &tailcfg.SSHPolicy{Rules: []*tailcfg.SSHRule{}}, + ControlTime: &time.Time{}, Debug: &tailcfg.Debug{ DisableLogTail: true, }, @@ -410,6 +334,9 @@ func Test_fullMapResponse(t *testing.T) { { name: "with-pol-map-response", pol: &policy.ACLPolicy{ + Hosts: policy.Hosts{ + "mini": netip.MustParsePrefix("100.64.0.1/32"), + }, ACLs: []policy.ACL{ { Action: "accept", @@ -421,7 +348,6 @@ func Test_fullMapResponse(t *testing.T) { node: mini, peers: types.Nodes{ peer1, - peer2, }, derpMap: &tailcfg.DERPMap{}, cfg: &types.Config{ @@ -449,7 +375,8 @@ func Test_fullMapResponse(t *testing.T) { }, }, UserProfiles: []tailcfg.UserProfile{ - {LoginName: "mini", DisplayName: "mini"}, + {ID: tailcfg.UserID(user1.ID), LoginName: "user1", DisplayName: "user1"}, + {ID: tailcfg.UserID(user2.ID), LoginName: "user2", DisplayName: "user2"}, }, SSHPolicy: &tailcfg.SSHPolicy{Rules: []*tailcfg.SSHRule{}}, ControlTime: &time.Time{}, @@ -464,6 +391,12 @@ func Test_fullMapResponse(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { polMan, _ := policy.NewPolicyManagerForTest(tt.pol, []types.User{user1, user2}, append(tt.peers, tt.node)) + primary := routes.New() + + primary.SetRoutes(tt.node.ID, tt.node.SubnetRoutes()...) + for _, peer := range tt.peers { + primary.SetRoutes(peer.ID, peer.SubnetRoutes()...) + } mappy := NewMapper( nil, @@ -471,6 +404,7 @@ func Test_fullMapResponse(t *testing.T) { tt.derpMap, nil, polMan, + primary, ) got, err := mappy.fullMapResponse( @@ -485,8 +419,6 @@ func Test_fullMapResponse(t *testing.T) { return } - spew.Dump(got) - if diff := cmp.Diff( tt.want, got, diff --git a/hscontrol/mapper/tail.go b/hscontrol/mapper/tail.go index ee2fb980..4a285290 100644 --- a/hscontrol/mapper/tail.go +++ b/hscontrol/mapper/tail.go @@ -6,6 +6,7 @@ import ( "time" "github.com/juanfont/headscale/hscontrol/policy" + "github.com/juanfont/headscale/hscontrol/routes" "github.com/juanfont/headscale/hscontrol/types" "github.com/samber/lo" "tailscale.com/tailcfg" @@ -15,6 +16,7 @@ func tailNodes( nodes types.Nodes, capVer tailcfg.CapabilityVersion, polMan policy.PolicyManager, + primary *routes.PrimaryRoutes, cfg *types.Config, ) ([]*tailcfg.Node, error) { tNodes := make([]*tailcfg.Node, len(nodes)) @@ -24,6 +26,7 @@ func tailNodes( node, capVer, polMan, + primary, cfg, ) if err != nil { @@ -41,6 +44,7 @@ func tailNode( node *types.Node, capVer tailcfg.CapabilityVersion, polMan policy.PolicyManager, + primary *routes.PrimaryRoutes, cfg *types.Config, ) (*tailcfg.Node, error) { addrs := node.Prefixes() @@ -49,17 +53,8 @@ func tailNode( []netip.Prefix{}, addrs...) // we append the node own IP, as it is required by the clients - primaryPrefixes := []netip.Prefix{} - - for _, route := range node.Routes { - if route.Enabled { - if route.IsPrimary { - allowedIPs = append(allowedIPs, netip.Prefix(route.Prefix)) - primaryPrefixes = append(primaryPrefixes, netip.Prefix(route.Prefix)) - } else if route.IsExitRoute() { - allowedIPs = append(allowedIPs, netip.Prefix(route.Prefix)) - } - } + for _, route := range node.SubnetRoutes() { + allowedIPs = append(allowedIPs, netip.Prefix(route)) } var derp int @@ -103,6 +98,7 @@ func tailNode( Machine: node.MachineKey, DiscoKey: node.DiscoKey, Addresses: addrs, + PrimaryRoutes: primary.PrimaryRoutes(node.ID), AllowedIPs: allowedIPs, Endpoints: node.Endpoints, HomeDERP: derp, @@ -114,8 +110,6 @@ func tailNode( Tags: tags, - PrimaryRoutes: primaryPrefixes, - MachineAuthorized: !node.IsExpired(), Expired: node.IsExpired(), } diff --git a/hscontrol/mapper/tail_test.go b/hscontrol/mapper/tail_test.go index 4a149426..6a620467 100644 --- a/hscontrol/mapper/tail_test.go +++ b/hscontrol/mapper/tail_test.go @@ -9,6 +9,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/juanfont/headscale/hscontrol/policy" + "github.com/juanfont/headscale/hscontrol/routes" "github.com/juanfont/headscale/hscontrol/types" "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" @@ -72,7 +73,6 @@ func TestTailNode(t *testing.T) { LegacyDERPString: "127.3.3.40:0", Hostinfo: hiview(tailcfg.Hostinfo{}), Tags: []string{}, - PrimaryRoutes: []netip.Prefix{}, MachineAuthorized: true, CapMap: tailcfg.NodeCapMap{ @@ -107,28 +107,15 @@ func TestTailNode(t *testing.T) { AuthKey: &types.PreAuthKey{}, LastSeen: &lastSeen, Expiry: &expire, - Hostinfo: &tailcfg.Hostinfo{}, - Routes: []types.Route{ - { - Prefix: tsaddr.AllIPv4(), - Advertised: true, - Enabled: true, - IsPrimary: false, - }, - { - Prefix: netip.MustParsePrefix("192.168.0.0/24"), - Advertised: true, - Enabled: true, - IsPrimary: true, - }, - { - Prefix: netip.MustParsePrefix("172.0.0.0/10"), - Advertised: true, - Enabled: false, - IsPrimary: true, + Hostinfo: &tailcfg.Hostinfo{ + RoutableIPs: []netip.Prefix{ + tsaddr.AllIPv4(), + netip.MustParsePrefix("192.168.0.0/24"), + netip.MustParsePrefix("172.0.0.0/10"), }, }, - CreatedAt: created, + ApprovedRoutes: []netip.Prefix{tsaddr.AllIPv4(), netip.MustParsePrefix("192.168.0.0/24")}, + CreatedAt: created, }, pol: &policy.ACLPolicy{}, dnsConfig: &tailcfg.DNSConfig{}, @@ -159,8 +146,14 @@ func TestTailNode(t *testing.T) { }, HomeDERP: 0, LegacyDERPString: "127.3.3.40:0", - Hostinfo: hiview(tailcfg.Hostinfo{}), - Created: created, + Hostinfo: hiview(tailcfg.Hostinfo{ + RoutableIPs: []netip.Prefix{ + tsaddr.AllIPv4(), + netip.MustParsePrefix("192.168.0.0/24"), + netip.MustParsePrefix("172.0.0.0/10"), + }, + }), + Created: created, Tags: []string{}, @@ -187,15 +180,22 @@ func TestTailNode(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { polMan, _ := policy.NewPolicyManagerForTest(tt.pol, []types.User{}, types.Nodes{tt.node}) + primary := routes.New() cfg := &types.Config{ BaseDomain: tt.baseDomain, TailcfgDNSConfig: tt.dnsConfig, RandomizeClientPort: false, } + _ = primary.SetRoutes(tt.node.ID, tt.node.SubnetRoutes()...) + + // This is a hack to avoid having a second node to test the primary route. + // This should be baked into the test case proper if it is extended in the future. + _ = primary.SetRoutes(2, netip.MustParsePrefix("192.168.0.0/24")) got, err := tailNode( tt.node, 0, polMan, + primary, cfg, ) @@ -249,6 +249,7 @@ func TestNodeExpiry(t *testing.T) { node, 0, &policy.PolicyManagerV1{}, + nil, &types.Config{}, ) if err != nil { diff --git a/hscontrol/policy/acls.go b/hscontrol/policy/acls.go index 3841ec0a..eab7063b 100644 --- a/hscontrol/policy/acls.go +++ b/hscontrol/policy/acls.go @@ -243,6 +243,7 @@ func (pol *ACLPolicy) CompileFilterRules( // ReduceFilterRules takes a node and a set of rules and removes all rules and destinations // that are not relevant to that particular node. func ReduceFilterRules(node *types.Node, rules []tailcfg.FilterRule) []tailcfg.FilterRule { + // TODO(kradalby): Make this nil and not alloc unless needed ret := []tailcfg.FilterRule{} for _, rule := range rules { @@ -264,13 +265,11 @@ func ReduceFilterRules(node *types.Node, rules []tailcfg.FilterRule) []tailcfg.F // If the node exposes routes, ensure they are note removed // when the filters are reduced. - if node.Hostinfo != nil { - if len(node.Hostinfo.RoutableIPs) > 0 { - for _, routableIP := range node.Hostinfo.RoutableIPs { - if expanded.OverlapsPrefix(routableIP) { - dests = append(dests, dest) - continue DEST_LOOP - } + if len(node.SubnetRoutes()) > 0 { + for _, routableIP := range node.SubnetRoutes() { + if expanded.OverlapsPrefix(routableIP) { + dests = append(dests, dest) + continue DEST_LOOP } } } diff --git a/hscontrol/policy/acls_test.go b/hscontrol/policy/acls_test.go index 87da4062..a7b12b1d 100644 --- a/hscontrol/policy/acls_test.go +++ b/hscontrol/policy/acls_test.go @@ -2165,6 +2165,9 @@ func TestReduceFilterRules(t *testing.T) { netip.MustParsePrefix("10.33.0.0/16"), }, }, + ApprovedRoutes: []netip.Prefix{ + netip.MustParsePrefix("10.33.0.0/16"), + }, }, peers: types.Nodes{ &types.Node{ @@ -2292,6 +2295,7 @@ func TestReduceFilterRules(t *testing.T) { Hostinfo: &tailcfg.Hostinfo{ RoutableIPs: tsaddr.ExitRoutes(), }, + ApprovedRoutes: tsaddr.ExitRoutes(), }, peers: types.Nodes{ &types.Node{ @@ -2398,6 +2402,7 @@ func TestReduceFilterRules(t *testing.T) { Hostinfo: &tailcfg.Hostinfo{ RoutableIPs: tsaddr.ExitRoutes(), }, + ApprovedRoutes: tsaddr.ExitRoutes(), }, peers: types.Nodes{ &types.Node{ @@ -2513,6 +2518,10 @@ func TestReduceFilterRules(t *testing.T) { netip.MustParsePrefix("16.0.0.0/16"), }, }, + ApprovedRoutes: []netip.Prefix{ + netip.MustParsePrefix("8.0.0.0/16"), + netip.MustParsePrefix("16.0.0.0/16"), + }, }, peers: types.Nodes{ &types.Node{ @@ -2603,6 +2612,10 @@ func TestReduceFilterRules(t *testing.T) { netip.MustParsePrefix("16.0.0.0/8"), }, }, + ApprovedRoutes: []netip.Prefix{ + netip.MustParsePrefix("8.0.0.0/8"), + netip.MustParsePrefix("16.0.0.0/8"), + }, }, peers: types.Nodes{ &types.Node{ @@ -2683,7 +2696,8 @@ func TestReduceFilterRules(t *testing.T) { Hostinfo: &tailcfg.Hostinfo{ RoutableIPs: []netip.Prefix{netip.MustParsePrefix("172.16.0.0/24")}, }, - ForcedTags: []string{"tag:access-servers"}, + ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("172.16.0.0/24")}, + ForcedTags: []string{"tag:access-servers"}, }, peers: types.Nodes{ &types.Node{ @@ -3475,14 +3489,10 @@ func Test_getFilteredByACLPeers(t *testing.T) { IPv4: iap("100.64.0.2"), Hostname: "router", User: types.User{Name: "router"}, - Routes: types.Routes{ - types.Route{ - NodeID: 2, - Prefix: netip.MustParsePrefix("10.33.0.0/16"), - IsPrimary: true, - Enabled: true, - }, + Hostinfo: &tailcfg.Hostinfo{ + RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")}, }, + ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")}, }, }, rules: []tailcfg.FilterRule{ @@ -3508,14 +3518,10 @@ func Test_getFilteredByACLPeers(t *testing.T) { IPv4: iap("100.64.0.2"), Hostname: "router", User: types.User{Name: "router"}, - Routes: types.Routes{ - types.Route{ - NodeID: 2, - Prefix: netip.MustParsePrefix("10.33.0.0/16"), - IsPrimary: true, - Enabled: true, - }, + Hostinfo: &tailcfg.Hostinfo{ + RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")}, }, + ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")}, }, }, }, diff --git a/hscontrol/policy/matcher/matcher.go b/hscontrol/policy/matcher/matcher.go index 1905dad2..2b86416e 100644 --- a/hscontrol/policy/matcher/matcher.go +++ b/hscontrol/policy/matcher/matcher.go @@ -9,8 +9,8 @@ import ( ) type Match struct { - Srcs *netipx.IPSet - Dests *netipx.IPSet + srcs *netipx.IPSet + dests *netipx.IPSet } func MatchFromFilterRule(rule tailcfg.FilterRule) Match { @@ -42,16 +42,16 @@ func MatchFromStrings(sources, destinations []string) Match { destsSet, _ := dests.IPSet() match := Match{ - Srcs: srcsSet, - Dests: destsSet, + srcs: srcsSet, + dests: destsSet, } return match } -func (m *Match) SrcsContainsIPs(ips []netip.Addr) bool { +func (m *Match) SrcsContainsIPs(ips ...netip.Addr) bool { for _, ip := range ips { - if m.Srcs.Contains(ip) { + if m.srcs.Contains(ip) { return true } } @@ -59,9 +59,29 @@ func (m *Match) SrcsContainsIPs(ips []netip.Addr) bool { return false } -func (m *Match) DestsContainsIP(ips []netip.Addr) bool { +func (m *Match) DestsContainsIP(ips ...netip.Addr) bool { for _, ip := range ips { - if m.Dests.Contains(ip) { + if m.dests.Contains(ip) { + return true + } + } + + return false +} + +func (m *Match) SrcsOverlapsPrefixes(prefixes ...netip.Prefix) bool { + for _, prefix := range prefixes { + if m.srcs.ContainsPrefix(prefix) { + return true + } + } + + return false +} + +func (m *Match) DestsOverlapsPrefixes(prefixes ...netip.Prefix) bool { + for _, prefix := range prefixes { + if m.dests.ContainsPrefix(prefix) { return true } } diff --git a/hscontrol/policy/pm.go b/hscontrol/policy/pm.go index 4e10003e..980dc5aa 100644 --- a/hscontrol/policy/pm.go +++ b/hscontrol/policy/pm.go @@ -23,6 +23,9 @@ type PolicyManager interface { SetPolicy([]byte) (bool, error) SetUsers(users []types.User) (bool, error) SetNodes(nodes types.Nodes) (bool, error) + + // NodeCanApproveRoute reports whether the given node can approve the given route. + NodeCanApproveRoute(*types.Node, netip.Prefix) bool } func NewPolicyManagerFromPath(path string, users []types.User, nodes types.Nodes) (PolicyManager, error) { @@ -185,3 +188,32 @@ func (pm *PolicyManagerV1) ExpandAlias(alias string) (*netipx.IPSet, error) { } return ips, nil } + +func (pm *PolicyManagerV1) NodeCanApproveRoute(node *types.Node, route netip.Prefix) bool { + if pm.pol == nil { + return false + } + + pm.mu.Lock() + defer pm.mu.Unlock() + + approvers, _ := pm.pol.AutoApprovers.GetRouteApprovers(route) + + for _, approvedAlias := range approvers { + if approvedAlias == node.User.Username() { + return true + } else { + ips, err := pm.pol.ExpandAlias(pm.nodes, pm.users, approvedAlias) + if err != nil { + return false + } + + // approvedIPs should contain all of node's IPs if it matches the rule, so check for first + if ips.Contains(*node.IPv4) { + return true + } + } + } + + return false +} diff --git a/hscontrol/poll.go b/hscontrol/poll.go index 2df35c36..7d9e1ab4 100644 --- a/hscontrol/poll.go +++ b/hscontrol/poll.go @@ -7,16 +7,15 @@ import ( "net/http" "net/netip" "slices" - "strings" "time" - "github.com/juanfont/headscale/hscontrol/db" "github.com/juanfont/headscale/hscontrol/mapper" "github.com/juanfont/headscale/hscontrol/types" + "github.com/juanfont/headscale/hscontrol/util" "github.com/rs/zerolog/log" + "github.com/samber/lo" "github.com/sasha-s/go-deadlock" xslices "golang.org/x/exp/slices" - "gorm.io/gorm" "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" ) @@ -205,7 +204,15 @@ func (m *mapSession) serveLongPoll() { if m.h.nodeNotifier.RemoveNode(m.node.ID, m.ch) { // Failover the node's routes if any. m.h.updateNodeOnlineStatus(false, m.node) - m.pollFailoverRoutes("node closing connection", m.node) + + // When a node disconnects, and it causes the primary route map to change, + // send a full update to all nodes. + // TODO(kradalby): This can likely be made more effective, but likely most + // nodes has access to the same routes, so it might not be a big deal. + if m.h.primaryRoutes.SetRoutes(m.node.ID) { + ctx := types.NotifyCtx(context.Background(), "poll-primary-change", m.node.Hostname) + m.h.nodeNotifier.NotifyAll(ctx, types.UpdateFull()) + } } m.afterServeLongPoll() @@ -216,7 +223,10 @@ func (m *mapSession) serveLongPoll() { m.h.pollNetMapStreamWG.Add(1) defer m.h.pollNetMapStreamWG.Done() - m.pollFailoverRoutes("node connected", m.node) + if m.h.primaryRoutes.SetRoutes(m.node.ID, m.node.SubnetRoutes()...) { + ctx := types.NotifyCtx(context.Background(), "poll-primary-change", m.node.Hostname) + m.h.nodeNotifier.NotifyAll(ctx, types.UpdateFull()) + } // Upgrade the writer to a ResponseController rc := http.NewResponseController(m.w) @@ -383,22 +393,6 @@ func (m *mapSession) serveLongPoll() { } } -func (m *mapSession) pollFailoverRoutes(where string, node *types.Node) { - update, err := db.Write(m.h.db.DB, func(tx *gorm.DB) (*types.StateUpdate, error) { - return db.FailoverNodeRoutesIfNecessary(tx, m.h.nodeNotifier.LikelyConnectedMap(), node) - }) - if err != nil { - m.errf(err, fmt.Sprintf("failed to ensure failover routes, %s", where)) - - return - } - - if update != nil && !update.Empty() { - ctx := types.NotifyCtx(context.Background(), fmt.Sprintf("poll-%s-routes-ensurefailover", strings.ReplaceAll(where, " ", "-")), node.Hostname) - m.h.nodeNotifier.NotifyWithIgnore(ctx, *update, node.ID) - } -} - // updateNodeOnlineStatus records the last seen status of a node and notifies peers // about change in their online/offline status. // It takes a StateUpdateType of either StatePeerOnlineChanged or StatePeerOfflineChanged. @@ -414,15 +408,6 @@ func (h *Headscale) updateNodeOnlineStatus(online bool, node *types.Node) { // lastSeen is only relevant if the node is disconnected. node.LastSeen = &now change.LastSeen = &now - - err := h.db.Write(func(tx *gorm.DB) error { - return db.SetLastSeen(tx, node.ID, *node.LastSeen) - }) - if err != nil { - log.Error().Err(err).Msg("Cannot update node LastSeen") - - return - } } ctx := types.NotifyCtx(context.Background(), "poll-nodeupdate-onlinestatus", node.Hostname) @@ -471,36 +456,47 @@ func (m *mapSession) handleEndpointUpdate() { // If the hostinfo has changed, but not the routes, just update // hostinfo and let the function continue. if routesChanged { - var err error - _, err = m.h.db.SaveNodeRoutes(m.node) - if err != nil { - m.errf(err, "Error processing node routes") - http.Error(m.w, "", http.StatusInternalServerError) - mapResponseEndpointUpdates.WithLabelValues("error").Inc() - - return - } - - // TODO(kradalby): Only update the node that has actually changed + // TODO(kradalby): I am not sure if we need this? nodesChangedHook(m.h.db, m.h.polMan, m.h.nodeNotifier) - if m.h.polMan != nil { - // update routes with peer information - err := m.h.db.EnableAutoApprovedRoutes(m.h.polMan, m.node) - if err != nil { - m.errf(err, "Error running auto approved routes") - mapResponseEndpointUpdates.WithLabelValues("error").Inc() + // Take all the routes presented to us by the node and check + // if any of them should be auto approved by the policy. + // If any of them are, add them to the approved routes of the node. + // Keep all the old entries and compact the list to remove duplicates. + var newApproved []netip.Prefix + for _, route := range m.node.Hostinfo.RoutableIPs { + if m.h.polMan.NodeCanApproveRoute(m.node, route) { + newApproved = append(newApproved, route) + } + } + if newApproved != nil { + newApproved = append(newApproved, m.node.ApprovedRoutes...) + slices.SortFunc(newApproved, util.ComparePrefix) + slices.Compact(newApproved) + newApproved = lo.Filter(newApproved, func(route netip.Prefix, index int) bool { + return route.IsValid() + }) + m.node.ApprovedRoutes = newApproved + + if m.h.primaryRoutes.SetRoutes(m.node.ID, m.node.SubnetRoutes()...) { + ctx := types.NotifyCtx(m.ctx, "poll-primary-change", m.node.Hostname) + m.h.nodeNotifier.NotifyAll(ctx, types.UpdateFull()) + } else { + ctx := types.NotifyCtx(m.ctx, "cli-approveroutes", m.node.Hostname) + m.h.nodeNotifier.NotifyWithIgnore(ctx, types.UpdatePeerChanged(m.node.ID), m.node.ID) + + // TODO(kradalby): I am not sure if we need this? + // Send an update to the node itself with to ensure it + // has an updated packetfilter allowing the new route + // if it is defined in the ACL. + ctx = types.NotifyCtx(m.ctx, "poll-nodeupdate-self-hostinfochange", m.node.Hostname) + m.h.nodeNotifier.NotifyByNodeID( + ctx, + types.UpdateSelf(m.node.ID), + m.node.ID) } } - // Send an update to the node itself with to ensure it - // has an updated packetfilter allowing the new route - // if it is defined in the ACL. - ctx := types.NotifyCtx(context.Background(), "poll-nodeupdate-self-hostinfochange", m.node.Hostname) - m.h.nodeNotifier.NotifyByNodeID( - ctx, - types.UpdateSelf(m.node.ID), - m.node.ID) } // Check if there has been a change to Hostname and update them diff --git a/hscontrol/routes/primary.go b/hscontrol/routes/primary.go new file mode 100644 index 00000000..344cf539 --- /dev/null +++ b/hscontrol/routes/primary.go @@ -0,0 +1,186 @@ +package routes + +import ( + "fmt" + "log" + "net/netip" + "slices" + "sort" + "strings" + "sync" + + "github.com/juanfont/headscale/hscontrol/types" + "github.com/juanfont/headscale/hscontrol/util" + xmaps "golang.org/x/exp/maps" + "tailscale.com/util/set" +) + +type PrimaryRoutes struct { + mu sync.Mutex + + // routes is a map of prefixes that are adverties and approved and available + // in the global headscale state. + routes map[types.NodeID]set.Set[netip.Prefix] + + // primaries is a map of prefixes to the node that is the primary for that prefix. + primaries map[netip.Prefix]types.NodeID + isPrimary map[types.NodeID]bool +} + +func New() *PrimaryRoutes { + return &PrimaryRoutes{ + routes: make(map[types.NodeID]set.Set[netip.Prefix]), + primaries: make(map[netip.Prefix]types.NodeID), + isPrimary: make(map[types.NodeID]bool), + } +} + +// updatePrimaryLocked recalculates the primary routes and updates the internal state. +// It returns true if the primary routes have changed. +// It is assumed that the caller holds the lock. +// The algorthm is as follows: +// 1. Reset the primaries map. +// 2. Iterate over the routes and count the number of times a prefix is advertised. +// 3. If a prefix is advertised by at least two nodes, it is a primary route. +// 4. If the primary routes have changed, update the internal state and return true. +// 5. Otherwise, return false. +func (pr *PrimaryRoutes) updatePrimaryLocked() bool { + // reset the primaries map, as we are going to recalculate it. + allPrimaries := make(map[netip.Prefix][]types.NodeID) + pr.isPrimary = make(map[types.NodeID]bool) + changed := false + + // sort the node ids so we can iterate over them in a deterministic order. + // this is important so the same node is chosen two times in a row + // as the primary route. + ids := types.NodeIDs(xmaps.Keys(pr.routes)) + sort.Sort(ids) + + // Create a map of prefixes to nodes that serve them so we + // can determine the primary route for each prefix. + for _, id := range ids { + routes := pr.routes[id] + for route := range routes { + if _, ok := allPrimaries[route]; !ok { + allPrimaries[route] = []types.NodeID{id} + } else { + allPrimaries[route] = append(allPrimaries[route], id) + } + } + } + + // Go through all prefixes and determine the primary route for each. + // If the number of routes is below the minimum, remove the primary. + // If the current primary is still available, continue. + // If the current primary is not available, select a new one. + for prefix, nodes := range allPrimaries { + if node, ok := pr.primaries[prefix]; ok { + if len(nodes) < 2 { + delete(pr.primaries, prefix) + changed = true + continue + } + + // If the current primary is still available, continue. + if slices.Contains(nodes, node) { + continue + } + } + if len(nodes) >= 2 { + pr.primaries[prefix] = nodes[0] + changed = true + } + } + + // Clean up any remaining primaries that are no longer valid. + for prefix := range pr.primaries { + if _, ok := allPrimaries[prefix]; !ok { + delete(pr.primaries, prefix) + changed = true + } + } + + // Populate the quick lookup index for primary routes + for _, nodeID := range pr.primaries { + pr.isPrimary[nodeID] = true + } + + return changed +} + +func (pr *PrimaryRoutes) SetRoutes(node types.NodeID, prefix ...netip.Prefix) bool { + pr.mu.Lock() + defer pr.mu.Unlock() + + // If no routes are being set, remove the node from the routes map. + if len(prefix) == 0 { + log.Printf("Removing node %d from routes", node) + if _, ok := pr.routes[node]; ok { + delete(pr.routes, node) + return pr.updatePrimaryLocked() + } + + return false + } + + if _, ok := pr.routes[node]; !ok { + pr.routes[node] = make(set.Set[netip.Prefix], len(prefix)) + } + + for _, p := range prefix { + pr.routes[node].Add(p) + } + + return pr.updatePrimaryLocked() +} + +func (pr *PrimaryRoutes) PrimaryRoutes(id types.NodeID) []netip.Prefix { + if pr == nil { + return nil + } + + pr.mu.Lock() + defer pr.mu.Unlock() + + // Short circuit if the node is not a primary for any route. + if _, ok := pr.isPrimary[id]; !ok { + return nil + } + + var routes []netip.Prefix + + for prefix, node := range pr.primaries { + if node == id { + routes = append(routes, prefix) + } + } + + return routes +} + +func (pr *PrimaryRoutes) String() string { + pr.mu.Lock() + defer pr.mu.Unlock() + + return pr.stringLocked() +} + +func (pr *PrimaryRoutes) stringLocked() string { + var sb strings.Builder + + fmt.Fprintln(&sb, "Available routes:") + + ids := types.NodeIDs(xmaps.Keys(pr.routes)) + sort.Sort(ids) + for _, id := range ids { + prefixes := pr.routes[id] + fmt.Fprintf(&sb, "\nNode %d: %s", id, strings.Join(util.PrefixesToString(prefixes.Slice()), ", ")) + } + + fmt.Fprintln(&sb, "\n\nCurrent primary routes:") + for route, nodeID := range pr.primaries { + fmt.Fprintf(&sb, "\nRoute %s: %d", route, nodeID) + } + + return sb.String() +} diff --git a/hscontrol/routes/primary_test.go b/hscontrol/routes/primary_test.go new file mode 100644 index 00000000..c58337c0 --- /dev/null +++ b/hscontrol/routes/primary_test.go @@ -0,0 +1,316 @@ +package routes + +import ( + "net/netip" + "sync" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/juanfont/headscale/hscontrol/types" + "github.com/juanfont/headscale/hscontrol/util" +) + +// mp is a helper function that wraps netip.MustParsePrefix. +func mp(prefix string) netip.Prefix { + return netip.MustParsePrefix(prefix) +} + +func TestPrimaryRoutes(t *testing.T) { + tests := []struct { + name string + operations func(pr *PrimaryRoutes) bool + nodeID types.NodeID + expectedRoutes []netip.Prefix + expectedChange bool + }{ + { + name: "single-node-registers-single-route", + operations: func(pr *PrimaryRoutes) bool { + return pr.SetRoutes(1, mp("192.168.1.0/24")) + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "multiple-nodes-register-different-routes", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) + return pr.SetRoutes(2, mp("192.168.2.0/24")) + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "multiple-nodes-register-overlapping-routes", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + return pr.SetRoutes(2, mp("192.168.1.0/24")) // true + }, + nodeID: 1, + expectedRoutes: []netip.Prefix{mp("192.168.1.0/24")}, + expectedChange: true, + }, + { + name: "node-deregisters-a-route", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) + return pr.SetRoutes(1) // Deregister by setting no routes + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "node-deregisters-one-of-multiple-routes", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24"), mp("192.168.2.0/24")) + return pr.SetRoutes(1, mp("192.168.2.0/24")) // Deregister one route by setting the remaining route + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "node-registers-and-deregisters-routes-in-sequence", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) + pr.SetRoutes(2, mp("192.168.2.0/24")) + pr.SetRoutes(1) // Deregister by setting no routes + return pr.SetRoutes(1, mp("192.168.3.0/24")) + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "no-change-in-primary-routes", + operations: func(pr *PrimaryRoutes) bool { + return pr.SetRoutes(1, mp("192.168.1.0/24")) + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "multiple-nodes-register-same-route", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + pr.SetRoutes(2, mp("192.168.1.0/24")) // true + return pr.SetRoutes(3, mp("192.168.1.0/24")) // false + }, + nodeID: 1, + expectedRoutes: []netip.Prefix{mp("192.168.1.0/24")}, + expectedChange: false, + }, + { + name: "register-multiple-routes-shift-primary-check-old-primary", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + pr.SetRoutes(2, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(3, mp("192.168.1.0/24")) // false, 1 primary + return pr.SetRoutes(1) // true, 2 primary + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: true, + }, + { + name: "register-multiple-routes-shift-primary-check-primary", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + pr.SetRoutes(2, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(3, mp("192.168.1.0/24")) // false, 1 primary + return pr.SetRoutes(1) // true, 2 primary + }, + nodeID: 2, + expectedRoutes: []netip.Prefix{mp("192.168.1.0/24")}, + expectedChange: true, + }, + { + name: "register-multiple-routes-shift-primary-check-non-primary", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + pr.SetRoutes(2, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(3, mp("192.168.1.0/24")) // false, 1 primary + return pr.SetRoutes(1) // true, 2 primary + }, + nodeID: 3, + expectedRoutes: nil, + expectedChange: true, + }, + { + name: "primary-route-map-is-cleared-up-no-primary", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + pr.SetRoutes(2, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(3, mp("192.168.1.0/24")) // false, 1 primary + pr.SetRoutes(1) // true, 2 primary + + return pr.SetRoutes(2) // true, no primary + }, + nodeID: 2, + expectedRoutes: nil, + expectedChange: true, + }, + { + name: "primary-route-map-is-cleared-up-all-no-primary", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + pr.SetRoutes(2, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(3, mp("192.168.1.0/24")) // false, 1 primary + pr.SetRoutes(1) // true, 2 primary + pr.SetRoutes(2) // true, no primary + + return pr.SetRoutes(3) // false, no primary + }, + nodeID: 2, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "primary-route-map-is-cleared-up", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + pr.SetRoutes(2, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(3, mp("192.168.1.0/24")) // false, 1 primary + pr.SetRoutes(1) // true, 2 primary + + return pr.SetRoutes(2) // true, no primary + }, + nodeID: 2, + expectedRoutes: nil, + expectedChange: true, + }, + { + name: "primary-route-no-flake", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + pr.SetRoutes(2, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(3, mp("192.168.1.0/24")) // false, 1 primary + pr.SetRoutes(1) // true, 2 primary + + return pr.SetRoutes(1, mp("192.168.1.0/24")) // false, 2 primary + }, + nodeID: 2, + expectedRoutes: []netip.Prefix{mp("192.168.1.0/24")}, + expectedChange: false, + }, + { + name: "primary-route-no-flake-check-old-primary", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + pr.SetRoutes(2, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(3, mp("192.168.1.0/24")) // false, 1 primary + pr.SetRoutes(1) // true, 2 primary + + return pr.SetRoutes(1, mp("192.168.1.0/24")) // false, 2 primary + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "primary-route-no-flake-full-integration", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("192.168.1.0/24")) // false + pr.SetRoutes(2, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(3, mp("192.168.1.0/24")) // false, 1 primary + pr.SetRoutes(1) // true, 2 primary + pr.SetRoutes(2) // true, no primary + pr.SetRoutes(1, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(2, mp("192.168.1.0/24")) // true, 1 primary + pr.SetRoutes(1) // true, 2 primary + + return pr.SetRoutes(1, mp("192.168.1.0/24")) // false, 2 primary + }, + nodeID: 2, + expectedRoutes: []netip.Prefix{mp("192.168.1.0/24")}, + expectedChange: false, + }, + { + name: "multiple-nodes-register-same-route-and-exit", + operations: func(pr *PrimaryRoutes) bool { + pr.SetRoutes(1, mp("0.0.0.0/0"), mp("192.168.1.0/24")) + return pr.SetRoutes(2, mp("192.168.1.0/24")) + }, + nodeID: 1, + expectedRoutes: []netip.Prefix{mp("192.168.1.0/24")}, + expectedChange: true, + }, + { + name: "deregister-non-existent-route", + operations: func(pr *PrimaryRoutes) bool { + return pr.SetRoutes(1) // Deregister by setting no routes + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "register-empty-prefix-list", + operations: func(pr *PrimaryRoutes) bool { + return pr.SetRoutes(1) + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "deregister-empty-prefix-list", + operations: func(pr *PrimaryRoutes) bool { + return pr.SetRoutes(1) + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "concurrent-access", + operations: func(pr *PrimaryRoutes) bool { + var wg sync.WaitGroup + wg.Add(2) + var change1, change2 bool + go func() { + defer wg.Done() + change1 = pr.SetRoutes(1, mp("192.168.1.0/24")) + }() + go func() { + defer wg.Done() + change2 = pr.SetRoutes(2, mp("192.168.2.0/24")) + }() + wg.Wait() + + return change1 || change2 + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + { + name: "no-routes-registered", + operations: func(pr *PrimaryRoutes) bool { + // No operations + return false + }, + nodeID: 1, + expectedRoutes: nil, + expectedChange: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pr := New() + change := tt.operations(pr) + if change != tt.expectedChange { + t.Errorf("change = %v, want %v", change, tt.expectedChange) + } + routes := pr.PrimaryRoutes(tt.nodeID) + if diff := cmp.Diff(tt.expectedRoutes, routes, util.Comparers...); diff != "" { + t.Errorf("PrimaryRoutes() mismatch (-want +got):\n%s", diff) + } + }) + } +} diff --git a/hscontrol/types/node.go b/hscontrol/types/node.go index 6443ba7d..7aeef4c0 100644 --- a/hscontrol/types/node.go +++ b/hscontrol/types/node.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "net/netip" + "slices" "strconv" "strings" "time" @@ -25,8 +26,11 @@ var ( ) type NodeID uint64 +type NodeIDs []NodeID -// type NodeConnectedMap *xsync.MapOf[NodeID, bool] +func (n NodeIDs) Len() int { return len(n) } +func (n NodeIDs) Less(i, j int) bool { return n[i] < n[j] } +func (n NodeIDs) Swap(i, j int) { n[i], n[j] = n[j], n[i] } func (id NodeID) StableID() tailcfg.StableNodeID { return tailcfg.StableNodeID(strconv.FormatUint(uint64(id), util.Base10)) @@ -84,10 +88,21 @@ type Node struct { AuthKeyID *uint64 `sql:"DEFAULT:NULL"` AuthKey *PreAuthKey - LastSeen *time.Time - Expiry *time.Time + Expiry *time.Time - Routes []Route `gorm:"constraint:OnDelete:CASCADE;"` + // LastSeen is when the node was last in contact with + // headscale. It is best effort and not persisted. + LastSeen *time.Time `gorm:"-"` + + // DEPRECATED: Use the ApprovedRoutes field instead. + // TODO(kradalby): remove when ApprovedRoutes is used all over the code. + // Routes []Route `gorm:"constraint:OnDelete:CASCADE;"` + + // ApprovedRoutes is a list of routes that the node is allowed to announce + // as a subnet router. They are not necessarily the routes that the node + // announces at the moment. + // See [Node.Hostinfo] + ApprovedRoutes []netip.Prefix `gorm:"column:approved_routes;serializer:json"` CreatedAt time.Time UpdatedAt time.Time @@ -96,9 +111,7 @@ type Node struct { IsOnline *bool `gorm:"-"` } -type ( - Nodes []*Node -) +type Nodes []*Node // GivenNameHasBeenChanged returns whether the `givenName` can be automatically changed based on the `Hostname` of the node. func (node *Node) GivenNameHasBeenChanged() bool { @@ -185,23 +198,22 @@ func (node *Node) CanAccess(filter []tailcfg.FilterRule, node2 *Node) bool { // TODO(kradalby): Regenerate this every time the filter change, instead of // every time we use it. + // Part of #2416 matchers := make([]matcher.Match, len(filter)) for i, rule := range filter { matchers[i] = matcher.MatchFromFilterRule(rule) } - for _, route := range node2.Routes { - if route.Enabled { - allowedIPs = append(allowedIPs, netip.Prefix(route.Prefix).Addr()) - } - } - for _, matcher := range matchers { - if !matcher.SrcsContainsIPs(src) { + if !matcher.SrcsContainsIPs(src...) { continue } - if matcher.DestsContainsIP(allowedIPs) { + if matcher.DestsContainsIP(allowedIPs...) { + return true + } + + if matcher.DestsOverlapsPrefixes(node2.SubnetRoutes()...) { return true } } @@ -245,11 +257,14 @@ func (node *Node) Proto() *v1.Node { DiscoKey: node.DiscoKey.String(), // TODO(kradalby): replace list with v4, v6 field? - IpAddresses: node.IPsAsString(), - Name: node.Hostname, - GivenName: node.GivenName, - User: node.User.Proto(), - ForcedTags: node.ForcedTags, + IpAddresses: node.IPsAsString(), + Name: node.Hostname, + GivenName: node.GivenName, + User: node.User.Proto(), + ForcedTags: node.ForcedTags, + ApprovedRoutes: util.PrefixesToString(node.ApprovedRoutes), + AvailableRoutes: util.PrefixesToString(node.AnnouncedRoutes()), + SubnetRoutes: util.PrefixesToString(node.SubnetRoutes()), RegisterMethod: node.RegisterMethodToV1Enum(), @@ -297,6 +312,29 @@ func (node *Node) GetFQDN(baseDomain string) (string, error) { return hostname, nil } +// AnnouncedRoutes returns the list of routes that the node announces. +// It should be used instead of checking Hostinfo.RoutableIPs directly. +func (node *Node) AnnouncedRoutes() []netip.Prefix { + if node.Hostinfo == nil { + return nil + } + + return node.Hostinfo.RoutableIPs +} + +// SubnetRoutes returns the list of routes that the node announces and are approved. +func (node *Node) SubnetRoutes() []netip.Prefix { + var routes []netip.Prefix + + for _, route := range node.AnnouncedRoutes() { + if slices.Contains(node.ApprovedRoutes, route) { + routes = append(routes, route) + } + } + + return routes +} + // func (node *Node) String() string { // return node.Hostname // } diff --git a/hscontrol/types/routes.go b/hscontrol/types/routes.go index 12559fa6..3ff56027 100644 --- a/hscontrol/types/routes.go +++ b/hscontrol/types/routes.go @@ -1,102 +1,31 @@ package types import ( - "fmt" "net/netip" - v1 "github.com/juanfont/headscale/gen/go/headscale/v1" - "google.golang.org/protobuf/types/known/timestamppb" "gorm.io/gorm" - "tailscale.com/net/tsaddr" ) +// Deprecated: Approval of routes is denormalised onto the relevant node. +// Struct is kept for GORM migrations only. type Route struct { gorm.Model NodeID uint64 `gorm:"not null"` Node *Node - // TODO(kradalby): change this custom type to netip.Prefix Prefix netip.Prefix `gorm:"serializer:text"` + // Advertised is now only stored as part of [Node.Hostinfo]. Advertised bool - Enabled bool - IsPrimary bool + + // Enabled is stored directly on the node as ApprovedRoutes. + Enabled bool + + // IsPrimary is only determined in memory as it is only relevant + // when the server is up. + IsPrimary bool } +// Deprecated: Approval of routes is denormalised onto the relevant node. type Routes []Route - -func (r *Route) String() string { - return fmt.Sprintf("%s:%s", r.Node.Hostname, netip.Prefix(r.Prefix).String()) -} - -func (r *Route) IsExitRoute() bool { - return tsaddr.IsExitRoute(r.Prefix) -} - -func (r *Route) IsAnnouncable() bool { - return r.Advertised && r.Enabled -} - -func (rs Routes) Prefixes() []netip.Prefix { - prefixes := make([]netip.Prefix, len(rs)) - for i, r := range rs { - prefixes[i] = netip.Prefix(r.Prefix) - } - - return prefixes -} - -// Primaries returns Primary routes from a list of routes. -func (rs Routes) Primaries() Routes { - res := make(Routes, 0) - for _, route := range rs { - if route.IsPrimary { - res = append(res, route) - } - } - - return res -} - -func (rs Routes) PrefixMap() map[netip.Prefix][]Route { - res := map[netip.Prefix][]Route{} - - for _, route := range rs { - if _, ok := res[route.Prefix]; ok { - res[route.Prefix] = append(res[route.Prefix], route) - } else { - res[route.Prefix] = []Route{route} - } - } - - return res -} - -func (rs Routes) Proto() []*v1.Route { - protoRoutes := []*v1.Route{} - - for _, route := range rs { - protoRoute := v1.Route{ - Id: uint64(route.ID), - Prefix: route.Prefix.String(), - Advertised: route.Advertised, - Enabled: route.Enabled, - IsPrimary: route.IsPrimary, - CreatedAt: timestamppb.New(route.CreatedAt), - UpdatedAt: timestamppb.New(route.UpdatedAt), - } - - if route.Node != nil { - protoRoute.Node = route.Node.Proto() - } - - if route.DeletedAt.Valid { - protoRoute.DeletedAt = timestamppb.New(route.DeletedAt.Time) - } - - protoRoutes = append(protoRoutes, &protoRoute) - } - - return protoRoutes -} diff --git a/hscontrol/types/routes_test.go b/hscontrol/types/routes_test.go deleted file mode 100644 index b3600482..00000000 --- a/hscontrol/types/routes_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package types - -import ( - "fmt" - "net/netip" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/juanfont/headscale/hscontrol/util" -) - -func TestPrefixMap(t *testing.T) { - ipp := func(s string) netip.Prefix { return netip.MustParsePrefix(s) } - - tests := []struct { - rs Routes - want map[netip.Prefix][]Route - }{ - { - rs: Routes{ - Route{ - Prefix: ipp("10.0.0.0/24"), - }, - }, - want: map[netip.Prefix][]Route{ - ipp("10.0.0.0/24"): Routes{ - Route{ - Prefix: ipp("10.0.0.0/24"), - }, - }, - }, - }, - { - rs: Routes{ - Route{ - Prefix: ipp("10.0.0.0/24"), - }, - Route{ - Prefix: ipp("10.0.1.0/24"), - }, - }, - want: map[netip.Prefix][]Route{ - ipp("10.0.0.0/24"): Routes{ - Route{ - Prefix: ipp("10.0.0.0/24"), - }, - }, - ipp("10.0.1.0/24"): Routes{ - Route{ - Prefix: ipp("10.0.1.0/24"), - }, - }, - }, - }, - { - rs: Routes{ - Route{ - Prefix: ipp("10.0.0.0/24"), - Enabled: true, - }, - Route{ - Prefix: ipp("10.0.0.0/24"), - Enabled: false, - }, - }, - want: map[netip.Prefix][]Route{ - ipp("10.0.0.0/24"): Routes{ - Route{ - Prefix: ipp("10.0.0.0/24"), - Enabled: true, - }, - Route{ - Prefix: ipp("10.0.0.0/24"), - Enabled: false, - }, - }, - }, - }, - } - - for idx, tt := range tests { - t.Run(fmt.Sprintf("test-%d", idx), func(t *testing.T) { - got := tt.rs.PrefixMap() - if diff := cmp.Diff(tt.want, got, util.Comparers...); diff != "" { - t.Errorf("PrefixMap() unexpected result (-want +got):\n%s", diff) - } - }) - } -} diff --git a/hscontrol/types/users.go b/hscontrol/types/users.go index cd6a4780..2eba5f0f 100644 --- a/hscontrol/types/users.go +++ b/hscontrol/types/users.go @@ -55,6 +55,13 @@ type User struct { ProfilePicURL string } +func (u *User) StringID() string { + if u == nil { + return "" + } + return strconv.FormatUint(uint64(u.ID), 10) +} + // Username is the main way to get the username of a user, // it will return the email if it exists, the name if it exists, // the OIDCIdentifier if it exists, and the ID if nothing else exists. @@ -63,7 +70,11 @@ type User struct { // should be used throughout headscale, in information returned to the // user and the Policy engine. func (u *User) Username() string { - return cmp.Or(u.Email, u.Name, u.ProviderIdentifier.String, strconv.FormatUint(uint64(u.ID), 10)) + return cmp.Or( + u.Email, + u.Name, + u.ProviderIdentifier.String, + u.StringID()) } // DisplayNameOrUsername returns the DisplayName if it exists, otherwise diff --git a/hscontrol/util/net.go b/hscontrol/util/net.go index b704c936..665ce1dd 100644 --- a/hscontrol/util/net.go +++ b/hscontrol/util/net.go @@ -1,8 +1,10 @@ package util import ( + "cmp" "context" "net" + "net/netip" ) func GrpcSocketDialer(ctx context.Context, addr string) (net.Conn, error) { @@ -10,3 +12,40 @@ func GrpcSocketDialer(ctx context.Context, addr string) (net.Conn, error) { return d.DialContext(ctx, "unix", addr) } + +// TODO(kradalby): Remove when in stdlib; +// https://github.com/golang/go/issues/61642 +// Compare returns an integer comparing two prefixes. +// The result will be 0 if p == p2, -1 if p < p2, and +1 if p > p2. +// Prefixes sort first by validity (invalid before valid), then +// address family (IPv4 before IPv6), then prefix length, then +// address. +func ComparePrefix(p, p2 netip.Prefix) int { + if c := cmp.Compare(p.Addr().BitLen(), p2.Addr().BitLen()); c != 0 { + return c + } + if c := cmp.Compare(p.Bits(), p2.Bits()); c != 0 { + return c + } + + return p.Addr().Compare(p2.Addr()) +} + +func PrefixesToString(prefixes []netip.Prefix) []string { + ret := make([]string, 0, len(prefixes)) + for _, prefix := range prefixes { + ret = append(ret, prefix.String()) + } + + return ret +} + +func MustStringsToPrefixes(strings []string) []netip.Prefix { + ret := make([]netip.Prefix, 0, len(strings)) + for _, str := range strings { + prefix := netip.MustParsePrefix(str) + ret = append(ret, prefix) + } + + return ret +} diff --git a/hscontrol/util/string.go b/hscontrol/util/string.go index 08769060..a9e7ca96 100644 --- a/hscontrol/util/string.go +++ b/hscontrol/util/string.go @@ -74,3 +74,21 @@ func TailMapResponseToString(resp tailcfg.MapResponse) string { TailNodesToString(resp.Peers), ) } + +func TailcfgFilterRulesToString(rules []tailcfg.FilterRule) string { + var sb strings.Builder + + for index, rule := range rules { + sb.WriteString(fmt.Sprintf(` +{ + SrcIPs: %v + DstIPs: %v +} +`, rule.SrcIPs, rule.DstPorts)) + if index < len(rules)-1 { + sb.WriteString(", ") + } + } + + return fmt.Sprintf("[ %s ](%d)", sb.String(), len(rules)) +} diff --git a/integration/control.go b/integration/control.go index 8ec6bad6..e1ad2a7e 100644 --- a/integration/control.go +++ b/integration/control.go @@ -1,6 +1,8 @@ package integration import ( + "net/netip" + v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/ory/dockertest/v3" ) @@ -19,6 +21,7 @@ type ControlServer interface { CreateAuthKey(user string, reusable bool, ephemeral bool) (*v1.PreAuthKey, error) ListNodes(users ...string) ([]*v1.Node, error) ListUsers() ([]*v1.User, error) + ApproveRoutes(uint64, []netip.Prefix) (*v1.Node, error) GetCert() []byte GetHostname() string GetIP() string diff --git a/integration/hsic/hsic.go b/integration/hsic/hsic.go index 8c888092..b75d9c08 100644 --- a/integration/hsic/hsic.go +++ b/integration/hsic/hsic.go @@ -9,6 +9,7 @@ import ( "io" "log" "net/http" + "net/netip" "os" "path" "sort" @@ -817,6 +818,33 @@ func (t *HeadscaleInContainer) ListUsers() ([]*v1.User, error) { return users, nil } +// ApproveRoutes approves routes for a node. +func (t *HeadscaleInContainer) ApproveRoutes(id uint64, routes []netip.Prefix) (*v1.Node, error) { + command := []string{ + "headscale", "nodes", "approve-routes", + "--output", "json", + "--identifier", strconv.FormatUint(id, 10), + fmt.Sprintf("--routes=%q", strings.Join(util.PrefixesToString(routes), ",")), + } + + result, _, err := dockertestutil.ExecuteCommand( + t.container, + command, + []string{}, + ) + if err != nil { + return nil, fmt.Errorf("failed to execute list node command: %w", err) + } + + var node *v1.Node + err = json.Unmarshal([]byte(result), &node) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal nodes: %w", err) + } + + return node, nil +} + // WriteFile save file inside the Headscale container. func (t *HeadscaleInContainer) WriteFile(path string, data []byte) error { return integrationutil.WriteFileToContainer(t.pool, t.container, path, data) diff --git a/integration/route_test.go b/integration/route_test.go index 32e49e7d..e6f6b5d6 100644 --- a/integration/route_test.go +++ b/integration/route_test.go @@ -1,16 +1,12 @@ package integration import ( - "fmt" - "log" "net/netip" "sort" - "strconv" "testing" "time" "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/juanfont/headscale/hscontrol/policy" "github.com/juanfont/headscale/hscontrol/util" @@ -18,6 +14,7 @@ import ( "github.com/juanfont/headscale/integration/tsic" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "tailscale.com/ipn/ipnstate" "tailscale.com/net/tsaddr" "tailscale.com/types/ipproto" "tailscale.com/types/views" @@ -35,7 +32,7 @@ func TestEnablingRoutes(t *testing.T) { user := "enable-routing" scenario, err := NewScenario(dockertestMaxWait()) - assertNoErrf(t, "failed to create scenario: %s", err) + require.NoErrorf(t, err, "failed to create scenario: %s", err) defer scenario.ShutdownAssertNoPanics(t) spec := map[string]int{ @@ -63,7 +60,7 @@ func TestEnablingRoutes(t *testing.T) { // advertise routes using the up command for _, client := range allClients { status, err := client.Status() - assertNoErr(t, err) + require.NoError(t, err) command := []string{ "tailscale", @@ -71,39 +68,26 @@ func TestEnablingRoutes(t *testing.T) { "--advertise-routes=" + expectedRoutes[string(status.Self.ID)], } _, _, err = client.Execute(command) - assertNoErrf(t, "failed to advertise route: %s", err) + require.NoErrorf(t, err, "failed to advertise route: %s", err) } err = scenario.WaitForTailscaleSync() assertNoErrSync(t, err) - var routes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routes, - ) + nodes, err := headscale.ListNodes() + require.NoError(t, err) - assertNoErr(t, err) - assert.Len(t, routes, 3) - - for _, route := range routes { - assert.True(t, route.GetAdvertised()) - assert.False(t, route.GetEnabled()) - assert.False(t, route.GetIsPrimary()) + for _, node := range nodes { + assert.Len(t, node.GetAvailableRoutes(), 1) + assert.Empty(t, node.GetApprovedRoutes()) + assert.Empty(t, node.GetSubnetRoutes()) } // Verify that no routes has been sent to the client, // they are not yet enabled. for _, client := range allClients { status, err := client.Status() - assertNoErr(t, err) + require.NoError(t, err) for _, peerKey := range status.Peers() { peerStatus := status.Peer[peerKey] @@ -112,38 +96,21 @@ func TestEnablingRoutes(t *testing.T) { } } - // Enable all routes - for _, route := range routes { - _, err = headscale.Execute( - []string{ - "headscale", - "routes", - "enable", - "--route", - strconv.Itoa(int(route.GetId())), - }) - assertNoErr(t, err) + for _, node := range nodes { + _, err := headscale.ApproveRoutes( + node.GetId(), + util.MustStringsToPrefixes(node.GetAvailableRoutes()), + ) + require.NoError(t, err) } - var enablingRoutes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &enablingRoutes, - ) - assertNoErr(t, err) - assert.Len(t, enablingRoutes, 3) + nodes, err = headscale.ListNodes() + require.NoError(t, err) - for _, route := range enablingRoutes { - assert.True(t, route.GetAdvertised()) - assert.True(t, route.GetEnabled()) - assert.True(t, route.GetIsPrimary()) + for _, node := range nodes { + assert.Len(t, node.GetAvailableRoutes(), 1) + assert.Len(t, node.GetApprovedRoutes(), 1) + assert.Len(t, node.GetSubnetRoutes(), 1) } time.Sleep(5 * time.Second) @@ -151,22 +118,17 @@ func TestEnablingRoutes(t *testing.T) { // Verify that the clients can see the new routes for _, client := range allClients { status, err := client.Status() - assertNoErr(t, err) + require.NoError(t, err) for _, peerKey := range status.Peers() { peerStatus := status.Peer[peerKey] - assert.NotNil(t, peerStatus.PrimaryRoutes) - if peerStatus.PrimaryRoutes == nil { - continue - } + assert.Nil(t, peerStatus.PrimaryRoutes) - pRoutes := peerStatus.PrimaryRoutes.AsSlice() + assert.Len(t, peerStatus.AllowedIPs.AsSlice(), 3) - assert.Len(t, pRoutes, 1) - - if len(pRoutes) > 0 { - peerRoute := peerStatus.PrimaryRoutes.AsSlice()[0] + if peerStatus.AllowedIPs.Len() > 2 { + peerRoute := peerStatus.AllowedIPs.At(2) // id starts at 1, we created routes with 0 index assert.Equalf( @@ -184,67 +146,54 @@ func TestEnablingRoutes(t *testing.T) { } } - routeToBeDisabled := enablingRoutes[0] - log.Printf("preparing to disable %v", routeToBeDisabled) + _, err = headscale.ApproveRoutes( + 1, + []netip.Prefix{netip.MustParsePrefix("10.0.1.0/24")}, + ) + require.NoError(t, err) - _, err = headscale.Execute( - []string{ - "headscale", - "routes", - "disable", - "--route", - strconv.Itoa(int(routeToBeDisabled.GetId())), - }) - assertNoErr(t, err) + _, err = headscale.ApproveRoutes( + 2, + []netip.Prefix{}, + ) + require.NoError(t, err) time.Sleep(5 * time.Second) - var disablingRoutes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &disablingRoutes, - ) - assertNoErr(t, err) + nodes, err = headscale.ListNodes() + require.NoError(t, err) - for _, route := range disablingRoutes { - assert.True(t, route.GetAdvertised()) - - if route.GetId() == routeToBeDisabled.GetId() { - assert.False(t, route.GetEnabled()) - - // since this is the only route of this cidr, - // it will not failover, and remain Primary - // until something can replace it. - assert.True(t, route.GetIsPrimary()) + for _, node := range nodes { + if node.GetId() == 1 { + assert.Len(t, node.GetAvailableRoutes(), 1) // 10.0.0.0/24 + assert.Len(t, node.GetApprovedRoutes(), 1) // 10.0.1.0/24 + assert.Empty(t, node.GetSubnetRoutes()) + } else if node.GetId() == 2 { + assert.Len(t, node.GetAvailableRoutes(), 1) // 10.0.1.0/24 + assert.Empty(t, node.GetApprovedRoutes()) + assert.Empty(t, node.GetSubnetRoutes()) } else { - assert.True(t, route.GetEnabled()) - assert.True(t, route.GetIsPrimary()) + assert.Len(t, node.GetAvailableRoutes(), 1) // 10.0.2.0/24 + assert.Len(t, node.GetApprovedRoutes(), 1) // 10.0.2.0/24 + assert.Len(t, node.GetSubnetRoutes(), 1) // 10.0.2.0/24 } } // Verify that the clients can see the new routes for _, client := range allClients { status, err := client.Status() - assertNoErr(t, err) + require.NoError(t, err) for _, peerKey := range status.Peers() { peerStatus := status.Peer[peerKey] - if string(peerStatus.ID) == fmt.Sprintf("%d", routeToBeDisabled.GetNode().GetId()) { - assert.Nilf( - t, - peerStatus.PrimaryRoutes, - "expected node %s to have no routes, got primary route (%v)", - peerStatus.HostName, - peerStatus.PrimaryRoutes, - ) + assert.Nil(t, peerStatus.PrimaryRoutes) + if peerStatus.ID == "1" { + assertPeerSubnetRoutes(t, peerStatus, nil) + } else if peerStatus.ID == "2" { + assertPeerSubnetRoutes(t, peerStatus, nil) + } else { + assertPeerSubnetRoutes(t, peerStatus, []netip.Prefix{netip.MustParsePrefix("10.0.2.0/24")}) } } } @@ -257,14 +206,18 @@ func TestHASubnetRouterFailover(t *testing.T) { user := "enable-routing" scenario, err := NewScenario(dockertestMaxWait()) - assertNoErrf(t, "failed to create scenario: %s", err) + require.NoErrorf(t, err, "failed to create scenario: %s", err) defer scenario.ShutdownAssertNoPanics(t) spec := map[string]int{ - user: 3, + user: 4, } - err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clienableroute")) + err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, + hsic.WithTestName("clienableroute"), + hsic.WithEmbeddedDERPServerOnly(), + hsic.WithTLS(), + ) assertNoErrHeadscaleEnv(t, err) allClients, err := scenario.ListTailscaleClients() @@ -279,35 +232,31 @@ func TestHASubnetRouterFailover(t *testing.T) { expectedRoutes := map[string]string{ "1": "10.0.0.0/24", "2": "10.0.0.0/24", + "3": "10.0.0.0/24", } // Sort nodes by ID sort.SliceStable(allClients, func(i, j int) bool { - statusI, err := allClients[i].Status() - if err != nil { - return false - } - - statusJ, err := allClients[j].Status() - if err != nil { - return false - } + statusI := allClients[i].MustStatus() + statusJ := allClients[j].MustStatus() return statusI.Self.ID < statusJ.Self.ID }) subRouter1 := allClients[0] subRouter2 := allClients[1] + subRouter3 := allClients[2] - client := allClients[2] + client := allClients[3] - t.Logf("Advertise route from r1 (%s) and r2 (%s), making it HA, n1 is primary", subRouter1.Hostname(), subRouter2.Hostname()) - // advertise HA route on node 1 and 2 + t.Logf("Advertise route from r1 (%s), r2 (%s), r3 (%s), making it HA, n1 is primary", subRouter1.Hostname(), subRouter2.Hostname(), subRouter3.Hostname()) + // advertise HA route on node 1, 2, 3 // ID 1 will be primary - // ID 2 will be secondary - for _, client := range allClients[:2] { + // ID 2 will be standby + // ID 3 will be standby + for _, client := range allClients[:3] { status, err := client.Status() - assertNoErr(t, err) + require.NoError(t, err) if route, ok := expectedRoutes[string(status.Self.ID)]; ok { command := []string{ @@ -316,7 +265,7 @@ func TestHASubnetRouterFailover(t *testing.T) { "--advertise-routes=" + route, } _, _, err = client.Execute(command) - assertNoErrf(t, "failed to advertise route: %s", err) + require.NoErrorf(t, err, "failed to advertise route: %s", err) } else { t.Fatalf("failed to find route for Node %s (id: %s)", status.Self.HostName, status.Self.ID) } @@ -325,101 +274,64 @@ func TestHASubnetRouterFailover(t *testing.T) { err = scenario.WaitForTailscaleSync() assertNoErrSync(t, err) - var routes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routes, - ) + nodes, err := headscale.ListNodes() + require.NoError(t, err) + assert.Len(t, nodes, 4) - assertNoErr(t, err) - assert.Len(t, routes, 2) - - t.Logf("initial routes %#v", routes) - - for _, route := range routes { - assert.True(t, route.GetAdvertised()) - assert.False(t, route.GetEnabled()) - assert.False(t, route.GetIsPrimary()) - } + assertNodeRouteCount(t, nodes[0], 1, 0, 0) + assertNodeRouteCount(t, nodes[1], 1, 0, 0) + assertNodeRouteCount(t, nodes[2], 1, 0, 0) // Verify that no routes has been sent to the client, // they are not yet enabled. for _, client := range allClients { status, err := client.Status() - assertNoErr(t, err) + require.NoError(t, err) for _, peerKey := range status.Peers() { peerStatus := status.Peer[peerKey] assert.Nil(t, peerStatus.PrimaryRoutes) + assertPeerSubnetRoutes(t, peerStatus, nil) } } // Enable all routes - for _, route := range routes { - _, err = headscale.Execute( - []string{ - "headscale", - "routes", - "enable", - "--route", - strconv.Itoa(int(route.GetId())), - }) - assertNoErr(t, err) - - time.Sleep(time.Second) + for _, node := range nodes { + _, err := headscale.ApproveRoutes( + node.GetId(), + util.MustStringsToPrefixes(node.GetAvailableRoutes()), + ) + require.NoError(t, err) } - var enablingRoutes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &enablingRoutes, - ) - assertNoErr(t, err) - assert.Len(t, enablingRoutes, 2) + nodes, err = headscale.ListNodes() + require.NoError(t, err) + assert.Len(t, nodes, 4) - // Node 1 is primary - assert.True(t, enablingRoutes[0].GetAdvertised()) - assert.True(t, enablingRoutes[0].GetEnabled()) - assert.True(t, enablingRoutes[0].GetIsPrimary(), "both subnet routers are up, expected r1 to be primary") - - // Node 2 is not primary - assert.True(t, enablingRoutes[1].GetAdvertised()) - assert.True(t, enablingRoutes[1].GetEnabled()) - assert.False(t, enablingRoutes[1].GetIsPrimary(), "both subnet routers are up, expected r2 to be non-primary") + assertNodeRouteCount(t, nodes[0], 1, 1, 1) + assertNodeRouteCount(t, nodes[1], 1, 1, 1) + assertNodeRouteCount(t, nodes[2], 1, 1, 1) // Verify that the client has routes from the primary machine - srs1, err := subRouter1.Status() - srs2, err := subRouter2.Status() - - clientStatus, err := client.Status() - assertNoErr(t, err) + srs1 := subRouter1.MustStatus() + srs2 := subRouter2.MustStatus() + srs3 := subRouter3.MustStatus() + clientStatus := client.MustStatus() srs1PeerStatus := clientStatus.Peer[srs1.Self.PublicKey] srs2PeerStatus := clientStatus.Peer[srs2.Self.PublicKey] + srs3PeerStatus := clientStatus.Peer[srs3.Self.PublicKey] assert.True(t, srs1PeerStatus.Online, "r1 up, r2 up") assert.True(t, srs2PeerStatus.Online, "r1 up, r2 up") + assert.True(t, srs3PeerStatus.Online, "r1 up, r2 up") - assertNotNil(t, srs1PeerStatus.PrimaryRoutes) assert.Nil(t, srs2PeerStatus.PrimaryRoutes) + assert.Nil(t, srs3PeerStatus.PrimaryRoutes) + require.NotNil(t, srs1PeerStatus.PrimaryRoutes) - assert.Contains( - t, + assert.Contains(t, srs1PeerStatus.PrimaryRoutes.AsSlice(), netip.MustParsePrefix(expectedRoutes[string(srs1.Self.ID)]), ) @@ -428,396 +340,186 @@ func TestHASubnetRouterFailover(t *testing.T) { t.Logf("taking down subnet router r1 (%s)", subRouter1.Hostname()) t.Logf("expecting r2 (%s) to take over as primary", subRouter2.Hostname()) err = subRouter1.Down() - assertNoErr(t, err) + require.NoError(t, err) time.Sleep(5 * time.Second) - var routesAfterMove []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routesAfterMove, - ) - assertNoErr(t, err) - assert.Len(t, routesAfterMove, 2) - - // Node 1 is not primary - assert.True(t, routesAfterMove[0].GetAdvertised()) - assert.True(t, routesAfterMove[0].GetEnabled()) - assert.False(t, routesAfterMove[0].GetIsPrimary(), "r1 is down, expected r2 to be primary") - - // Node 2 is primary - assert.True(t, routesAfterMove[1].GetAdvertised()) - assert.True(t, routesAfterMove[1].GetEnabled()) - assert.True(t, routesAfterMove[1].GetIsPrimary(), "r1 is down, expected r2 to be primary") - - srs2, err = subRouter2.Status() - - clientStatus, err = client.Status() - assertNoErr(t, err) + srs2 = subRouter2.MustStatus() + clientStatus = client.MustStatus() srs1PeerStatus = clientStatus.Peer[srs1.Self.PublicKey] srs2PeerStatus = clientStatus.Peer[srs2.Self.PublicKey] + srs3PeerStatus = clientStatus.Peer[srs3.Self.PublicKey] assert.False(t, srs1PeerStatus.Online, "r1 down, r2 down") assert.True(t, srs2PeerStatus.Online, "r1 down, r2 up") + assert.True(t, srs3PeerStatus.Online, "r1 down, r2 up") assert.Nil(t, srs1PeerStatus.PrimaryRoutes) - assertNotNil(t, srs2PeerStatus.PrimaryRoutes) + require.NotNil(t, srs2PeerStatus.PrimaryRoutes) + assert.Nil(t, srs3PeerStatus.PrimaryRoutes) - if srs2PeerStatus.PrimaryRoutes != nil { - assert.Contains( - t, - srs2PeerStatus.PrimaryRoutes.AsSlice(), - netip.MustParsePrefix(expectedRoutes[string(srs2.Self.ID)]), - ) - } + assert.Contains( + t, + srs2PeerStatus.PrimaryRoutes.AsSlice(), + netip.MustParsePrefix(expectedRoutes[string(srs2.Self.ID)]), + ) // Take down subnet router 2, leaving none available t.Logf("taking down subnet router r2 (%s)", subRouter2.Hostname()) - t.Logf("expecting r2 (%s) to remain primary, no other available", subRouter2.Hostname()) + t.Logf("expecting no primary, r3 available, but no HA so no primary") err = subRouter2.Down() - assertNoErr(t, err) + require.NoError(t, err) time.Sleep(5 * time.Second) - var routesAfterBothDown []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routesAfterBothDown, - ) - assertNoErr(t, err) - assert.Len(t, routesAfterBothDown, 2) - - // Node 1 is not primary - assert.True(t, routesAfterBothDown[0].GetAdvertised()) - assert.True(t, routesAfterBothDown[0].GetEnabled()) - assert.False(t, routesAfterBothDown[0].GetIsPrimary(), "r1 and r2 is down, expected r2 to _still_ be primary") - - // Node 2 is primary - // if the node goes down, but no other suitable route is - // available, keep the last known good route. - assert.True(t, routesAfterBothDown[1].GetAdvertised()) - assert.True(t, routesAfterBothDown[1].GetEnabled()) - assert.True(t, routesAfterBothDown[1].GetIsPrimary(), "r1 and r2 is down, expected r2 to _still_ be primary") - // TODO(kradalby): Check client status // Both are expected to be down // Verify that the route is not presented from either router clientStatus, err = client.Status() - assertNoErr(t, err) + require.NoError(t, err) srs1PeerStatus = clientStatus.Peer[srs1.Self.PublicKey] srs2PeerStatus = clientStatus.Peer[srs2.Self.PublicKey] + srs3PeerStatus = clientStatus.Peer[srs3.Self.PublicKey] assert.False(t, srs1PeerStatus.Online, "r1 down, r2 down") assert.False(t, srs2PeerStatus.Online, "r1 down, r2 down") + assert.True(t, srs3PeerStatus.Online, "r1 down, r2 down") assert.Nil(t, srs1PeerStatus.PrimaryRoutes) - assertNotNil(t, srs2PeerStatus.PrimaryRoutes) - - if srs2PeerStatus.PrimaryRoutes != nil { - assert.Contains( - t, - srs2PeerStatus.PrimaryRoutes.AsSlice(), - netip.MustParsePrefix(expectedRoutes[string(srs2.Self.ID)]), - ) - } + assert.Nil(t, srs2PeerStatus.PrimaryRoutes) + assert.Nil(t, srs3PeerStatus.PrimaryRoutes) // Bring up subnet router 1, making the route available from there. t.Logf("bringing up subnet router r1 (%s)", subRouter1.Hostname()) - t.Logf("expecting r1 (%s) to take over as primary (only one online)", subRouter1.Hostname()) + t.Logf("expecting r1 (%s) to take over as primary, r1 and r3 available", subRouter1.Hostname()) err = subRouter1.Up() - assertNoErr(t, err) + require.NoError(t, err) time.Sleep(5 * time.Second) - var routesAfter1Up []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routesAfter1Up, - ) - assertNoErr(t, err) - assert.Len(t, routesAfter1Up, 2) - - // Node 1 is primary - assert.True(t, routesAfter1Up[0].GetAdvertised()) - assert.True(t, routesAfter1Up[0].GetEnabled()) - assert.True(t, routesAfter1Up[0].GetIsPrimary(), "r1 is back up, expected r1 to become be primary") - - // Node 2 is not primary - assert.True(t, routesAfter1Up[1].GetAdvertised()) - assert.True(t, routesAfter1Up[1].GetEnabled()) - assert.False(t, routesAfter1Up[1].GetIsPrimary(), "r1 is back up, expected r1 to become be primary") - // Verify that the route is announced from subnet router 1 clientStatus, err = client.Status() - assertNoErr(t, err) + require.NoError(t, err) srs1PeerStatus = clientStatus.Peer[srs1.Self.PublicKey] srs2PeerStatus = clientStatus.Peer[srs2.Self.PublicKey] + srs3PeerStatus = clientStatus.Peer[srs3.Self.PublicKey] assert.True(t, srs1PeerStatus.Online, "r1 is back up, r2 down") assert.False(t, srs2PeerStatus.Online, "r1 is back up, r2 down") + assert.True(t, srs3PeerStatus.Online, "r1 is back up, r3 available") assert.NotNil(t, srs1PeerStatus.PrimaryRoutes) assert.Nil(t, srs2PeerStatus.PrimaryRoutes) + assert.Nil(t, srs3PeerStatus.PrimaryRoutes) - if srs1PeerStatus.PrimaryRoutes != nil { - assert.Contains( - t, - srs1PeerStatus.PrimaryRoutes.AsSlice(), - netip.MustParsePrefix(expectedRoutes[string(srs1.Self.ID)]), - ) - } + assert.Contains( + t, + srs1PeerStatus.PrimaryRoutes.AsSlice(), + netip.MustParsePrefix(expectedRoutes[string(srs1.Self.ID)]), + ) // Bring up subnet router 2, should result in no change. t.Logf("bringing up subnet router r2 (%s)", subRouter2.Hostname()) - t.Logf("both online, expecting r1 (%s) to still be primary (no flapping)", subRouter1.Hostname()) + t.Logf("all online, expecting r1 (%s) to still be primary (no flapping)", subRouter1.Hostname()) err = subRouter2.Up() - assertNoErr(t, err) + require.NoError(t, err) time.Sleep(5 * time.Second) - var routesAfter2Up []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routesAfter2Up, - ) - assertNoErr(t, err) - assert.Len(t, routesAfter2Up, 2) - - // Node 1 is not primary - assert.True(t, routesAfter2Up[0].GetAdvertised()) - assert.True(t, routesAfter2Up[0].GetEnabled()) - assert.True(t, routesAfter2Up[0].GetIsPrimary(), "r1 and r2 is back up, expected r1 to _still_ be primary") - - // Node 2 is primary - assert.True(t, routesAfter2Up[1].GetAdvertised()) - assert.True(t, routesAfter2Up[1].GetEnabled()) - assert.False(t, routesAfter2Up[1].GetIsPrimary(), "r1 and r2 is back up, expected r1 to _still_ be primary") - // Verify that the route is announced from subnet router 1 clientStatus, err = client.Status() - assertNoErr(t, err) + require.NoError(t, err) srs1PeerStatus = clientStatus.Peer[srs1.Self.PublicKey] srs2PeerStatus = clientStatus.Peer[srs2.Self.PublicKey] + srs3PeerStatus = clientStatus.Peer[srs3.Self.PublicKey] assert.True(t, srs1PeerStatus.Online, "r1 up, r2 up") assert.True(t, srs2PeerStatus.Online, "r1 up, r2 up") + assert.True(t, srs3PeerStatus.Online, "r1 up, r2 up") - assert.NotNil(t, srs1PeerStatus.PrimaryRoutes) + require.NotNil(t, srs1PeerStatus.PrimaryRoutes) assert.Nil(t, srs2PeerStatus.PrimaryRoutes) + assert.Nil(t, srs3PeerStatus.PrimaryRoutes) - if srs1PeerStatus.PrimaryRoutes != nil { - assert.Contains( - t, - srs1PeerStatus.PrimaryRoutes.AsSlice(), - netip.MustParsePrefix(expectedRoutes[string(srs1.Self.ID)]), - ) - } + assert.Contains( + t, + srs1PeerStatus.PrimaryRoutes.AsSlice(), + netip.MustParsePrefix(expectedRoutes[string(srs1.Self.ID)]), + ) // Disable the route of subnet router 1, making it failover to 2 t.Logf("disabling route in subnet router r1 (%s)", subRouter1.Hostname()) - t.Logf("expecting route to failover to r2 (%s), which is still available", subRouter2.Hostname()) - _, err = headscale.Execute( - []string{ - "headscale", - "routes", - "disable", - "--route", - fmt.Sprintf("%d", routesAfter2Up[0].GetId()), - }) - assertNoErr(t, err) + t.Logf("expecting route to failover to r2 (%s), which is still available with r3", subRouter2.Hostname()) + _, err = headscale.ApproveRoutes(nodes[0].GetId(), []netip.Prefix{}) time.Sleep(5 * time.Second) - var routesAfterDisabling1 []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routesAfterDisabling1, - ) - assertNoErr(t, err) - assert.Len(t, routesAfterDisabling1, 2) + nodes, err = headscale.ListNodes() + require.NoError(t, err) + assert.Len(t, nodes, 4) - t.Logf("routes after disabling r1 %#v", routesAfterDisabling1) - - // Node 1 is not primary - assert.True(t, routesAfterDisabling1[0].GetAdvertised()) - assert.False(t, routesAfterDisabling1[0].GetEnabled()) - assert.False(t, routesAfterDisabling1[0].GetIsPrimary()) - - // Node 2 is primary - assert.True(t, routesAfterDisabling1[1].GetAdvertised()) - assert.True(t, routesAfterDisabling1[1].GetEnabled()) - assert.True(t, routesAfterDisabling1[1].GetIsPrimary()) + assertNodeRouteCount(t, nodes[0], 1, 0, 0) + assertNodeRouteCount(t, nodes[1], 1, 1, 1) + assertNodeRouteCount(t, nodes[2], 1, 1, 1) // Verify that the route is announced from subnet router 1 clientStatus, err = client.Status() - assertNoErr(t, err) + require.NoError(t, err) srs1PeerStatus = clientStatus.Peer[srs1.Self.PublicKey] srs2PeerStatus = clientStatus.Peer[srs2.Self.PublicKey] + srs3PeerStatus = clientStatus.Peer[srs3.Self.PublicKey] assert.Nil(t, srs1PeerStatus.PrimaryRoutes) assert.NotNil(t, srs2PeerStatus.PrimaryRoutes) + assert.Nil(t, srs3PeerStatus.PrimaryRoutes) - if srs2PeerStatus.PrimaryRoutes != nil { - assert.Contains( - t, - srs2PeerStatus.PrimaryRoutes.AsSlice(), - netip.MustParsePrefix(expectedRoutes[string(srs2.Self.ID)]), - ) - } + assert.Contains( + t, + srs2PeerStatus.PrimaryRoutes.AsSlice(), + netip.MustParsePrefix(expectedRoutes[string(srs2.Self.ID)]), + ) // enable the route of subnet router 1, no change expected t.Logf("enabling route in subnet router 1 (%s)", subRouter1.Hostname()) t.Logf("both online, expecting r2 (%s) to still be primary (no flapping)", subRouter2.Hostname()) - _, err = headscale.Execute( - []string{ - "headscale", - "routes", - "enable", - "--route", - fmt.Sprintf("%d", routesAfter2Up[0].GetId()), - }) - assertNoErr(t, err) + _, err = headscale.ApproveRoutes( + nodes[0].GetId(), + util.MustStringsToPrefixes(nodes[0].GetAvailableRoutes()), + ) time.Sleep(5 * time.Second) - var routesAfterEnabling1 []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routesAfterEnabling1, - ) - assertNoErr(t, err) - assert.Len(t, routesAfterEnabling1, 2) + nodes, err = headscale.ListNodes() + require.NoError(t, err) + assert.Len(t, nodes, 4) - // Node 1 is not primary - assert.True(t, routesAfterEnabling1[0].GetAdvertised()) - assert.True(t, routesAfterEnabling1[0].GetEnabled()) - assert.False(t, routesAfterEnabling1[0].GetIsPrimary()) - - // Node 2 is primary - assert.True(t, routesAfterEnabling1[1].GetAdvertised()) - assert.True(t, routesAfterEnabling1[1].GetEnabled()) - assert.True(t, routesAfterEnabling1[1].GetIsPrimary()) + assertNodeRouteCount(t, nodes[0], 1, 1, 1) + assertNodeRouteCount(t, nodes[1], 1, 1, 1) + assertNodeRouteCount(t, nodes[2], 1, 1, 1) // Verify that the route is announced from subnet router 1 clientStatus, err = client.Status() - assertNoErr(t, err) + require.NoError(t, err) srs1PeerStatus = clientStatus.Peer[srs1.Self.PublicKey] srs2PeerStatus = clientStatus.Peer[srs2.Self.PublicKey] + srs3PeerStatus = clientStatus.Peer[srs3.Self.PublicKey] assert.Nil(t, srs1PeerStatus.PrimaryRoutes) - assert.NotNil(t, srs2PeerStatus.PrimaryRoutes) + require.NotNil(t, srs2PeerStatus.PrimaryRoutes) + assert.Nil(t, srs3PeerStatus.PrimaryRoutes) - if srs2PeerStatus.PrimaryRoutes != nil { - assert.Contains( - t, - srs2PeerStatus.PrimaryRoutes.AsSlice(), - netip.MustParsePrefix(expectedRoutes[string(srs2.Self.ID)]), - ) - } - - // delete the route of subnet router 2, failover to one expected - t.Logf("deleting route in subnet router r2 (%s)", subRouter2.Hostname()) - t.Logf("expecting route to failover to r1 (%s)", subRouter1.Hostname()) - _, err = headscale.Execute( - []string{ - "headscale", - "routes", - "delete", - "--route", - fmt.Sprintf("%d", routesAfterEnabling1[1].GetId()), - }) - assertNoErr(t, err) - - time.Sleep(5 * time.Second) - - var routesAfterDeleting2 []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routesAfterDeleting2, + assert.Contains( + t, + srs2PeerStatus.PrimaryRoutes.AsSlice(), + netip.MustParsePrefix(expectedRoutes[string(srs2.Self.ID)]), ) - assertNoErr(t, err) - assert.Len(t, routesAfterDeleting2, 1) - - t.Logf("routes after deleting r2 %#v", routesAfterDeleting2) - - // Node 1 is primary - assert.True(t, routesAfterDeleting2[0].GetAdvertised()) - assert.True(t, routesAfterDeleting2[0].GetEnabled()) - assert.True(t, routesAfterDeleting2[0].GetIsPrimary()) - - // Verify that the route is announced from subnet router 1 - clientStatus, err = client.Status() - assertNoErr(t, err) - - srs1PeerStatus = clientStatus.Peer[srs1.Self.PublicKey] - srs2PeerStatus = clientStatus.Peer[srs2.Self.PublicKey] - - assertNotNil(t, srs1PeerStatus.PrimaryRoutes) - assert.Nil(t, srs2PeerStatus.PrimaryRoutes) - - if srs1PeerStatus.PrimaryRoutes != nil { - assert.Contains( - t, - srs1PeerStatus.PrimaryRoutes.AsSlice(), - netip.MustParsePrefix(expectedRoutes[string(srs1.Self.ID)]), - ) - } } func TestEnableDisableAutoApprovedRoute(t *testing.T) { @@ -829,7 +531,7 @@ func TestEnableDisableAutoApprovedRoute(t *testing.T) { user := "enable-disable-routing" scenario, err := NewScenario(dockertestMaxWait()) - assertNoErrf(t, "failed to create scenario: %s", err) + require.NoErrorf(t, err, "failed to create scenario: %s", err) defer scenario.ShutdownAssertNoPanics(t) spec := map[string]int{ @@ -875,29 +577,14 @@ func TestEnableDisableAutoApprovedRoute(t *testing.T) { "--advertise-routes=" + expectedRoutes, } _, _, err = subRouter1.Execute(command) - assertNoErrf(t, "failed to advertise route: %s", err) + require.NoErrorf(t, err, "failed to advertise route: %s", err) time.Sleep(10 * time.Second) - var routes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routes, - ) - assertNoErr(t, err) - assert.Len(t, routes, 1) - - // All routes should be auto approved and enabled - assert.True(t, routes[0].GetAdvertised()) - assert.True(t, routes[0].GetEnabled()) - assert.True(t, routes[0].GetIsPrimary()) + nodes, err := headscale.ListNodes() + require.NoError(t, err) + assert.Len(t, nodes, 1) + assertNodeRouteCount(t, nodes[0], 1, 1, 1) // Stop advertising route command = []string{ @@ -906,29 +593,14 @@ func TestEnableDisableAutoApprovedRoute(t *testing.T) { "--advertise-routes=", } _, _, err = subRouter1.Execute(command) - assertNoErrf(t, "failed to remove advertised route: %s", err) + require.NoErrorf(t, err, "failed to remove advertised route: %s", err) time.Sleep(10 * time.Second) - var notAdvertisedRoutes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - ¬AdvertisedRoutes, - ) - assertNoErr(t, err) - assert.Len(t, notAdvertisedRoutes, 1) - - // Route is no longer advertised - assert.False(t, notAdvertisedRoutes[0].GetAdvertised()) - assert.False(t, notAdvertisedRoutes[0].GetEnabled()) - assert.True(t, notAdvertisedRoutes[0].GetIsPrimary()) + nodes, err = headscale.ListNodes() + require.NoError(t, err) + assert.Len(t, nodes, 1) + assertNodeRouteCount(t, nodes[0], 0, 1, 0) // Advertise route again command = []string{ @@ -937,29 +609,14 @@ func TestEnableDisableAutoApprovedRoute(t *testing.T) { "--advertise-routes=" + expectedRoutes, } _, _, err = subRouter1.Execute(command) - assertNoErrf(t, "failed to advertise route: %s", err) + require.NoErrorf(t, err, "failed to advertise route: %s", err) time.Sleep(10 * time.Second) - var reAdvertisedRoutes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &reAdvertisedRoutes, - ) - assertNoErr(t, err) - assert.Len(t, reAdvertisedRoutes, 1) - - // All routes should be auto approved and enabled - assert.True(t, reAdvertisedRoutes[0].GetAdvertised()) - assert.True(t, reAdvertisedRoutes[0].GetEnabled()) - assert.True(t, reAdvertisedRoutes[0].GetIsPrimary()) + nodes, err = headscale.ListNodes() + require.NoError(t, err) + assert.Len(t, nodes, 1) + assertNodeRouteCount(t, nodes[0], 1, 1, 1) } func TestAutoApprovedSubRoute2068(t *testing.T) { @@ -968,35 +625,39 @@ func TestAutoApprovedSubRoute2068(t *testing.T) { expectedRoutes := "10.42.7.0/24" - user := "subroute" + user := "user1" scenario, err := NewScenario(dockertestMaxWait()) - assertNoErrf(t, "failed to create scenario: %s", err) + require.NoErrorf(t, err, "failed to create scenario: %s", err) defer scenario.ShutdownAssertNoPanics(t) spec := map[string]int{ user: 1, } - err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{tsic.WithTags([]string{"tag:approve"})}, hsic.WithTestName("clienableroute"), hsic.WithACLPolicy( - &policy.ACLPolicy{ - ACLs: []policy.ACL{ - { - Action: "accept", - Sources: []string{"*"}, - Destinations: []string{"*:*"}, + err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{tsic.WithTags([]string{"tag:approve"})}, + hsic.WithTestName("clienableroute"), + hsic.WithEmbeddedDERPServerOnly(), + hsic.WithTLS(), + hsic.WithACLPolicy( + &policy.ACLPolicy{ + ACLs: []policy.ACL{ + { + Action: "accept", + Sources: []string{"*"}, + Destinations: []string{"*:*"}, + }, + }, + TagOwners: map[string][]string{ + "tag:approve": {user}, + }, + AutoApprovers: policy.AutoApprovers{ + Routes: map[string][]string{ + "10.42.0.0/16": {"tag:approve"}, + }, }, }, - TagOwners: map[string][]string{ - "tag:approve": {user}, - }, - AutoApprovers: policy.AutoApprovers{ - Routes: map[string][]string{ - "10.42.0.0/16": {"tag:approve"}, - }, - }, - }, - )) + )) assertNoErrHeadscaleEnv(t, err) allClients, err := scenario.ListTailscaleClients() @@ -1017,38 +678,14 @@ func TestAutoApprovedSubRoute2068(t *testing.T) { "--advertise-routes=" + expectedRoutes, } _, _, err = subRouter1.Execute(command) - assertNoErrf(t, "failed to advertise route: %s", err) + require.NoErrorf(t, err, "failed to advertise route: %s", err) time.Sleep(10 * time.Second) - var routes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routes, - ) - assertNoErr(t, err) - assert.Len(t, routes, 1) - - want := []*v1.Route{ - { - Id: 1, - Prefix: expectedRoutes, - Advertised: true, - Enabled: true, - IsPrimary: true, - }, - } - - if diff := cmp.Diff(want, routes, cmpopts.IgnoreUnexported(v1.Route{}), cmpopts.IgnoreFields(v1.Route{}, "Node", "CreatedAt", "UpdatedAt", "DeletedAt")); diff != "" { - t.Errorf("unexpected routes (-want +got):\n%s", diff) - } + nodes, err := headscale.ListNodes() + require.NoError(t, err) + assert.Len(t, nodes, 1) + assertNodeRouteCount(t, nodes[0], 1, 1, 1) } // TestSubnetRouteACL verifies that Subnet routes are distributed @@ -1062,7 +699,7 @@ func TestSubnetRouteACL(t *testing.T) { user := "subnet-route-acl" scenario, err := NewScenario(dockertestMaxWait()) - assertNoErrf(t, "failed to create scenario: %s", err) + require.NoErrorf(t, err, "failed to create scenario: %s", err) defer scenario.ShutdownAssertNoPanics(t) spec := map[string]int{ @@ -1127,12 +764,9 @@ func TestSubnetRouteACL(t *testing.T) { client := allClients[1] - // advertise HA route on node 1 and 2 - // ID 1 will be primary - // ID 2 will be secondary for _, client := range allClients { status, err := client.Status() - assertNoErr(t, err) + require.NoError(t, err) if route, ok := expectedRoutes[string(status.Self.ID)]; ok { command := []string{ @@ -1141,103 +775,61 @@ func TestSubnetRouteACL(t *testing.T) { "--advertise-routes=" + route, } _, _, err = client.Execute(command) - assertNoErrf(t, "failed to advertise route: %s", err) + require.NoErrorf(t, err, "failed to advertise route: %s", err) } } err = scenario.WaitForTailscaleSync() assertNoErrSync(t, err) - var routes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routes, - ) + nodes, err := headscale.ListNodes() + require.NoError(t, err) + require.Len(t, nodes, 2) - assertNoErr(t, err) - assert.Len(t, routes, 1) - - for _, route := range routes { - assert.True(t, route.GetAdvertised()) - assert.False(t, route.GetEnabled()) - assert.False(t, route.GetIsPrimary()) - } + assertNodeRouteCount(t, nodes[0], 1, 0, 0) + assertNodeRouteCount(t, nodes[1], 0, 0, 0) // Verify that no routes has been sent to the client, // they are not yet enabled. for _, client := range allClients { status, err := client.Status() - assertNoErr(t, err) + require.NoError(t, err) for _, peerKey := range status.Peers() { peerStatus := status.Peer[peerKey] assert.Nil(t, peerStatus.PrimaryRoutes) + assertPeerSubnetRoutes(t, peerStatus, nil) } } - // Enable all routes - for _, route := range routes { - _, err = headscale.Execute( - []string{ - "headscale", - "routes", - "enable", - "--route", - strconv.Itoa(int(route.GetId())), - }) - assertNoErr(t, err) - } + _, err = headscale.ApproveRoutes( + 1, + []netip.Prefix{netip.MustParsePrefix(expectedRoutes["1"])}, + ) + require.NoError(t, err) time.Sleep(5 * time.Second) - var enablingRoutes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &enablingRoutes, - ) - assertNoErr(t, err) - assert.Len(t, enablingRoutes, 1) + nodes, err = headscale.ListNodes() + require.NoError(t, err) + require.Len(t, nodes, 2) - // Node 1 has active route - assert.True(t, enablingRoutes[0].GetAdvertised()) - assert.True(t, enablingRoutes[0].GetEnabled()) - assert.True(t, enablingRoutes[0].GetIsPrimary()) + assertNodeRouteCount(t, nodes[0], 1, 1, 1) + assertNodeRouteCount(t, nodes[1], 0, 0, 0) // Verify that the client has routes from the primary machine srs1, _ := subRouter1.Status() clientStatus, err := client.Status() - assertNoErr(t, err) + require.NoError(t, err) srs1PeerStatus := clientStatus.Peer[srs1.Self.PublicKey] - assertNotNil(t, srs1PeerStatus.PrimaryRoutes) - - t.Logf("subnet1 has following routes: %v", srs1PeerStatus.PrimaryRoutes.AsSlice()) - assert.Len(t, srs1PeerStatus.PrimaryRoutes.AsSlice(), 1) - assert.Contains( - t, - srs1PeerStatus.PrimaryRoutes.AsSlice(), - netip.MustParsePrefix(expectedRoutes[string(srs1.Self.ID)]), - ) + assertPeerSubnetRoutes(t, srs1PeerStatus, []netip.Prefix{netip.MustParsePrefix(expectedRoutes["1"])}) clientNm, err := client.Netmap() - assertNoErr(t, err) + require.NoError(t, err) wantClientFilter := []filter.Match{ { @@ -1269,7 +861,7 @@ func TestSubnetRouteACL(t *testing.T) { } subnetNm, err := subRouter1.Netmap() - assertNoErr(t, err) + require.NoError(t, err) wantSubnetFilter := []filter.Match{ { @@ -1353,27 +945,12 @@ func TestEnablingExitRoutes(t *testing.T) { err = scenario.WaitForTailscaleSync() assertNoErrSync(t, err) - var routes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &routes, - ) + nodes, err := headscale.ListNodes() + require.NoError(t, err) + require.Len(t, nodes, 2) - assertNoErr(t, err) - assert.Len(t, routes, 4) - - for _, route := range routes { - assert.True(t, route.GetAdvertised()) - assert.False(t, route.GetEnabled()) - assert.False(t, route.GetIsPrimary()) - } + assertNodeRouteCount(t, nodes[0], 2, 0, 0) + assertNodeRouteCount(t, nodes[1], 2, 0, 0) // Verify that no routes has been sent to the client, // they are not yet enabled. @@ -1388,38 +965,25 @@ func TestEnablingExitRoutes(t *testing.T) { } } - // Enable all routes - for _, route := range routes { - _, err = headscale.Execute( - []string{ - "headscale", - "routes", - "enable", - "--route", - strconv.Itoa(int(route.GetId())), - }) - assertNoErr(t, err) - } - - var enablingRoutes []*v1.Route - err = executeAndUnmarshal( - headscale, - []string{ - "headscale", - "routes", - "list", - "--output", - "json", - }, - &enablingRoutes, + // Enable all routes, but do v4 on one and v6 on other to ensure they + // are both added since they are exit routes. + _, err = headscale.ApproveRoutes( + nodes[0].GetId(), + []netip.Prefix{tsaddr.AllIPv4()}, ) - assertNoErr(t, err) - assert.Len(t, enablingRoutes, 4) + require.NoError(t, err) + _, err = headscale.ApproveRoutes( + nodes[1].GetId(), + []netip.Prefix{tsaddr.AllIPv6()}, + ) + require.NoError(t, err) - for _, route := range enablingRoutes { - assert.True(t, route.GetAdvertised()) - assert.True(t, route.GetEnabled()) - } + nodes, err = headscale.ListNodes() + require.NoError(t, err) + require.Len(t, nodes, 2) + + assertNodeRouteCount(t, nodes[0], 2, 2, 2) + assertNodeRouteCount(t, nodes[1], 2, 2, 2) time.Sleep(5 * time.Second) @@ -1438,3 +1002,29 @@ func TestEnablingExitRoutes(t *testing.T) { } } } + +// assertPeerSubnetRoutes asserts that the peer has the expected subnet routes. +func assertPeerSubnetRoutes(t *testing.T, status *ipnstate.PeerStatus, expected []netip.Prefix) { + t.Helper() + if status.AllowedIPs.Len() <= 2 && len(expected) != 0 { + t.Errorf("peer %s (%s) has no subnet routes, expected %v", status.HostName, status.ID, expected) + return + } + + if len(expected) == 0 { + expected = []netip.Prefix{} + } + + got := status.AllowedIPs.AsSlice()[2:] + + if diff := cmp.Diff(expected, got, util.PrefixComparer); diff != "" { + t.Errorf("peer %s (%s) subnet routes, unexpected result (-want +got):\n%s", status.HostName, status.ID, diff) + } +} + +func assertNodeRouteCount(t *testing.T, node *v1.Node, announced, approved, subnet int) { + t.Helper() + assert.Len(t, node.GetAvailableRoutes(), announced) + assert.Len(t, node.GetApprovedRoutes(), approved) + assert.Len(t, node.GetSubnetRoutes(), subnet) +} diff --git a/integration/tailscale.go b/integration/tailscale.go index da9b8754..9ab6e1e2 100644 --- a/integration/tailscale.go +++ b/integration/tailscale.go @@ -29,6 +29,7 @@ type TailscaleClient interface { IPs() ([]netip.Addr, error) FQDN() (string, error) Status(...bool) (*ipnstate.Status, error) + MustStatus() *ipnstate.Status Netmap() (*netmap.NetworkMap, error) DebugDERPRegion(region string) (*ipnstate.DebugDERPRegionReport, error) Netcheck() (*netcheck.Report, error) diff --git a/integration/tsic/tsic.go b/integration/tsic/tsic.go index 8bfd4f60..b501dc1a 100644 --- a/integration/tsic/tsic.go +++ b/integration/tsic/tsic.go @@ -624,6 +624,16 @@ func (t *TailscaleInContainer) Status(save ...bool) (*ipnstate.Status, error) { return &status, err } +// Status returns the ipnstate.Status of the Tailscale instance. +func (t *TailscaleInContainer) MustStatus() *ipnstate.Status { + status, err := t.Status() + if err != nil { + panic(err) + } + + return status +} + // Netmap returns the current Netmap (netmap.NetworkMap) of the Tailscale instance. // Only works with Tailscale 1.56 and newer. // Panics if version is lower then minimum. diff --git a/proto/headscale/v1/headscale.proto b/proto/headscale/v1/headscale.proto index 4a2867a6..7e0672bb 100644 --- a/proto/headscale/v1/headscale.proto +++ b/proto/headscale/v1/headscale.proto @@ -7,10 +7,8 @@ import "google/api/annotations.proto"; import "headscale/v1/user.proto"; import "headscale/v1/preauthkey.proto"; import "headscale/v1/node.proto"; -import "headscale/v1/routes.proto"; import "headscale/v1/apikey.proto"; import "headscale/v1/policy.proto"; -// import "headscale/v1/device.proto"; service HeadscaleService { // --- User start --- @@ -87,6 +85,14 @@ service HeadscaleService { }; } + rpc SetApprovedRoutes(SetApprovedRoutesRequest) + returns (SetApprovedRoutesResponse) { + option (google.api.http) = { + post : "/api/v1/node/{node_id}/approve_routes" + body : "*" + }; + } + rpc RegisterNode(RegisterNodeRequest) returns (RegisterNodeResponse) { option (google.api.http) = { post : "/api/v1/node/register" @@ -133,39 +139,6 @@ service HeadscaleService { // --- Node end --- - // --- Route start --- - rpc GetRoutes(GetRoutesRequest) returns (GetRoutesResponse) { - option (google.api.http) = { - get : "/api/v1/routes" - }; - } - - rpc EnableRoute(EnableRouteRequest) returns (EnableRouteResponse) { - option (google.api.http) = { - post : "/api/v1/routes/{route_id}/enable" - }; - } - - rpc DisableRoute(DisableRouteRequest) returns (DisableRouteResponse) { - option (google.api.http) = { - post : "/api/v1/routes/{route_id}/disable" - }; - } - - rpc GetNodeRoutes(GetNodeRoutesRequest) returns (GetNodeRoutesResponse) { - option (google.api.http) = { - get : "/api/v1/node/{node_id}/routes" - }; - } - - rpc DeleteRoute(DeleteRouteRequest) returns (DeleteRouteResponse) { - option (google.api.http) = { - delete : "/api/v1/routes/{route_id}" - }; - } - - // --- Route end --- - // --- ApiKeys start --- rpc CreateApiKey(CreateApiKeyRequest) returns (CreateApiKeyResponse) { option (google.api.http) = { diff --git a/proto/headscale/v1/node.proto b/proto/headscale/v1/node.proto index 3c75ee77..1b6021ce 100644 --- a/proto/headscale/v1/node.proto +++ b/proto/headscale/v1/node.proto @@ -48,6 +48,9 @@ message Node { repeated string valid_tags = 20; string given_name = 21; bool online = 22; + repeated string approved_routes = 23; + repeated string available_routes = 24; + repeated string subnet_routes = 25; } message RegisterNodeRequest { @@ -68,6 +71,13 @@ message SetTagsRequest { message SetTagsResponse { Node node = 1; } +message SetApprovedRoutesRequest { + uint64 node_id = 1; + repeated string routes = 2; +} + +message SetApprovedRoutesResponse { Node node = 1; } + message DeleteNodeRequest { uint64 node_id = 1; } message DeleteNodeResponse {} diff --git a/proto/headscale/v1/routes.proto b/proto/headscale/v1/routes.proto deleted file mode 100644 index 7ea29a01..00000000 --- a/proto/headscale/v1/routes.proto +++ /dev/null @@ -1,39 +0,0 @@ -syntax = "proto3"; -package headscale.v1; -option go_package = "github.com/juanfont/headscale/gen/go/v1"; - -import "google/protobuf/timestamp.proto"; -import "headscale/v1/node.proto"; - -message Route { - uint64 id = 1; - Node node = 2; - string prefix = 3; - bool advertised = 4; - bool enabled = 5; - bool is_primary = 6; - - google.protobuf.Timestamp created_at = 7; - google.protobuf.Timestamp updated_at = 8; - google.protobuf.Timestamp deleted_at = 9; -} - -message GetRoutesRequest {} - -message GetRoutesResponse { repeated Route routes = 1; } - -message EnableRouteRequest { uint64 route_id = 1; } - -message EnableRouteResponse {} - -message DisableRouteRequest { uint64 route_id = 1; } - -message DisableRouteResponse {} - -message GetNodeRoutesRequest { uint64 node_id = 1; } - -message GetNodeRoutesResponse { repeated Route routes = 1; } - -message DeleteRouteRequest { uint64 route_id = 1; } - -message DeleteRouteResponse {}