diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml index d9c52c7b..b8fd85a6 100644 --- a/.github/workflows/test-integration.yml +++ b/.github/workflows/test-integration.yml @@ -29,4 +29,4 @@ jobs: - name: Run Integration tests if: steps.changed-files.outputs.any_changed == 'true' - run: go test -tags integration -timeout 30m + run: make test_integration diff --git a/CHANGELOG.md b/CHANGELOG.md index 531137fa..d44db566 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,17 @@ # CHANGELOG -**TBD (TBD):** +**0.15.0 (2022-xx-xx):** -**0.14.0 (2022-xx-xx):** +**BREAKING**: + +- Boundaries between Namespaces has been removed and all nodes can communicate by default [#357](https://github.com/juanfont/headscale/pull/357) + - To limit access between nodes, use [ACLs](./docs/acls.md). + +**Changes**: + +- Fix a bug were the same IP could be assigned to multiple hosts if joined in quick succession [#346](https://github.com/juanfont/headscale/pull/346) + +**0.14.0 (2022-02-24):** **UPCOMING BREAKING**: From the **next** version (`0.15.0`), all machines will be able to communicate regardless of @@ -36,6 +45,10 @@ This is a part of aligning `headscale`'s behaviour with Tailscale's upstream beh - Add API Key support - Enable remote control of `headscale` via CLI [docs](docs/remote-cli.md) - Enable HTTP API (beta, subject to change) +- OpenID Connect users will be mapped per namespaces + - Each user will get its own namespace, created if it does not exist + - `oidc.domain_map` option has been removed + - `strip_email_domain` option has been added (see [config-example.yaml](./config_example.yaml)) **Changes**: diff --git a/Makefile b/Makefile index 52145090..266dadb8 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ test: @go test -coverprofile=coverage.out ./... test_integration: - go test -tags integration -timeout 30m -count=1 ./... + go test -failfast -tags integration -timeout 30m -count=1 ./... test_integration_cli: go test -tags integration -v integration_cli_test.go integration_common_test.go diff --git a/README.md b/README.md index d23a216a..fb5d9692 100644 --- a/README.md +++ b/README.md @@ -2,44 +2,67 @@ ![ci](https://github.com/juanfont/headscale/actions/workflows/test.yml/badge.svg) -An open source, self-hosted implementation of the Tailscale coordination server. +An open source, self-hosted implementation of the Tailscale control server. Join our [Discord](https://discord.gg/XcQxk2VHjx) server for a chat. -**Note:** Always select the same GitHub tag as the released version you use to ensure you have the correct example configuration and documentation. The `main` branch might contain unreleased changes. +**Note:** Always select the same GitHub tag as the released version you use +to ensure you have the correct example configuration and documentation. +The `main` branch might contain unreleased changes. -## Overview +## What is Tailscale -Tailscale is [a modern VPN](https://tailscale.com/) built on top of [Wireguard](https://www.wireguard.com/). It [works like an overlay network](https://tailscale.com/blog/how-tailscale-works/) between the computers of your networks - using [NAT traversal](https://tailscale.com/blog/how-nat-traversal-works/). +Tailscale is [a modern VPN](https://tailscale.com/) built on top of +[Wireguard](https://www.wireguard.com/). +It [works like an overlay network](https://tailscale.com/blog/how-tailscale-works/) +between the computers of your networks - using +[NAT traversal](https://tailscale.com/blog/how-nat-traversal-works/). -Everything in Tailscale is Open Source, except the GUI clients for proprietary OS (Windows and macOS/iOS), and the 'coordination/control server'. +Everything in Tailscale is Open Source, except the GUI clients for proprietary OS +(Windows and macOS/iOS), and the control server. -The control server works as an exchange point of Wireguard public keys for the nodes in the Tailscale network. It also assigns the IP addresses of the clients, creates the boundaries between each user, enables sharing machines between users, and exposes the advertised routes of your nodes. +The control server works as an exchange point of Wireguard public keys for the +nodes in the Tailscale network. It assigns the IP addresses of the clients, +creates the boundaries between each user, enables sharing machines between users, +and exposes the advertised routes of your nodes. -headscale implements this coordination server. +A [Tailscale network (tailnet)](https://tailscale.com/kb/1136/tailnet/) is private +network which Tailscale assigns to a user in terms of private users or an +organisations. + +## Design goal + +`headscale` aims to implement a self-hosted, open source alternative to the Tailscale +control server. `headscale` has a narrower scope and an instance of `headscale` +implements a _single_ Tailnet, which is typically what a single organisation, or +home/personal setup would use. + +`headscale` uses terms that maps to Tailscale's control server, consult the +[glossary](./docs/glossary.md) for explainations. ## Support -If you like `headscale` and find it useful, there is sponsorship and donation buttons available in the repo. +If you like `headscale` and find it useful, there is a sponsorship and donation +buttons available in the repo. -If you would like to sponsor features, bugs or prioritisation, reach out to one of the maintainers. +If you would like to sponsor features, bugs or prioritisation, reach out to +one of the maintainers. -## Status +## Features -- [x] Base functionality (nodes can communicate with each other) -- [x] Node registration through the web flow -- [x] Network changes are relayed to the nodes -- [x] Namespaces support (~tailnets in Tailscale.com naming) -- [x] Routing (advertise & accept, including exit nodes) -- [x] Node registration via pre-auth keys (including reusable keys, and ephemeral node support) -- [x] JSON-formatted output -- [x] ACLs -- [x] Taildrop (File Sharing) -- [x] Support for alternative IP ranges in the tailnets (default Tailscale's 100.64.0.0/10) -- [x] DNS (passing DNS servers to nodes) -- [x] Single-Sign-On (via Open ID Connect) -- [x] Share nodes between namespaces -- [x] MagicDNS (see `docs/`) +- Full "base" support of Tailscale's features +- Configurable DNS + - [Split DNS](https://tailscale.com/kb/1054/dns/#using-dns-settings-in-the-admin-console) +- Node registration + - Single-Sign-On (via Open ID Connect) + - Pre authenticated key +- Taildrop (File Sharing) +- [Access control lists](https://tailscale.com/kb/1018/acls/) +- [MagicDNS](https://tailscale.com/kb/1081/magicdns) +- Support for multiple IP ranges in the tailnet +- Dual stack (IPv4 and IPv6) +- Routing advertising (including exit nodes) +- Ephemeral nodes ## Client OS support @@ -53,10 +76,6 @@ If you would like to sponsor features, bugs or prioritisation, reach out to one | Android | [You need to compile the client yourself](https://github.com/juanfont/headscale/issues/58#issuecomment-885255270) | | iOS | Not yet | -## Roadmap - -Suggestions/PRs welcomed! - ## Running headscale Please have a look at the documentation under [`docs/`](docs/). @@ -68,11 +87,15 @@ Please have a look at the documentation under [`docs/`](docs/). ## Contributing -To contribute to Headscale you would need the lastest version of [Go](https://golang.org) and [Buf](https://buf.build)(Protobuf generator). +To contribute to headscale you would need the lastest version of [Go](https://golang.org) +and [Buf](https://buf.build)(Protobuf generator). + +PRs and suggestions are welcome. ### Code style -To ensure we have some consistency with a growing number of contributions, this project has adopted linting and style/formatting rules: +To ensure we have some consistency with a growing number of contributions, +this project has adopted linting and style/formatting rules: The **Go** code is linted with [`golangci-lint`](https://golangci-lint.run) and formatted with [`golines`](https://github.com/segmentio/golines) (width 88) and @@ -99,7 +122,8 @@ make install-protobuf-plugins ### Testing and building -Some parts of the project require the generation of Go code from Protobuf (if changes are made in `proto/`) and it must be (re-)generated with: +Some parts of the project require the generation of Go code from Protobuf +(if changes are made in `proto/`) and it must be (re-)generated with: ```shell make generate diff --git a/acls.go b/acls.go index db2fc588..ce14a89a 100644 --- a/acls.go +++ b/acls.go @@ -90,7 +90,7 @@ func (h *Headscale) generateACLRules() ([]tailcfg.FilterRule, error) { return nil, errEmptyPolicy } - machines, err := h.ListAllMachines() + machines, err := h.ListMachines() if err != nil { return nil, err } diff --git a/api.go b/api.go index 073be5e2..bb5495ae 100644 --- a/api.go +++ b/api.go @@ -574,6 +574,9 @@ func (h *Headscale) handleAuthKey( Str("func", "handleAuthKey"). Str("machine", machine.Name). Msg("Authentication key was valid, proceeding to acquire IP addresses") + + h.ipAllocationMutex.Lock() + ips, err := h.getAvailableIPs() if err != nil { log.Error(). @@ -602,6 +605,8 @@ func (h *Headscale) handleAuthKey( machine.Registered = true machine.RegisterMethod = RegisterMethodAuthKey h.db.Save(&machine) + + h.ipAllocationMutex.Unlock() } pak.Used = true diff --git a/app.go b/app.go index a67031e8..f8b18fb4 100644 --- a/app.go +++ b/app.go @@ -114,10 +114,10 @@ type Config struct { } type OIDCConfig struct { - Issuer string - ClientID string - ClientSecret string - MatchMap map[string]string + Issuer string + ClientID string + ClientSecret string + StripEmaildomain bool } type DERPConfig struct { @@ -155,6 +155,8 @@ type Headscale struct { oidcStateCache *cache.Cache requestedExpiryCache *cache.Cache + + ipAllocationMutex sync.Mutex } // Look up the TLS constant relative to user-supplied TLS client diff --git a/cmd/headscale/cli/nodes.go b/cmd/headscale/cli/nodes.go index d6b86ee1..a05339c4 100644 --- a/cmd/headscale/cli/nodes.go +++ b/cmd/headscale/cli/nodes.go @@ -46,30 +46,6 @@ func init() { log.Fatalf(err.Error()) } nodeCmd.AddCommand(deleteNodeCmd) - - shareMachineCmd.Flags().StringP("namespace", "n", "", "Namespace") - err = shareMachineCmd.MarkFlagRequired("namespace") - if err != nil { - log.Fatalf(err.Error()) - } - shareMachineCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") - err = shareMachineCmd.MarkFlagRequired("identifier") - if err != nil { - log.Fatalf(err.Error()) - } - nodeCmd.AddCommand(shareMachineCmd) - - unshareMachineCmd.Flags().StringP("namespace", "n", "", "Namespace") - err = unshareMachineCmd.MarkFlagRequired("namespace") - if err != nil { - log.Fatalf(err.Error()) - } - unshareMachineCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") - err = unshareMachineCmd.MarkFlagRequired("identifier") - if err != nil { - log.Fatalf(err.Error()) - } - nodeCmd.AddCommand(unshareMachineCmd) } var nodeCmd = &cobra.Command{ @@ -317,139 +293,6 @@ var deleteNodeCmd = &cobra.Command{ }, } -func sharingWorker( - cmd *cobra.Command, -) (string, *v1.Machine, *v1.Namespace, error) { - output, _ := cmd.Flags().GetString("output") - namespaceStr, err := cmd.Flags().GetString("namespace") - if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting namespace: %s", err), output) - - return "", nil, nil, err - } - - ctx, client, conn, cancel := getHeadscaleCLIClient() - defer cancel() - defer conn.Close() - - identifier, err := cmd.Flags().GetUint64("identifier") - if err != nil { - ErrorOutput(err, fmt.Sprintf("Error converting ID to integer: %s", err), output) - - return "", nil, nil, err - } - - machineRequest := &v1.GetMachineRequest{ - MachineId: identifier, - } - - machineResponse, err := client.GetMachine(ctx, machineRequest) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Error getting node node: %s", status.Convert(err).Message()), - output, - ) - - return "", nil, nil, err - } - - namespaceRequest := &v1.GetNamespaceRequest{ - Name: namespaceStr, - } - - namespaceResponse, err := client.GetNamespace(ctx, namespaceRequest) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Error getting node node: %s", status.Convert(err).Message()), - output, - ) - - return "", nil, nil, err - } - - return output, machineResponse.GetMachine(), namespaceResponse.GetNamespace(), nil -} - -var shareMachineCmd = &cobra.Command{ - Use: "share", - Short: "Shares a node from the current namespace to the specified one", - Run: func(cmd *cobra.Command, args []string) { - output, machine, namespace, err := sharingWorker(cmd) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Failed to fetch namespace or machine: %s", err), - output, - ) - - return - } - - ctx, client, conn, cancel := getHeadscaleCLIClient() - defer cancel() - defer conn.Close() - - request := &v1.ShareMachineRequest{ - MachineId: machine.Id, - Namespace: namespace.Name, - } - - response, err := client.ShareMachine(ctx, request) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Error sharing node: %s", status.Convert(err).Message()), - output, - ) - - return - } - - SuccessOutput(response.Machine, "Node shared", output) - }, -} - -var unshareMachineCmd = &cobra.Command{ - Use: "unshare", - Short: "Unshares a node from the specified namespace", - Run: func(cmd *cobra.Command, args []string) { - output, machine, namespace, err := sharingWorker(cmd) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Failed to fetch namespace or machine: %s", err), - output, - ) - - return - } - - ctx, client, conn, cancel := getHeadscaleCLIClient() - defer cancel() - defer conn.Close() - - request := &v1.UnshareMachineRequest{ - MachineId: machine.Id, - Namespace: namespace.Name, - } - - response, err := client.UnshareMachine(ctx, request) - if err != nil { - ErrorOutput( - err, - fmt.Sprintf("Error unsharing node: %s", status.Convert(err).Message()), - output, - ) - - return - } - - SuccessOutput(response.Machine, "Node unshared", output) - }, -} - func nodesToPtables( currentNamespace string, machines []*v1.Machine, diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go index f287cd4a..381f1800 100644 --- a/cmd/headscale/cli/utils.go +++ b/cmd/headscale/cli/utils.go @@ -10,7 +10,6 @@ import ( "net/url" "os" "path/filepath" - "regexp" "strconv" "strings" "time" @@ -65,6 +64,8 @@ func LoadConfig(path string) error { viper.SetDefault("cli.timeout", "5s") viper.SetDefault("cli.insecure", false) + viper.SetDefault("oidc.strip_email_domain", true) + if err := viper.ReadInConfig(); err != nil { return fmt.Errorf("fatal error reading config file: %w", err) } @@ -346,9 +347,10 @@ func getHeadscaleConfig() headscale.Config { UnixSocketPermission: GetFileMode("unix_socket_permission"), OIDC: headscale.OIDCConfig{ - Issuer: viper.GetString("oidc.issuer"), - ClientID: viper.GetString("oidc.client_id"), - ClientSecret: viper.GetString("oidc.client_secret"), + Issuer: viper.GetString("oidc.issuer"), + ClientID: viper.GetString("oidc.client_id"), + ClientSecret: viper.GetString("oidc.client_secret"), + StripEmaildomain: viper.GetBool("oidc.strip_email_domain"), }, CLI: headscale.CLIConfig{ @@ -378,8 +380,6 @@ func getHeadscaleApp() (*headscale.Headscale, error) { cfg := getHeadscaleConfig() - cfg.OIDC.MatchMap = loadOIDCMatchMap() - app, err := headscale.NewHeadscale(cfg) if err != nil { return nil, err @@ -536,18 +536,6 @@ func (tokenAuth) RequireTransportSecurity() bool { return true } -// loadOIDCMatchMap is a wrapper around viper to verifies that the keys in -// the match map is valid regex strings. -func loadOIDCMatchMap() map[string]string { - strMap := viper.GetStringMapString("oidc.domain_map") - - for oidcMatcher := range strMap { - _ = regexp.MustCompile(oidcMatcher) - } - - return strMap -} - func GetFileMode(key string) fs.FileMode { modeStr := viper.GetString(key) diff --git a/config-example.yaml b/config-example.yaml index 8b028dba..157805ed 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -196,7 +196,9 @@ unix_socket_permission: "0770" # client_id: "your-oidc-client-id" # client_secret: "your-oidc-client-secret" # -# # Domain map is used to map incomming users (by their email) to -# # a namespace. The key can be a string, or regex. -# domain_map: -# ".*": default-namespace +# If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed. +# This will transform `first-name.last-name@example.com` to the namespace `first-name.last-name` +# If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following +# namespace: `first-name.last-name.example.com` +# +# strip_email_domain: true diff --git a/db.go b/db.go index feee7474..8db7bc69 100644 --- a/db.go +++ b/db.go @@ -54,10 +54,7 @@ func (h *Headscale) initDB() error { return err } - err = db.AutoMigrate(&SharedMachine{}) - if err != nil { - return err - } + _ = db.Migrator().DropTable("shared_machines") err = db.AutoMigrate(&APIKey{}) if err != nil { diff --git a/dns.go b/dns.go index 45e0faeb..9a91cff0 100644 --- a/dns.go +++ b/dns.go @@ -165,11 +165,7 @@ func getMapResponseDNSConfig( dnsConfig.Domains, fmt.Sprintf( "%s.%s", - strings.ReplaceAll( - machine.Namespace.Name, - "@", - ".", - ), // Replace @ with . for valid domain for machine + machine.Namespace.Name, baseDomain, ), ) diff --git a/dns_test.go b/dns_test.go index 80ee83bb..23a34ca7 100644 --- a/dns_test.go +++ b/dns_test.go @@ -225,9 +225,6 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) { } app.db.Save(machine2InShared1) - err = app.AddSharedMachineToNamespace(machineInShared2, namespaceShared1) - c.Assert(err, check.IsNil) - baseDomain := "foobar.headscale.net" dnsConfigOrig := tailcfg.DNSConfig{ Routes: make(map[string][]dnstype.Resolver), @@ -245,7 +242,8 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) { peersOfMachineInShared1, ) c.Assert(dnsConfig, check.NotNil) - c.Assert(len(dnsConfig.Routes), check.Equals, 2) + + c.Assert(len(dnsConfig.Routes), check.Equals, 3) domainRouteShared1 := fmt.Sprintf("%s.%s", namespaceShared1.Name, baseDomain) _, ok := dnsConfig.Routes[domainRouteShared1] @@ -257,7 +255,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) { domainRouteShared3 := fmt.Sprintf("%s.%s", namespaceShared3.Name, baseDomain) _, ok = dnsConfig.Routes[domainRouteShared3] - c.Assert(ok, check.Equals, false) + c.Assert(ok, check.Equals, true) } func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) { @@ -374,9 +372,6 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) { } app.db.Save(machine2InShared1) - err = app.AddSharedMachineToNamespace(machineInShared2, namespaceShared1) - c.Assert(err, check.IsNil) - baseDomain := "foobar.headscale.net" dnsConfigOrig := tailcfg.DNSConfig{ Routes: make(map[string][]dnstype.Resolver), diff --git a/docs/glossary.md b/docs/glossary.md index aa3e2e35..c38060d5 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -1,3 +1,6 @@ # Glossary -- Namespace: Collection of Tailscale nodes that can see each other. In Tailscale.com this is called Tailnet. +| Term | Description | +| --------- | --------------------------------------------------------------------------------------------------------------------- | +| Machine | A machine is a single entity connected to `headscale`, typically an installation of Tailscale. Also known as **Node** | +| Namespace | A namespace is a logical grouping of machines "owned" by the same entity, in Tailscale, this is typically a User | diff --git a/gen/go/headscale/v1/apikey.pb.go b/gen/go/headscale/v1/apikey.pb.go index ace8b18c..9e6fddb7 100644 --- a/gen/go/headscale/v1/apikey.pb.go +++ b/gen/go/headscale/v1/apikey.pb.go @@ -7,12 +7,11 @@ package v1 import ( - reflect "reflect" - sync "sync" - 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 ( diff --git a/gen/go/headscale/v1/device.pb.go b/gen/go/headscale/v1/device.pb.go index 58792512..26607019 100644 --- a/gen/go/headscale/v1/device.pb.go +++ b/gen/go/headscale/v1/device.pb.go @@ -7,12 +7,11 @@ package v1 import ( - reflect "reflect" - sync "sync" - 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 ( diff --git a/gen/go/headscale/v1/headscale.pb.go b/gen/go/headscale/v1/headscale.pb.go index 7799082d..5c700113 100644 --- a/gen/go/headscale/v1/headscale.pb.go +++ b/gen/go/headscale/v1/headscale.pb.go @@ -7,11 +7,10 @@ package v1 import ( - reflect "reflect" - _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" ) const ( @@ -37,7 +36,7 @@ var file_headscale_v1_headscale_proto_rawDesc = []byte{ 0x6f, 0x74, 0x6f, 0x1a, 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, 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, 0x32, 0xcb, 0x15, 0x0a, 0x10, 0x48, 0x65, + 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xa3, 0x13, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x77, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, @@ -152,68 +151,50 @@ var file_headscale_v1_headscale_proto_rawDesc = []byte{ 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, - 0x12, 0x8d, 0x01, 0x0a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, - 0x65, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x30, - 0x22, 0x2e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, - 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x73, - 0x68, 0x61, 0x72, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, - 0x12, 0x95, 0x01, 0x0a, 0x0e, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, - 0x69, 0x6e, 0x65, 0x12, 0x23, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, - 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, - 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22, 0x30, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, - 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x75, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f, 0x7b, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x12, 0x8b, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, - 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x24, 0x2e, 0x68, - 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, - 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x25, 0x12, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, - 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x97, 0x01, 0x0a, 0x13, 0x45, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x28, - 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, - 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, - 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x23, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, - 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 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, 0x22, - 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x3a, - 0x01, 0x2a, 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, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, - 0x79, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x3a, 0x01, 0x2a, 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, 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, + 0x12, 0x8b, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, + 0x6f, 0x75, 0x74, 0x65, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, + 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, + 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, + 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x97, + 0x01, 0x0a, 0x13, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, + 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, + 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, + 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x29, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x25, 0x22, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, + 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, + 0x7d, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 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, 0x22, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x3a, 0x01, 0x2a, 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, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x2f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, + 0x3a, 0x01, 0x2a, 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, 0x42, + 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x75, + 0x61, 0x6e, 0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, + 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var file_headscale_v1_headscale_proto_goTypes = []interface{}{ @@ -231,34 +212,30 @@ var file_headscale_v1_headscale_proto_goTypes = []interface{}{ (*DeleteMachineRequest)(nil), // 11: headscale.v1.DeleteMachineRequest (*ExpireMachineRequest)(nil), // 12: headscale.v1.ExpireMachineRequest (*ListMachinesRequest)(nil), // 13: headscale.v1.ListMachinesRequest - (*ShareMachineRequest)(nil), // 14: headscale.v1.ShareMachineRequest - (*UnshareMachineRequest)(nil), // 15: headscale.v1.UnshareMachineRequest - (*GetMachineRouteRequest)(nil), // 16: headscale.v1.GetMachineRouteRequest - (*EnableMachineRoutesRequest)(nil), // 17: headscale.v1.EnableMachineRoutesRequest - (*CreateApiKeyRequest)(nil), // 18: headscale.v1.CreateApiKeyRequest - (*ExpireApiKeyRequest)(nil), // 19: headscale.v1.ExpireApiKeyRequest - (*ListApiKeysRequest)(nil), // 20: headscale.v1.ListApiKeysRequest - (*GetNamespaceResponse)(nil), // 21: headscale.v1.GetNamespaceResponse - (*CreateNamespaceResponse)(nil), // 22: headscale.v1.CreateNamespaceResponse - (*RenameNamespaceResponse)(nil), // 23: headscale.v1.RenameNamespaceResponse - (*DeleteNamespaceResponse)(nil), // 24: headscale.v1.DeleteNamespaceResponse - (*ListNamespacesResponse)(nil), // 25: headscale.v1.ListNamespacesResponse - (*CreatePreAuthKeyResponse)(nil), // 26: headscale.v1.CreatePreAuthKeyResponse - (*ExpirePreAuthKeyResponse)(nil), // 27: headscale.v1.ExpirePreAuthKeyResponse - (*ListPreAuthKeysResponse)(nil), // 28: headscale.v1.ListPreAuthKeysResponse - (*DebugCreateMachineResponse)(nil), // 29: headscale.v1.DebugCreateMachineResponse - (*GetMachineResponse)(nil), // 30: headscale.v1.GetMachineResponse - (*RegisterMachineResponse)(nil), // 31: headscale.v1.RegisterMachineResponse - (*DeleteMachineResponse)(nil), // 32: headscale.v1.DeleteMachineResponse - (*ExpireMachineResponse)(nil), // 33: headscale.v1.ExpireMachineResponse - (*ListMachinesResponse)(nil), // 34: headscale.v1.ListMachinesResponse - (*ShareMachineResponse)(nil), // 35: headscale.v1.ShareMachineResponse - (*UnshareMachineResponse)(nil), // 36: headscale.v1.UnshareMachineResponse - (*GetMachineRouteResponse)(nil), // 37: headscale.v1.GetMachineRouteResponse - (*EnableMachineRoutesResponse)(nil), // 38: headscale.v1.EnableMachineRoutesResponse - (*CreateApiKeyResponse)(nil), // 39: headscale.v1.CreateApiKeyResponse - (*ExpireApiKeyResponse)(nil), // 40: headscale.v1.ExpireApiKeyResponse - (*ListApiKeysResponse)(nil), // 41: headscale.v1.ListApiKeysResponse + (*GetMachineRouteRequest)(nil), // 14: headscale.v1.GetMachineRouteRequest + (*EnableMachineRoutesRequest)(nil), // 15: headscale.v1.EnableMachineRoutesRequest + (*CreateApiKeyRequest)(nil), // 16: headscale.v1.CreateApiKeyRequest + (*ExpireApiKeyRequest)(nil), // 17: headscale.v1.ExpireApiKeyRequest + (*ListApiKeysRequest)(nil), // 18: headscale.v1.ListApiKeysRequest + (*GetNamespaceResponse)(nil), // 19: headscale.v1.GetNamespaceResponse + (*CreateNamespaceResponse)(nil), // 20: headscale.v1.CreateNamespaceResponse + (*RenameNamespaceResponse)(nil), // 21: headscale.v1.RenameNamespaceResponse + (*DeleteNamespaceResponse)(nil), // 22: headscale.v1.DeleteNamespaceResponse + (*ListNamespacesResponse)(nil), // 23: headscale.v1.ListNamespacesResponse + (*CreatePreAuthKeyResponse)(nil), // 24: headscale.v1.CreatePreAuthKeyResponse + (*ExpirePreAuthKeyResponse)(nil), // 25: headscale.v1.ExpirePreAuthKeyResponse + (*ListPreAuthKeysResponse)(nil), // 26: headscale.v1.ListPreAuthKeysResponse + (*DebugCreateMachineResponse)(nil), // 27: headscale.v1.DebugCreateMachineResponse + (*GetMachineResponse)(nil), // 28: headscale.v1.GetMachineResponse + (*RegisterMachineResponse)(nil), // 29: headscale.v1.RegisterMachineResponse + (*DeleteMachineResponse)(nil), // 30: headscale.v1.DeleteMachineResponse + (*ExpireMachineResponse)(nil), // 31: headscale.v1.ExpireMachineResponse + (*ListMachinesResponse)(nil), // 32: headscale.v1.ListMachinesResponse + (*GetMachineRouteResponse)(nil), // 33: headscale.v1.GetMachineRouteResponse + (*EnableMachineRoutesResponse)(nil), // 34: headscale.v1.EnableMachineRoutesResponse + (*CreateApiKeyResponse)(nil), // 35: headscale.v1.CreateApiKeyResponse + (*ExpireApiKeyResponse)(nil), // 36: headscale.v1.ExpireApiKeyResponse + (*ListApiKeysResponse)(nil), // 37: headscale.v1.ListApiKeysResponse } var file_headscale_v1_headscale_proto_depIdxs = []int32{ 0, // 0: headscale.v1.HeadscaleService.GetNamespace:input_type -> headscale.v1.GetNamespaceRequest @@ -275,36 +252,32 @@ var file_headscale_v1_headscale_proto_depIdxs = []int32{ 11, // 11: headscale.v1.HeadscaleService.DeleteMachine:input_type -> headscale.v1.DeleteMachineRequest 12, // 12: headscale.v1.HeadscaleService.ExpireMachine:input_type -> headscale.v1.ExpireMachineRequest 13, // 13: headscale.v1.HeadscaleService.ListMachines:input_type -> headscale.v1.ListMachinesRequest - 14, // 14: headscale.v1.HeadscaleService.ShareMachine:input_type -> headscale.v1.ShareMachineRequest - 15, // 15: headscale.v1.HeadscaleService.UnshareMachine:input_type -> headscale.v1.UnshareMachineRequest - 16, // 16: headscale.v1.HeadscaleService.GetMachineRoute:input_type -> headscale.v1.GetMachineRouteRequest - 17, // 17: headscale.v1.HeadscaleService.EnableMachineRoutes:input_type -> headscale.v1.EnableMachineRoutesRequest - 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.GetNamespace:output_type -> headscale.v1.GetNamespaceResponse - 22, // 22: headscale.v1.HeadscaleService.CreateNamespace:output_type -> headscale.v1.CreateNamespaceResponse - 23, // 23: headscale.v1.HeadscaleService.RenameNamespace:output_type -> headscale.v1.RenameNamespaceResponse - 24, // 24: headscale.v1.HeadscaleService.DeleteNamespace:output_type -> headscale.v1.DeleteNamespaceResponse - 25, // 25: headscale.v1.HeadscaleService.ListNamespaces:output_type -> headscale.v1.ListNamespacesResponse - 26, // 26: headscale.v1.HeadscaleService.CreatePreAuthKey:output_type -> headscale.v1.CreatePreAuthKeyResponse - 27, // 27: headscale.v1.HeadscaleService.ExpirePreAuthKey:output_type -> headscale.v1.ExpirePreAuthKeyResponse - 28, // 28: headscale.v1.HeadscaleService.ListPreAuthKeys:output_type -> headscale.v1.ListPreAuthKeysResponse - 29, // 29: headscale.v1.HeadscaleService.DebugCreateMachine:output_type -> headscale.v1.DebugCreateMachineResponse - 30, // 30: headscale.v1.HeadscaleService.GetMachine:output_type -> headscale.v1.GetMachineResponse - 31, // 31: headscale.v1.HeadscaleService.RegisterMachine:output_type -> headscale.v1.RegisterMachineResponse - 32, // 32: headscale.v1.HeadscaleService.DeleteMachine:output_type -> headscale.v1.DeleteMachineResponse - 33, // 33: headscale.v1.HeadscaleService.ExpireMachine:output_type -> headscale.v1.ExpireMachineResponse - 34, // 34: headscale.v1.HeadscaleService.ListMachines:output_type -> headscale.v1.ListMachinesResponse - 35, // 35: headscale.v1.HeadscaleService.ShareMachine:output_type -> headscale.v1.ShareMachineResponse - 36, // 36: headscale.v1.HeadscaleService.UnshareMachine:output_type -> headscale.v1.UnshareMachineResponse - 37, // 37: headscale.v1.HeadscaleService.GetMachineRoute:output_type -> headscale.v1.GetMachineRouteResponse - 38, // 38: headscale.v1.HeadscaleService.EnableMachineRoutes:output_type -> headscale.v1.EnableMachineRoutesResponse - 39, // 39: headscale.v1.HeadscaleService.CreateApiKey:output_type -> headscale.v1.CreateApiKeyResponse - 40, // 40: headscale.v1.HeadscaleService.ExpireApiKey:output_type -> headscale.v1.ExpireApiKeyResponse - 41, // 41: headscale.v1.HeadscaleService.ListApiKeys:output_type -> headscale.v1.ListApiKeysResponse - 21, // [21:42] is the sub-list for method output_type - 0, // [0:21] is the sub-list for method input_type + 14, // 14: headscale.v1.HeadscaleService.GetMachineRoute:input_type -> headscale.v1.GetMachineRouteRequest + 15, // 15: headscale.v1.HeadscaleService.EnableMachineRoutes:input_type -> headscale.v1.EnableMachineRoutesRequest + 16, // 16: headscale.v1.HeadscaleService.CreateApiKey:input_type -> headscale.v1.CreateApiKeyRequest + 17, // 17: headscale.v1.HeadscaleService.ExpireApiKey:input_type -> headscale.v1.ExpireApiKeyRequest + 18, // 18: headscale.v1.HeadscaleService.ListApiKeys:input_type -> headscale.v1.ListApiKeysRequest + 19, // 19: headscale.v1.HeadscaleService.GetNamespace:output_type -> headscale.v1.GetNamespaceResponse + 20, // 20: headscale.v1.HeadscaleService.CreateNamespace:output_type -> headscale.v1.CreateNamespaceResponse + 21, // 21: headscale.v1.HeadscaleService.RenameNamespace:output_type -> headscale.v1.RenameNamespaceResponse + 22, // 22: headscale.v1.HeadscaleService.DeleteNamespace:output_type -> headscale.v1.DeleteNamespaceResponse + 23, // 23: headscale.v1.HeadscaleService.ListNamespaces:output_type -> headscale.v1.ListNamespacesResponse + 24, // 24: headscale.v1.HeadscaleService.CreatePreAuthKey:output_type -> headscale.v1.CreatePreAuthKeyResponse + 25, // 25: headscale.v1.HeadscaleService.ExpirePreAuthKey:output_type -> headscale.v1.ExpirePreAuthKeyResponse + 26, // 26: headscale.v1.HeadscaleService.ListPreAuthKeys:output_type -> headscale.v1.ListPreAuthKeysResponse + 27, // 27: headscale.v1.HeadscaleService.DebugCreateMachine:output_type -> headscale.v1.DebugCreateMachineResponse + 28, // 28: headscale.v1.HeadscaleService.GetMachine:output_type -> headscale.v1.GetMachineResponse + 29, // 29: headscale.v1.HeadscaleService.RegisterMachine:output_type -> headscale.v1.RegisterMachineResponse + 30, // 30: headscale.v1.HeadscaleService.DeleteMachine:output_type -> headscale.v1.DeleteMachineResponse + 31, // 31: headscale.v1.HeadscaleService.ExpireMachine:output_type -> headscale.v1.ExpireMachineResponse + 32, // 32: headscale.v1.HeadscaleService.ListMachines:output_type -> headscale.v1.ListMachinesResponse + 33, // 33: headscale.v1.HeadscaleService.GetMachineRoute:output_type -> headscale.v1.GetMachineRouteResponse + 34, // 34: headscale.v1.HeadscaleService.EnableMachineRoutes:output_type -> headscale.v1.EnableMachineRoutesResponse + 35, // 35: headscale.v1.HeadscaleService.CreateApiKey:output_type -> headscale.v1.CreateApiKeyResponse + 36, // 36: headscale.v1.HeadscaleService.ExpireApiKey:output_type -> headscale.v1.ExpireApiKeyResponse + 37, // 37: headscale.v1.HeadscaleService.ListApiKeys:output_type -> headscale.v1.ListApiKeysResponse + 19, // [19:38] is the sub-list for method output_type + 0, // [0:19] 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 diff --git a/gen/go/headscale/v1/headscale.pb.gw.go b/gen/go/headscale/v1/headscale.pb.gw.go index b245b895..0938e147 100644 --- a/gen/go/headscale/v1/headscale.pb.gw.go +++ b/gen/go/headscale/v1/headscale.pb.gw.go @@ -625,150 +625,6 @@ func local_request_HeadscaleService_ListMachines_0(ctx context.Context, marshale } -func request_HeadscaleService_ShareMachine_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ShareMachineRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["machine_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "machine_id") - } - - protoReq.MachineId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "machine_id", err) - } - - val, ok = pathParams["namespace"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") - } - - protoReq.Namespace, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) - } - - msg, err := client.ShareMachine(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_HeadscaleService_ShareMachine_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ShareMachineRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["machine_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "machine_id") - } - - protoReq.MachineId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "machine_id", err) - } - - val, ok = pathParams["namespace"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") - } - - protoReq.Namespace, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) - } - - msg, err := server.ShareMachine(ctx, &protoReq) - return msg, metadata, err - -} - -func request_HeadscaleService_UnshareMachine_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UnshareMachineRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["machine_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "machine_id") - } - - protoReq.MachineId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "machine_id", err) - } - - val, ok = pathParams["namespace"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") - } - - protoReq.Namespace, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) - } - - msg, err := client.UnshareMachine(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_HeadscaleService_UnshareMachine_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UnshareMachineRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["machine_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "machine_id") - } - - protoReq.MachineId, err = runtime.Uint64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "machine_id", err) - } - - val, ok = pathParams["namespace"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") - } - - protoReq.Namespace, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) - } - - msg, err := server.UnshareMachine(ctx, &protoReq) - return msg, metadata, err - -} - func request_HeadscaleService_GetMachineRoute_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq GetMachineRouteRequest var metadata runtime.ServerMetadata @@ -1305,52 +1161,6 @@ func RegisterHeadscaleServiceHandlerServer(ctx context.Context, mux *runtime.Ser }) - mux.Handle("POST", pattern_HeadscaleService_ShareMachine_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) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/ShareMachine", runtime.WithHTTPPathPattern("/api/v1/machine/{machine_id}/share/{namespace}")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_HeadscaleService_ShareMachine_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_HeadscaleService_ShareMachine_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_HeadscaleService_UnshareMachine_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) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/UnshareMachine", runtime.WithHTTPPathPattern("/api/v1/machine/{machine_id}/unshare/{namespace}")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_HeadscaleService_UnshareMachine_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_HeadscaleService_UnshareMachine_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_HeadscaleService_GetMachineRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1787,46 +1597,6 @@ func RegisterHeadscaleServiceHandlerClient(ctx context.Context, mux *runtime.Ser }) - mux.Handle("POST", pattern_HeadscaleService_ShareMachine_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) - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/ShareMachine", runtime.WithHTTPPathPattern("/api/v1/machine/{machine_id}/share/{namespace}")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_HeadscaleService_ShareMachine_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_HeadscaleService_ShareMachine_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_HeadscaleService_UnshareMachine_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) - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/UnshareMachine", runtime.WithHTTPPathPattern("/api/v1/machine/{machine_id}/unshare/{namespace}")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_HeadscaleService_UnshareMachine_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_HeadscaleService_UnshareMachine_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_HeadscaleService_GetMachineRoute_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1959,10 +1729,6 @@ var ( pattern_HeadscaleService_ListMachines_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "machine"}, "")) - pattern_HeadscaleService_ShareMachine_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", "machine", "machine_id", "share", "namespace"}, "")) - - pattern_HeadscaleService_UnshareMachine_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", "machine", "machine_id", "unshare", "namespace"}, "")) - pattern_HeadscaleService_GetMachineRoute_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "machine", "machine_id", "routes"}, "")) pattern_HeadscaleService_EnableMachineRoutes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "machine", "machine_id", "routes"}, "")) @@ -2003,10 +1769,6 @@ var ( forward_HeadscaleService_ListMachines_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_ShareMachine_0 = runtime.ForwardResponseMessage - - forward_HeadscaleService_UnshareMachine_0 = runtime.ForwardResponseMessage - forward_HeadscaleService_GetMachineRoute_0 = runtime.ForwardResponseMessage forward_HeadscaleService_EnableMachineRoutes_0 = runtime.ForwardResponseMessage diff --git a/gen/go/headscale/v1/headscale_grpc.pb.go b/gen/go/headscale/v1/headscale_grpc.pb.go index c75a36c5..e4edf3f0 100644 --- a/gen/go/headscale/v1/headscale_grpc.pb.go +++ b/gen/go/headscale/v1/headscale_grpc.pb.go @@ -1,10 +1,13 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc (unknown) +// source: headscale/v1/headscale.proto package v1 import ( context "context" - grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -36,8 +39,6 @@ type HeadscaleServiceClient interface { DeleteMachine(ctx context.Context, in *DeleteMachineRequest, opts ...grpc.CallOption) (*DeleteMachineResponse, error) ExpireMachine(ctx context.Context, in *ExpireMachineRequest, opts ...grpc.CallOption) (*ExpireMachineResponse, error) ListMachines(ctx context.Context, in *ListMachinesRequest, opts ...grpc.CallOption) (*ListMachinesResponse, error) - ShareMachine(ctx context.Context, in *ShareMachineRequest, opts ...grpc.CallOption) (*ShareMachineResponse, error) - UnshareMachine(ctx context.Context, in *UnshareMachineRequest, opts ...grpc.CallOption) (*UnshareMachineResponse, error) // --- Route start --- GetMachineRoute(ctx context.Context, in *GetMachineRouteRequest, opts ...grpc.CallOption) (*GetMachineRouteResponse, error) EnableMachineRoutes(ctx context.Context, in *EnableMachineRoutesRequest, opts ...grpc.CallOption) (*EnableMachineRoutesResponse, error) @@ -181,24 +182,6 @@ func (c *headscaleServiceClient) ListMachines(ctx context.Context, in *ListMachi return out, nil } -func (c *headscaleServiceClient) ShareMachine(ctx context.Context, in *ShareMachineRequest, opts ...grpc.CallOption) (*ShareMachineResponse, error) { - out := new(ShareMachineResponse) - err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/ShareMachine", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *headscaleServiceClient) UnshareMachine(ctx context.Context, in *UnshareMachineRequest, opts ...grpc.CallOption) (*UnshareMachineResponse, error) { - out := new(UnshareMachineResponse) - err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/UnshareMachine", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *headscaleServiceClient) GetMachineRoute(ctx context.Context, in *GetMachineRouteRequest, opts ...grpc.CallOption) (*GetMachineRouteResponse, error) { out := new(GetMachineRouteResponse) err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/GetMachineRoute", in, out, opts...) @@ -265,8 +248,6 @@ type HeadscaleServiceServer interface { DeleteMachine(context.Context, *DeleteMachineRequest) (*DeleteMachineResponse, error) ExpireMachine(context.Context, *ExpireMachineRequest) (*ExpireMachineResponse, error) ListMachines(context.Context, *ListMachinesRequest) (*ListMachinesResponse, error) - ShareMachine(context.Context, *ShareMachineRequest) (*ShareMachineResponse, error) - UnshareMachine(context.Context, *UnshareMachineRequest) (*UnshareMachineResponse, error) // --- Route start --- GetMachineRoute(context.Context, *GetMachineRouteRequest) (*GetMachineRouteResponse, error) EnableMachineRoutes(context.Context, *EnableMachineRoutesRequest) (*EnableMachineRoutesResponse, error) @@ -323,12 +304,6 @@ func (UnimplementedHeadscaleServiceServer) ExpireMachine(context.Context, *Expir func (UnimplementedHeadscaleServiceServer) ListMachines(context.Context, *ListMachinesRequest) (*ListMachinesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListMachines not implemented") } -func (UnimplementedHeadscaleServiceServer) ShareMachine(context.Context, *ShareMachineRequest) (*ShareMachineResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ShareMachine not implemented") -} -func (UnimplementedHeadscaleServiceServer) UnshareMachine(context.Context, *UnshareMachineRequest) (*UnshareMachineResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UnshareMachine not implemented") -} func (UnimplementedHeadscaleServiceServer) GetMachineRoute(context.Context, *GetMachineRouteRequest) (*GetMachineRouteResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMachineRoute not implemented") } @@ -609,42 +584,6 @@ func _HeadscaleService_ListMachines_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } -func _HeadscaleService_ShareMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ShareMachineRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(HeadscaleServiceServer).ShareMachine(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/headscale.v1.HeadscaleService/ShareMachine", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HeadscaleServiceServer).ShareMachine(ctx, req.(*ShareMachineRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _HeadscaleService_UnshareMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnshareMachineRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(HeadscaleServiceServer).UnshareMachine(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/headscale.v1.HeadscaleService/UnshareMachine", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HeadscaleServiceServer).UnshareMachine(ctx, req.(*UnshareMachineRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _HeadscaleService_GetMachineRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetMachineRouteRequest) if err := dec(in); err != nil { @@ -798,14 +737,6 @@ var HeadscaleService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListMachines", Handler: _HeadscaleService_ListMachines_Handler, }, - { - MethodName: "ShareMachine", - Handler: _HeadscaleService_ShareMachine_Handler, - }, - { - MethodName: "UnshareMachine", - Handler: _HeadscaleService_UnshareMachine_Handler, - }, { MethodName: "GetMachineRoute", Handler: _HeadscaleService_GetMachineRoute_Handler, diff --git a/gen/go/headscale/v1/machine.pb.go b/gen/go/headscale/v1/machine.pb.go index 5f12c6e5..9a5064fe 100644 --- a/gen/go/headscale/v1/machine.pb.go +++ b/gen/go/headscale/v1/machine.pb.go @@ -7,12 +7,11 @@ package v1 import ( - reflect "reflect" - sync "sync" - 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 ( @@ -694,210 +693,6 @@ func (x *ListMachinesResponse) GetMachines() []*Machine { return nil } -type ShareMachineRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - MachineId uint64 `protobuf:"varint,1,opt,name=machine_id,json=machineId,proto3" json:"machine_id,omitempty"` - Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` -} - -func (x *ShareMachineRequest) Reset() { - *x = ShareMachineRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_headscale_v1_machine_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ShareMachineRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ShareMachineRequest) ProtoMessage() {} - -func (x *ShareMachineRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_machine_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ShareMachineRequest.ProtoReflect.Descriptor instead. -func (*ShareMachineRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_machine_proto_rawDescGZIP(), []int{11} -} - -func (x *ShareMachineRequest) GetMachineId() uint64 { - if x != nil { - return x.MachineId - } - return 0 -} - -func (x *ShareMachineRequest) GetNamespace() string { - if x != nil { - return x.Namespace - } - return "" -} - -type ShareMachineResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Machine *Machine `protobuf:"bytes,1,opt,name=machine,proto3" json:"machine,omitempty"` -} - -func (x *ShareMachineResponse) Reset() { - *x = ShareMachineResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_headscale_v1_machine_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ShareMachineResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ShareMachineResponse) ProtoMessage() {} - -func (x *ShareMachineResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_machine_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ShareMachineResponse.ProtoReflect.Descriptor instead. -func (*ShareMachineResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_machine_proto_rawDescGZIP(), []int{12} -} - -func (x *ShareMachineResponse) GetMachine() *Machine { - if x != nil { - return x.Machine - } - return nil -} - -type UnshareMachineRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - MachineId uint64 `protobuf:"varint,1,opt,name=machine_id,json=machineId,proto3" json:"machine_id,omitempty"` - Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` -} - -func (x *UnshareMachineRequest) Reset() { - *x = UnshareMachineRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_headscale_v1_machine_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UnshareMachineRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UnshareMachineRequest) ProtoMessage() {} - -func (x *UnshareMachineRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_machine_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UnshareMachineRequest.ProtoReflect.Descriptor instead. -func (*UnshareMachineRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_machine_proto_rawDescGZIP(), []int{13} -} - -func (x *UnshareMachineRequest) GetMachineId() uint64 { - if x != nil { - return x.MachineId - } - return 0 -} - -func (x *UnshareMachineRequest) GetNamespace() string { - if x != nil { - return x.Namespace - } - return "" -} - -type UnshareMachineResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Machine *Machine `protobuf:"bytes,1,opt,name=machine,proto3" json:"machine,omitempty"` -} - -func (x *UnshareMachineResponse) Reset() { - *x = UnshareMachineResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_headscale_v1_machine_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UnshareMachineResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UnshareMachineResponse) ProtoMessage() {} - -func (x *UnshareMachineResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_machine_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UnshareMachineResponse.ProtoReflect.Descriptor instead. -func (*UnshareMachineResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_machine_proto_rawDescGZIP(), []int{14} -} - -func (x *UnshareMachineResponse) GetMachine() *Machine { - if x != nil { - return x.Machine - } - return nil -} - type DebugCreateMachineRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -912,7 +707,7 @@ type DebugCreateMachineRequest struct { func (x *DebugCreateMachineRequest) Reset() { *x = DebugCreateMachineRequest{} if protoimpl.UnsafeEnabled { - mi := &file_headscale_v1_machine_proto_msgTypes[15] + mi := &file_headscale_v1_machine_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -925,7 +720,7 @@ func (x *DebugCreateMachineRequest) String() string { func (*DebugCreateMachineRequest) ProtoMessage() {} func (x *DebugCreateMachineRequest) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_machine_proto_msgTypes[15] + mi := &file_headscale_v1_machine_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -938,7 +733,7 @@ func (x *DebugCreateMachineRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DebugCreateMachineRequest.ProtoReflect.Descriptor instead. func (*DebugCreateMachineRequest) Descriptor() ([]byte, []int) { - return file_headscale_v1_machine_proto_rawDescGZIP(), []int{15} + return file_headscale_v1_machine_proto_rawDescGZIP(), []int{11} } func (x *DebugCreateMachineRequest) GetNamespace() string { @@ -980,7 +775,7 @@ type DebugCreateMachineResponse struct { func (x *DebugCreateMachineResponse) Reset() { *x = DebugCreateMachineResponse{} if protoimpl.UnsafeEnabled { - mi := &file_headscale_v1_machine_proto_msgTypes[16] + mi := &file_headscale_v1_machine_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -993,7 +788,7 @@ func (x *DebugCreateMachineResponse) String() string { func (*DebugCreateMachineResponse) ProtoMessage() {} func (x *DebugCreateMachineResponse) ProtoReflect() protoreflect.Message { - mi := &file_headscale_v1_machine_proto_msgTypes[16] + mi := &file_headscale_v1_machine_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1006,7 +801,7 @@ func (x *DebugCreateMachineResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DebugCreateMachineResponse.ProtoReflect.Descriptor instead. func (*DebugCreateMachineResponse) Descriptor() ([]byte, []int) { - return file_headscale_v1_machine_proto_rawDescGZIP(), []int{16} + return file_headscale_v1_machine_proto_rawDescGZIP(), []int{12} } func (x *DebugCreateMachineResponse) GetMachine() *Machine { @@ -1105,51 +900,31 @@ var file_headscale_v1_machine_proto_rawDesc = []byte{ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, - 0x52, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x22, 0x52, 0x0a, 0x13, 0x53, 0x68, - 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x47, - 0x0a, 0x14, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, - 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, - 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x54, 0x0a, 0x15, 0x55, 0x6e, 0x73, 0x68, 0x61, - 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, - 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x49, 0x0a, - 0x16, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, - 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, - 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, - 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x77, 0x0a, 0x19, 0x44, 0x65, 0x62, 0x75, - 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 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, 0x4d, 0x0a, 0x1a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, - 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, + 0x52, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x22, 0x77, 0x0a, 0x19, 0x44, 0x65, + 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 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, 0x4d, 0x0a, 0x1a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, + 0x6e, 0x65, 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 ( @@ -1165,7 +940,7 @@ func file_headscale_v1_machine_proto_rawDescGZIP() []byte { } var file_headscale_v1_machine_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_headscale_v1_machine_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_headscale_v1_machine_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_headscale_v1_machine_proto_goTypes = []interface{}{ (RegisterMethod)(0), // 0: headscale.v1.RegisterMethod (*Machine)(nil), // 1: headscale.v1.Machine @@ -1179,36 +954,30 @@ var file_headscale_v1_machine_proto_goTypes = []interface{}{ (*ExpireMachineResponse)(nil), // 9: headscale.v1.ExpireMachineResponse (*ListMachinesRequest)(nil), // 10: headscale.v1.ListMachinesRequest (*ListMachinesResponse)(nil), // 11: headscale.v1.ListMachinesResponse - (*ShareMachineRequest)(nil), // 12: headscale.v1.ShareMachineRequest - (*ShareMachineResponse)(nil), // 13: headscale.v1.ShareMachineResponse - (*UnshareMachineRequest)(nil), // 14: headscale.v1.UnshareMachineRequest - (*UnshareMachineResponse)(nil), // 15: headscale.v1.UnshareMachineResponse - (*DebugCreateMachineRequest)(nil), // 16: headscale.v1.DebugCreateMachineRequest - (*DebugCreateMachineResponse)(nil), // 17: headscale.v1.DebugCreateMachineResponse - (*Namespace)(nil), // 18: headscale.v1.Namespace - (*timestamppb.Timestamp)(nil), // 19: google.protobuf.Timestamp - (*PreAuthKey)(nil), // 20: headscale.v1.PreAuthKey + (*DebugCreateMachineRequest)(nil), // 12: headscale.v1.DebugCreateMachineRequest + (*DebugCreateMachineResponse)(nil), // 13: headscale.v1.DebugCreateMachineResponse + (*Namespace)(nil), // 14: headscale.v1.Namespace + (*timestamppb.Timestamp)(nil), // 15: google.protobuf.Timestamp + (*PreAuthKey)(nil), // 16: headscale.v1.PreAuthKey } var file_headscale_v1_machine_proto_depIdxs = []int32{ - 18, // 0: headscale.v1.Machine.namespace:type_name -> headscale.v1.Namespace + 14, // 0: headscale.v1.Machine.namespace:type_name -> headscale.v1.Namespace 0, // 1: headscale.v1.Machine.register_method:type_name -> headscale.v1.RegisterMethod - 19, // 2: headscale.v1.Machine.last_seen:type_name -> google.protobuf.Timestamp - 19, // 3: headscale.v1.Machine.last_successful_update:type_name -> google.protobuf.Timestamp - 19, // 4: headscale.v1.Machine.expiry:type_name -> google.protobuf.Timestamp - 20, // 5: headscale.v1.Machine.pre_auth_key:type_name -> headscale.v1.PreAuthKey - 19, // 6: headscale.v1.Machine.created_at:type_name -> google.protobuf.Timestamp + 15, // 2: headscale.v1.Machine.last_seen:type_name -> google.protobuf.Timestamp + 15, // 3: headscale.v1.Machine.last_successful_update:type_name -> google.protobuf.Timestamp + 15, // 4: headscale.v1.Machine.expiry:type_name -> google.protobuf.Timestamp + 16, // 5: headscale.v1.Machine.pre_auth_key:type_name -> headscale.v1.PreAuthKey + 15, // 6: headscale.v1.Machine.created_at:type_name -> google.protobuf.Timestamp 1, // 7: headscale.v1.RegisterMachineResponse.machine:type_name -> headscale.v1.Machine 1, // 8: headscale.v1.GetMachineResponse.machine:type_name -> headscale.v1.Machine 1, // 9: headscale.v1.ExpireMachineResponse.machine:type_name -> headscale.v1.Machine 1, // 10: headscale.v1.ListMachinesResponse.machines:type_name -> headscale.v1.Machine - 1, // 11: headscale.v1.ShareMachineResponse.machine:type_name -> headscale.v1.Machine - 1, // 12: headscale.v1.UnshareMachineResponse.machine:type_name -> headscale.v1.Machine - 1, // 13: headscale.v1.DebugCreateMachineResponse.machine:type_name -> headscale.v1.Machine - 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, // 11: headscale.v1.DebugCreateMachineResponse.machine:type_name -> headscale.v1.Machine + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_headscale_v1_machine_proto_init() } @@ -1352,54 +1121,6 @@ func file_headscale_v1_machine_proto_init() { } } file_headscale_v1_machine_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShareMachineRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_headscale_v1_machine_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShareMachineResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_headscale_v1_machine_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnshareMachineRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_headscale_v1_machine_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnshareMachineResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_headscale_v1_machine_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DebugCreateMachineRequest); i { case 0: return &v.state @@ -1411,7 +1132,7 @@ func file_headscale_v1_machine_proto_init() { return nil } } - file_headscale_v1_machine_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_headscale_v1_machine_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DebugCreateMachineResponse); i { case 0: return &v.state @@ -1430,7 +1151,7 @@ func file_headscale_v1_machine_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_headscale_v1_machine_proto_rawDesc, NumEnums: 1, - NumMessages: 17, + NumMessages: 13, NumExtensions: 0, NumServices: 0, }, diff --git a/gen/go/headscale/v1/namespace.pb.go b/gen/go/headscale/v1/namespace.pb.go index 0e0f8279..f0893653 100644 --- a/gen/go/headscale/v1/namespace.pb.go +++ b/gen/go/headscale/v1/namespace.pb.go @@ -7,12 +7,11 @@ package v1 import ( - reflect "reflect" - sync "sync" - 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 ( diff --git a/gen/go/headscale/v1/preauthkey.pb.go b/gen/go/headscale/v1/preauthkey.pb.go index 056e0f39..645a0f03 100644 --- a/gen/go/headscale/v1/preauthkey.pb.go +++ b/gen/go/headscale/v1/preauthkey.pb.go @@ -7,12 +7,11 @@ package v1 import ( - reflect "reflect" - sync "sync" - 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 ( diff --git a/gen/go/headscale/v1/routes.pb.go b/gen/go/headscale/v1/routes.pb.go index 12510f39..5ab4bbdc 100644 --- a/gen/go/headscale/v1/routes.pb.go +++ b/gen/go/headscale/v1/routes.pb.go @@ -7,11 +7,10 @@ package v1 import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( diff --git a/gen/openapiv2/headscale/v1/headscale.swagger.json b/gen/openapiv2/headscale/v1/headscale.swagger.json index d91d0baf..db348f41 100644 --- a/gen/openapiv2/headscale/v1/headscale.swagger.json +++ b/gen/openapiv2/headscale/v1/headscale.swagger.json @@ -181,6 +181,20 @@ } } }, + "parameters": [ + { + "name": "namespace", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "key", + "in": "query", + "required": false, + "type": "string" + } + ], "tags": [ "HeadscaleService" ] @@ -324,37 +338,6 @@ } } }, - "parameters": [ - { - "name": "machineId", - "in": "path", - "required": true, - "type": "string", - "format": "uint64" - } - ], - "tags": [ - "HeadscaleService" - ] - } - }, - "/api/v1/machine/{machineId}/share/{namespace}": { - "post": { - "operationId": "HeadscaleService_ShareMachine", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ShareMachineResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, "parameters": [ { "name": "machineId", @@ -364,47 +347,14 @@ "format": "uint64" }, { - "name": "namespace", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "HeadscaleService" - ] - } - }, - "/api/v1/machine/{machineId}/unshare/{namespace}": { - "post": { - "operationId": "HeadscaleService_UnshareMachine", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1UnshareMachineResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "machineId", - "in": "path", - "required": true, - "type": "string", - "format": "uint64" - }, - { - "name": "namespace", - "in": "path", - "required": true, - "type": "string" + "name": "routes", + "in": "query", + "required": false, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi" } ], "tags": [ @@ -1050,22 +1000,6 @@ } } } - }, - "v1ShareMachineResponse": { - "type": "object", - "properties": { - "machine": { - "$ref": "#/definitions/v1Machine" - } - } - }, - "v1UnshareMachineResponse": { - "type": "object", - "properties": { - "machine": { - "$ref": "#/definitions/v1Machine" - } - } } } } diff --git a/grpcv1.go b/grpcv1.go index 9762d22b..60e181df 100644 --- a/grpcv1.go +++ b/grpcv1.go @@ -232,15 +232,6 @@ func (api headscaleV1APIServer) ListMachines( return nil, err } - sharedMachines, err := api.h.ListSharedMachinesInNamespace( - request.GetNamespace(), - ) - if err != nil { - return nil, err - } - - machines = append(machines, sharedMachines...) - response := make([]*v1.Machine, len(machines)) for index, machine := range machines { response[index] = machine.toProto() @@ -262,50 +253,6 @@ func (api headscaleV1APIServer) ListMachines( return &v1.ListMachinesResponse{Machines: response}, nil } -func (api headscaleV1APIServer) ShareMachine( - ctx context.Context, - request *v1.ShareMachineRequest, -) (*v1.ShareMachineResponse, error) { - destinationNamespace, err := api.h.GetNamespace(request.GetNamespace()) - if err != nil { - return nil, err - } - - machine, err := api.h.GetMachineByID(request.GetMachineId()) - if err != nil { - return nil, err - } - - err = api.h.AddSharedMachineToNamespace(machine, destinationNamespace) - if err != nil { - return nil, err - } - - return &v1.ShareMachineResponse{Machine: machine.toProto()}, nil -} - -func (api headscaleV1APIServer) UnshareMachine( - ctx context.Context, - request *v1.UnshareMachineRequest, -) (*v1.UnshareMachineResponse, error) { - destinationNamespace, err := api.h.GetNamespace(request.GetNamespace()) - if err != nil { - return nil, err - } - - machine, err := api.h.GetMachineByID(request.GetMachineId()) - if err != nil { - return nil, err - } - - err = api.h.RemoveSharedMachineFromNamespace(machine, destinationNamespace) - if err != nil { - return nil, err - } - - return &v1.UnshareMachineResponse{Machine: machine.toProto()}, nil -} - func (api headscaleV1APIServer) GetMachineRoute( ctx context.Context, request *v1.GetMachineRouteRequest, diff --git a/integration_cli_test.go b/integration_cli_test.go index 818be911..aae80cb0 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -529,7 +529,7 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { namespace, err := s.createNamespace("machine-namespace") assert.Nil(s.T(), err) - sharedNamespace, err := s.createNamespace("shared-namespace") + secondNamespace, err := s.createNamespace("other-namespace") assert.Nil(s.T(), err) // Randomly generated machine keys @@ -589,7 +589,7 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { assert.Len(s.T(), machines, len(machineKeys)) - // Test list all nodes after added shared + // Test list all nodes after added seconds listAllResult, err := ExecuteCommand( &s.headscale, []string{ @@ -627,14 +627,14 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { assert.True(s.T(), listAll[3].Registered) assert.True(s.T(), listAll[4].Registered) - sharedMachineKeys := []string{ + otherNamespaceMachineKeys := []string{ "b5b444774186d4217adcec407563a1223929465ee2c68a4da13af0d0185b4f8e", "dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584", } - sharedMachines := make([]*v1.Machine, len(sharedMachineKeys)) + otherNamespaceMachines := make([]*v1.Machine, len(otherNamespaceMachineKeys)) assert.Nil(s.T(), err) - for index, machineKey := range sharedMachineKeys { + for index, machineKey := range otherNamespaceMachineKeys { _, err := ExecuteCommand( &s.headscale, []string{ @@ -642,9 +642,9 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { "debug", "create-node", "--name", - fmt.Sprintf("shared-machine-%d", index+1), + fmt.Sprintf("otherNamespace-machine-%d", index+1), "--namespace", - sharedNamespace.Name, + secondNamespace.Name, "--key", machineKey, "--output", @@ -660,7 +660,7 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { "headscale", "nodes", "--namespace", - sharedNamespace.Name, + secondNamespace.Name, "register", "--key", machineKey, @@ -675,13 +675,13 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { err = json.Unmarshal([]byte(machineResult), &machine) assert.Nil(s.T(), err) - sharedMachines[index] = &machine + otherNamespaceMachines[index] = &machine } - assert.Len(s.T(), sharedMachines, len(sharedMachineKeys)) + assert.Len(s.T(), otherNamespaceMachines, len(otherNamespaceMachineKeys)) - // Test list all nodes after added shared - listAllWithSharedResult, err := ExecuteCommand( + // Test list all nodes after added otherNamespace + listAllWithotherNamespaceResult, err := ExecuteCommand( &s.headscale, []string{ "headscale", @@ -694,31 +694,34 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { ) assert.Nil(s.T(), err) - var listAllWithShared []v1.Machine - err = json.Unmarshal([]byte(listAllWithSharedResult), &listAllWithShared) + var listAllWithotherNamespace []v1.Machine + err = json.Unmarshal( + []byte(listAllWithotherNamespaceResult), + &listAllWithotherNamespace, + ) assert.Nil(s.T(), err) - // All nodes, machines + shared - assert.Len(s.T(), listAllWithShared, 7) + // All nodes, machines + otherNamespace + assert.Len(s.T(), listAllWithotherNamespace, 7) - assert.Equal(s.T(), uint64(6), listAllWithShared[5].Id) - assert.Equal(s.T(), uint64(7), listAllWithShared[6].Id) + assert.Equal(s.T(), uint64(6), listAllWithotherNamespace[5].Id) + assert.Equal(s.T(), uint64(7), listAllWithotherNamespace[6].Id) - assert.Equal(s.T(), "shared-machine-1", listAllWithShared[5].Name) - assert.Equal(s.T(), "shared-machine-2", listAllWithShared[6].Name) + assert.Equal(s.T(), "otherNamespace-machine-1", listAllWithotherNamespace[5].Name) + assert.Equal(s.T(), "otherNamespace-machine-2", listAllWithotherNamespace[6].Name) - assert.True(s.T(), listAllWithShared[5].Registered) - assert.True(s.T(), listAllWithShared[6].Registered) + assert.True(s.T(), listAllWithotherNamespace[5].Registered) + assert.True(s.T(), listAllWithotherNamespace[6].Registered) - // Test list all nodes after added shared - listOnlySharedMachineNamespaceResult, err := ExecuteCommand( + // Test list all nodes after added otherNamespace + listOnlyotherNamespaceMachineNamespaceResult, err := ExecuteCommand( &s.headscale, []string{ "headscale", "nodes", "list", "--namespace", - sharedNamespace.Name, + secondNamespace.Name, "--output", "json", }, @@ -726,23 +729,31 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { ) assert.Nil(s.T(), err) - var listOnlySharedMachineNamespace []v1.Machine + var listOnlyotherNamespaceMachineNamespace []v1.Machine err = json.Unmarshal( - []byte(listOnlySharedMachineNamespaceResult), - &listOnlySharedMachineNamespace, + []byte(listOnlyotherNamespaceMachineNamespaceResult), + &listOnlyotherNamespaceMachineNamespace, ) assert.Nil(s.T(), err) - assert.Len(s.T(), listOnlySharedMachineNamespace, 2) + assert.Len(s.T(), listOnlyotherNamespaceMachineNamespace, 2) - assert.Equal(s.T(), uint64(6), listOnlySharedMachineNamespace[0].Id) - assert.Equal(s.T(), uint64(7), listOnlySharedMachineNamespace[1].Id) + assert.Equal(s.T(), uint64(6), listOnlyotherNamespaceMachineNamespace[0].Id) + assert.Equal(s.T(), uint64(7), listOnlyotherNamespaceMachineNamespace[1].Id) - assert.Equal(s.T(), "shared-machine-1", listOnlySharedMachineNamespace[0].Name) - assert.Equal(s.T(), "shared-machine-2", listOnlySharedMachineNamespace[1].Name) + assert.Equal( + s.T(), + "otherNamespace-machine-1", + listOnlyotherNamespaceMachineNamespace[0].Name, + ) + assert.Equal( + s.T(), + "otherNamespace-machine-2", + listOnlyotherNamespaceMachineNamespace[1].Name, + ) - assert.True(s.T(), listOnlySharedMachineNamespace[0].Registered) - assert.True(s.T(), listOnlySharedMachineNamespace[1].Registered) + assert.True(s.T(), listOnlyotherNamespaceMachineNamespace[0].Registered) + assert.True(s.T(), listOnlyotherNamespaceMachineNamespace[1].Registered) // Delete a machines _, err = ExecuteCommand( @@ -786,120 +797,6 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { assert.Nil(s.T(), err) assert.Len(s.T(), listOnlyMachineNamespaceAfterDelete, 4) - - // test: share node - - shareMachineResult, err := ExecuteCommand( - &s.headscale, - []string{ - "headscale", - "nodes", - "share", - "--namespace", - namespace.Name, - "--identifier", - "7", - "--output", - "json", - }, - []string{}, - ) - assert.Nil(s.T(), err) - - var shareMachine v1.Machine - err = json.Unmarshal([]byte(shareMachineResult), &shareMachine) - assert.Nil(s.T(), err) - - assert.Equal(s.T(), uint64(7), shareMachine.Id) - - assert.Equal(s.T(), "shared-machine-2", shareMachine.Name) - - assert.True(s.T(), shareMachine.Registered) - - // Test: list main namespace after machine has been shared - listOnlyMachineNamespaceAfterShareResult, err := ExecuteCommand( - &s.headscale, - []string{ - "headscale", - "nodes", - "list", - "--namespace", - namespace.Name, - "--output", - "json", - }, - []string{}, - ) - assert.Nil(s.T(), err) - - var listOnlyMachineNamespaceAfterShare []v1.Machine - err = json.Unmarshal( - []byte(listOnlyMachineNamespaceAfterShareResult), - &listOnlyMachineNamespaceAfterShare, - ) - assert.Nil(s.T(), err) - - assert.Len(s.T(), listOnlyMachineNamespaceAfterShare, 5) - - assert.Equal(s.T(), uint64(7), listOnlyMachineNamespaceAfterShare[4].Id) - - assert.Equal(s.T(), "shared-machine-2", listOnlyMachineNamespaceAfterShare[4].Name) - - assert.True(s.T(), listOnlyMachineNamespaceAfterShare[4].Registered) - - // test: unshare node - - unshareMachineResult, err := ExecuteCommand( - &s.headscale, - []string{ - "headscale", - "nodes", - "unshare", - "--namespace", - namespace.Name, - "--identifier", - "7", - "--output", - "json", - }, - []string{}, - ) - assert.Nil(s.T(), err) - - var unshareMachine v1.Machine - err = json.Unmarshal([]byte(unshareMachineResult), &unshareMachine) - assert.Nil(s.T(), err) - - assert.Equal(s.T(), uint64(7), unshareMachine.Id) - - assert.Equal(s.T(), "shared-machine-2", unshareMachine.Name) - - assert.True(s.T(), unshareMachine.Registered) - - // Test: list main namespace after machine has been shared - listOnlyMachineNamespaceAfterUnshareResult, err := ExecuteCommand( - &s.headscale, - []string{ - "headscale", - "nodes", - "list", - "--namespace", - namespace.Name, - "--output", - "json", - }, - []string{}, - ) - assert.Nil(s.T(), err) - - var listOnlyMachineNamespaceAfterUnshare []v1.Machine - err = json.Unmarshal( - []byte(listOnlyMachineNamespaceAfterUnshareResult), - &listOnlyMachineNamespaceAfterUnshare, - ) - assert.Nil(s.T(), err) - - assert.Len(s.T(), listOnlyMachineNamespaceAfterUnshare, 4) } func (s *IntegrationCLITestSuite) TestNodeExpireCommand() { diff --git a/integration_test.go b/integration_test.go index 43845b61..03d6d2f2 100644 --- a/integration_test.go +++ b/integration_test.go @@ -15,6 +15,7 @@ import ( "os" "path" "strings" + "sync" "testing" "time" @@ -44,17 +45,19 @@ type IntegrationTestSuite struct { headscale dockertest.Resource namespaces map[string]TestNamespace + + joinWaitGroup sync.WaitGroup } func TestIntegrationTestSuite(t *testing.T) { s := new(IntegrationTestSuite) s.namespaces = map[string]TestNamespace{ - "main": { - count: 20, + "thisspace": { + count: 15, tailscales: make(map[string]dockertest.Resource), }, - "shared": { + "otherspace": { count: 5, tailscales: make(map[string]dockertest.Resource), }, @@ -118,7 +121,7 @@ func (s *IntegrationTestSuite) saveLog( return err } - fmt.Printf("Saving logs for %s to %s\n", resource.Container.Name, basePath) + log.Printf("Saving logs for %s to %s\n", resource.Container.Name, basePath) err = ioutil.WriteFile( path.Join(basePath, resource.Container.Name+".stdout.log"), @@ -141,6 +144,34 @@ func (s *IntegrationTestSuite) saveLog( return nil } +func (s *IntegrationTestSuite) Join( + endpoint, key, hostname string, + tailscale dockertest.Resource, +) { + defer s.joinWaitGroup.Done() + + command := []string{ + "tailscale", + "up", + "-login-server", + endpoint, + "--authkey", + key, + "--hostname", + hostname, + } + + log.Println("Join command:", command) + log.Printf("Running join command for %s\n", hostname) + _, err := ExecuteCommand( + &tailscale, + command, + []string{}, + ) + assert.Nil(s.T(), err) + log.Printf("%s joined\n", hostname) +} + func (s *IntegrationTestSuite) tailscaleContainer( namespace, identifier, version string, ) (string, *dockertest.Resource) { @@ -178,7 +209,7 @@ func (s *IntegrationTestSuite) tailscaleContainer( if err != nil { log.Fatalf("Could not start resource: %s", err) } - fmt.Printf("Created %s container\n", hostname) + log.Printf("Created %s container\n", hostname) return hostname, pts } @@ -221,15 +252,15 @@ func (s *IntegrationTestSuite) SetupSuite() { Cmd: []string{"headscale", "serve"}, } - fmt.Println("Creating headscale container") + log.Println("Creating headscale container") if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil { s.headscale = *pheadscale } else { log.Fatalf("Could not start resource: %s", err) } - fmt.Println("Created headscale container") + log.Println("Created headscale container") - fmt.Println("Creating tailscale containers") + log.Println("Creating tailscale containers") for namespace, scales := range s.namespaces { for i := 0; i < scales.count; i++ { version := tailscaleVersions[i%len(tailscaleVersions)] @@ -243,7 +274,7 @@ func (s *IntegrationTestSuite) SetupSuite() { } } - fmt.Println("Waiting for headscale to be ready") + log.Println("Waiting for headscale to be ready") hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8080/tcp")) if err := s.pool.Retry(func() error { @@ -266,19 +297,19 @@ func (s *IntegrationTestSuite) SetupSuite() { // https://github.com/stretchr/testify/issues/849 return // fmt.Errorf("Could not connect to headscale: %s", err) } - fmt.Println("headscale container is ready") + log.Println("headscale container is ready") for namespace, scales := range s.namespaces { - fmt.Printf("Creating headscale namespace: %s\n", namespace) + log.Printf("Creating headscale namespace: %s\n", namespace) result, err := ExecuteCommand( &s.headscale, []string{"headscale", "namespaces", "create", namespace}, []string{}, ) - fmt.Println("headscale create namespace result: ", result) + log.Println("headscale create namespace result: ", result) assert.Nil(s.T(), err) - fmt.Printf("Creating pre auth key for %s\n", namespace) + log.Printf("Creating pre auth key for %s\n", namespace) preAuthResult, err := ExecuteCommand( &s.headscale, []string{ @@ -304,33 +335,16 @@ func (s *IntegrationTestSuite) SetupSuite() { headscaleEndpoint := "http://headscale:8080" - fmt.Printf( + log.Printf( "Joining tailscale containers to headscale at %s\n", headscaleEndpoint, ) for hostname, tailscale := range scales.tailscales { - command := []string{ - "tailscale", - "up", - "-login-server", - headscaleEndpoint, - "--authkey", - preAuthKey.Key, - "--hostname", - hostname, - } - - fmt.Println("Join command:", command) - fmt.Printf("Running join command for %s\n", hostname) - result, err := ExecuteCommand( - &tailscale, - command, - []string{}, - ) - fmt.Println("tailscale result: ", result) - assert.Nil(s.T(), err) - fmt.Printf("%s joined\n", hostname) + s.joinWaitGroup.Add(1) + go s.Join(headscaleEndpoint, preAuthKey.Key, hostname, tailscale) } + + s.joinWaitGroup.Wait() } // The nodes need a bit of time to get their updated maps from headscale @@ -350,7 +364,7 @@ func (s *IntegrationTestSuite) HandleStats( func (s *IntegrationTestSuite) TestListNodes() { for namespace, scales := range s.namespaces { - fmt.Println("Listing nodes") + log.Println("Listing nodes") result, err := ExecuteCommand( &s.headscale, []string{"headscale", "--namespace", namespace, "nodes", "list"}, @@ -358,7 +372,7 @@ func (s *IntegrationTestSuite) TestListNodes() { ) assert.Nil(s.T(), err) - fmt.Printf("List nodes: \n%s\n", result) + log.Printf("List nodes: \n%s\n", result) // Chck that the correct count of host is present in node list lines := strings.Split(result, "\n") @@ -381,7 +395,7 @@ func (s *IntegrationTestSuite) TestGetIpAddresses() { s.T().Run(hostname, func(t *testing.T) { assert.NotNil(t, ip) - fmt.Printf("IP for %s: %s\n", hostname, ip) + log.Printf("IP for %s: %s\n", hostname, ip) // c.Assert(ip.Valid(), check.IsTrue) assert.True(t, ip.Is4() || ip.Is6()) @@ -410,7 +424,7 @@ func (s *IntegrationTestSuite) TestGetIpAddresses() { // s.T().Run(hostname, func(t *testing.T) { // command := []string{"tailscale", "status", "--json"} // -// fmt.Printf("Getting status for %s\n", hostname) +// log.Printf("Getting status for %s\n", hostname) // result, err := ExecuteCommand( // &tailscale, // command, @@ -452,6 +466,7 @@ func getIPsfromIPNstate(status ipnstate.Status) []netaddr.IP { return ips } +// TODO: Adopt test for cross communication between namespaces func (s *IntegrationTestSuite) TestPingAllPeersByAddress() { for _, scales := range s.namespaces { ips, err := getIPs(scales.tailscales) @@ -476,7 +491,7 @@ func (s *IntegrationTestSuite) TestPingAllPeersByAddress() { ip.String(), } - fmt.Printf( + log.Printf( "Pinging from %s to %s (%s)\n", hostname, peername, @@ -488,7 +503,7 @@ func (s *IntegrationTestSuite) TestPingAllPeersByAddress() { []string{}, ) assert.Nil(t, err) - fmt.Printf("Result for %s: %s\n", hostname, result) + log.Printf("Result for %s: %s\n", hostname, result) assert.Contains(t, result, "pong") }) } @@ -497,111 +512,6 @@ func (s *IntegrationTestSuite) TestPingAllPeersByAddress() { } } -func (s *IntegrationTestSuite) TestSharedNodes() { - main := s.namespaces["main"] - shared := s.namespaces["shared"] - - result, err := ExecuteCommand( - &s.headscale, - []string{ - "headscale", - "nodes", - "list", - "--output", - "json", - "--namespace", - "shared", - }, - []string{}, - ) - assert.Nil(s.T(), err) - - var machineList []v1.Machine - err = json.Unmarshal([]byte(result), &machineList) - assert.Nil(s.T(), err) - - for _, machine := range machineList { - result, err := ExecuteCommand( - &s.headscale, - []string{ - "headscale", - "nodes", - "share", - "--identifier", fmt.Sprint(machine.Id), - "--namespace", "main", - }, - []string{}, - ) - assert.Nil(s.T(), err) - - fmt.Println("Shared node with result: ", result) - } - - result, err = ExecuteCommand( - &s.headscale, - []string{"headscale", "nodes", "list", "--namespace", "main"}, - []string{}, - ) - assert.Nil(s.T(), err) - fmt.Println("Nodelist after sharing", result) - - // Chck that the correct count of host is present in node list - lines := strings.Split(result, "\n") - assert.Equal(s.T(), len(main.tailscales)+len(shared.tailscales), len(lines)-2) - - for hostname := range main.tailscales { - assert.Contains(s.T(), result, hostname) - } - - for hostname := range shared.tailscales { - assert.Contains(s.T(), result, hostname) - } - - // TODO(juanfont): We have to find out why do we need to wait - time.Sleep(100 * time.Second) // Wait for the nodes to receive updates - - sharedIps, err := getIPs(shared.tailscales) - assert.Nil(s.T(), err) - - for hostname, tailscale := range main.tailscales { - for peername, peerIPs := range sharedIps { - for i, ip := range peerIPs { - // We currently cant ping ourselves, so skip that. - if peername == hostname { - continue - } - s.T(). - Run(fmt.Sprintf("%s-%s-%d", hostname, peername, i), func(t *testing.T) { - // We are only interested in "direct ping" which means what we - // might need a couple of more attempts before reaching the node. - command := []string{ - "tailscale", "ping", - "--timeout=15s", - "--c=20", - "--until-direct=true", - ip.String(), - } - - fmt.Printf( - "Pinging from %s to %s (%s)\n", - hostname, - peername, - ip, - ) - result, err := ExecuteCommand( - &tailscale, - command, - []string{}, - ) - assert.Nil(t, err) - fmt.Printf("Result for %s: %s\n", hostname, result) - assert.Contains(t, result, "pong") - }) - } - } - } -} - func (s *IntegrationTestSuite) TestTailDrop() { for _, scales := range s.namespaces { ips, err := getIPs(scales.tailscales) @@ -616,6 +526,7 @@ func (s *IntegrationTestSuite) TestTailDrop() { } time.Sleep(sleepInverval) } + return } @@ -638,7 +549,7 @@ func (s *IntegrationTestSuite) TestTailDrop() { fmt.Sprintf("%s:", peername), } retry(10, 1*time.Second, func() error { - fmt.Printf( + log.Printf( "Sending file from %s to %s\n", hostname, peername, @@ -677,7 +588,7 @@ func (s *IntegrationTestSuite) TestTailDrop() { "ls", fmt.Sprintf("/tmp/file_from_%s", peername), } - fmt.Printf( + log.Printf( "Checking file in %s (%s) from %s (%s)\n", hostname, ips[hostname], @@ -690,7 +601,7 @@ func (s *IntegrationTestSuite) TestTailDrop() { []string{}, ) assert.Nil(t, err) - fmt.Printf("Result for %s: %s\n", peername, result) + log.Printf("Result for %s: %s\n", peername, result) assert.Equal( t, fmt.Sprintf("/tmp/file_from_%s\n", peername), @@ -720,7 +631,7 @@ func (s *IntegrationTestSuite) TestPingAllPeersByHostname() { fmt.Sprintf("%s.%s.headscale.net", peername, namespace), } - fmt.Printf( + log.Printf( "Pinging using hostname from %s to %s\n", hostname, peername, @@ -731,7 +642,7 @@ func (s *IntegrationTestSuite) TestPingAllPeersByHostname() { []string{}, ) assert.Nil(t, err) - fmt.Printf("Result for %s: %s\n", hostname, result) + log.Printf("Result for %s: %s\n", hostname, result) assert.Contains(t, result, "pong") }) } @@ -754,7 +665,7 @@ func (s *IntegrationTestSuite) TestMagicDNS() { fmt.Sprintf("%s.%s.headscale.net", peername, namespace), } - fmt.Printf( + log.Printf( "Resolving name %s from %s\n", peername, hostname, @@ -765,7 +676,7 @@ func (s *IntegrationTestSuite) TestMagicDNS() { []string{}, ) assert.Nil(t, err) - fmt.Printf("Result for %s: %s\n", hostname, result) + log.Printf("Result for %s: %s\n", hostname, result) for _, ip := range ips { assert.Contains(t, result, ip.String()) diff --git a/machine.go b/machine.go index 3c704ad3..dac44591 100644 --- a/machine.go +++ b/machine.go @@ -3,7 +3,6 @@ package headscale import ( "database/sql/driver" "encoding/json" - "errors" "fmt" "sort" "strconv" @@ -25,6 +24,11 @@ const ( errMachineAlreadyRegistered = Error("machine already registered") errMachineRouteIsNotAvailable = Error("route is not available on machine") errMachineAddressesInvalid = Error("failed to parse machine addresses") + errHostnameTooLong = Error("Hostname too long") +) + +const ( + maxHostnameLength = 255 ) // Machine is a Headscale client. @@ -119,19 +123,6 @@ func (machine Machine) isExpired() bool { return time.Now().UTC().After(*machine.Expiry) } -func (h *Headscale) ListAllMachines() ([]Machine, error) { - machines := []Machine{} - if err := h.db.Preload("AuthKey"). - Preload("AuthKey.Namespace"). - Preload("Namespace"). - Where("registered"). - Find(&machines).Error; err != nil { - return nil, err - } - - return machines, nil -} - func containsAddresses(inputs []string, addrs []string) bool { for _, addr := range addrs { if containsString(inputs, addr) { @@ -216,15 +207,15 @@ func getFilteredByACLPeers( return authorizedPeers } -func (h *Headscale) getDirectPeers(machine *Machine) (Machines, error) { +func (h *Headscale) ListPeers(machine *Machine) (Machines, error) { log.Trace(). Caller(). Str("machine", machine.Name). Msg("Finding direct peers") machines := Machines{} - if err := h.db.Preload("Namespace").Where("namespace_id = ? AND machine_key <> ? AND registered", - machine.NamespaceID, machine.MachineKey).Find(&machines).Error; err != nil { + if err := h.db.Preload("AuthKey").Preload("AuthKey.Namespace").Preload("Namespace").Where("machine_key <> ? AND registered", + machine.MachineKey).Find(&machines).Error; err != nil { log.Error().Err(err).Msg("Error accessing db") return Machines{}, err @@ -235,73 +226,11 @@ func (h *Headscale) getDirectPeers(machine *Machine) (Machines, error) { log.Trace(). Caller(). Str("machine", machine.Name). - Msgf("Found direct machines: %s", machines.String()) + Msgf("Found peers: %s", machines.String()) return machines, nil } -// getShared fetches machines that are shared to the `Namespace` of the machine we are getting peers for. -func (h *Headscale) getShared(machine *Machine) (Machines, error) { - log.Trace(). - Caller(). - Str("machine", machine.Name). - Msg("Finding shared peers") - - sharedMachines := []SharedMachine{} - if err := h.db.Preload("Namespace").Preload("Machine").Preload("Machine.Namespace").Where("namespace_id = ?", - machine.NamespaceID).Find(&sharedMachines).Error; err != nil { - return Machines{}, err - } - - peers := make(Machines, 0) - for _, sharedMachine := range sharedMachines { - peers = append(peers, sharedMachine.Machine) - } - - sort.Slice(peers, func(i, j int) bool { return peers[i].ID < peers[j].ID }) - - log.Trace(). - Caller(). - Str("machine", machine.Name). - Msgf("Found shared peers: %s", peers.String()) - - return peers, nil -} - -// getSharedTo fetches the machines of the namespaces this machine is shared in. -func (h *Headscale) getSharedTo(machine *Machine) (Machines, error) { - log.Trace(). - Caller(). - Str("machine", machine.Name). - Msg("Finding peers in namespaces this machine is shared with") - - sharedMachines := []SharedMachine{} - if err := h.db.Preload("Namespace").Preload("Machine").Preload("Machine.Namespace").Where("machine_id = ?", - machine.ID).Find(&sharedMachines).Error; err != nil { - return Machines{}, err - } - - peers := make(Machines, 0) - for _, sharedMachine := range sharedMachines { - namespaceMachines, err := h.ListMachinesInNamespace( - sharedMachine.Namespace.Name, - ) - if err != nil { - return Machines{}, err - } - peers = append(peers, namespaceMachines...) - } - - sort.Slice(peers, func(i, j int) bool { return peers[i].ID < peers[j].ID }) - - log.Trace(). - Caller(). - Str("machine", machine.Name). - Msgf("Found peers we are shared with: %s", peers.String()) - - return peers, nil -} - func (h *Headscale) getPeers(machine *Machine) (Machines, error) { var peers Machines var err error @@ -310,7 +239,7 @@ func (h *Headscale) getPeers(machine *Machine) (Machines, error) { // else use the classic namespace scope if h.aclPolicy != nil { var machines []Machine - machines, err = h.ListAllMachines() + machines, err = h.ListMachines() if err != nil { log.Error().Err(err).Msg("Error retrieving list of machines") @@ -318,7 +247,7 @@ func (h *Headscale) getPeers(machine *Machine) (Machines, error) { } peers = getFilteredByACLPeers(machines, h.aclRules, machine) } else { - direct, err := h.getDirectPeers(machine) + peers, err = h.ListPeers(machine) if err != nil { log.Error(). Caller(). @@ -327,28 +256,6 @@ func (h *Headscale) getPeers(machine *Machine) (Machines, error) { return Machines{}, err } - - shared, err := h.getShared(machine) - if err != nil { - log.Error(). - Caller(). - Err(err). - Msg("Cannot fetch peers") - - return Machines{}, err - } - - sharedTo, err := h.getSharedTo(machine) - if err != nil { - log.Error(). - Caller(). - Err(err). - Msg("Cannot fetch peers") - - return Machines{}, err - } - peers = append(direct, shared...) - peers = append(peers, sharedTo...) } sort.Slice(peers, func(i, j int) bool { return peers[i].ID < peers[j].ID }) @@ -459,11 +366,6 @@ func (h *Headscale) RefreshMachine(machine *Machine, expiry time.Time) { // DeleteMachine softs deletes a Machine from the database. func (h *Headscale) DeleteMachine(machine *Machine) error { - err := h.RemoveSharedMachineFromAllNamespaces(machine) - if err != nil && errors.Is(err, errMachineNotShared) { - return err - } - machine.Registered = false h.db.Save(&machine) // we mark it as unregistered, just in case if err := h.db.Delete(&machine).Error; err != nil { @@ -483,11 +385,6 @@ func (h *Headscale) TouchMachine(machine *Machine) error { // HardDeleteMachine hard deletes a Machine from the database. func (h *Headscale) HardDeleteMachine(machine *Machine) error { - err := h.RemoveSharedMachineFromAllNamespaces(machine) - if err != nil && errors.Is(err, errMachineNotShared) { - return err - } - if err := h.db.Unscoped().Delete(&machine).Error; err != nil { return err } @@ -519,17 +416,9 @@ func (h *Headscale) isOutdated(machine *Machine) bool { return true } - sharedMachines, _ := h.getShared(machine) - namespaceSet := set.New(set.ThreadSafe) namespaceSet.Add(machine.Namespace.Name) - // Check if any of our shared namespaces has updates that we have - // not propagated. - for _, sharedMachine := range sharedMachines { - namespaceSet.Add(sharedMachine.Namespace.Name) - } - namespaces := make([]string, namespaceSet.Size()) for index, namespace := range namespaceSet.List() { if name, ok := namespace.(string); ok { @@ -644,6 +533,8 @@ func (machine Machine) toNode( []netaddr.IPPrefix{}, addrs...) // we append the node own IP, as it is required by the clients + // TODO(kradalby): Needs investigation, We probably dont need this condition + // now that we dont have shared nodes if includeRoutes { routesStr := []string{} if len(machine.EnabledRoutes) != 0 { @@ -709,13 +600,16 @@ func (machine Machine) toNode( hostname = fmt.Sprintf( "%s.%s.%s", machine.Name, - strings.ReplaceAll( - machine.Namespace.Name, - "@", - ".", - ), // Replace @ with . for valid domain for machine + machine.Namespace.Name, baseDomain, ) + if len(hostname) > maxHostnameLength { + return nil, fmt.Errorf( + "hostname %q is too long it cannot except 255 ASCII chars: %w", + hostname, + errHostnameTooLong, + ) + } } else { hostname = machine.Name } @@ -856,6 +750,9 @@ func (h *Headscale) RegisterMachine( return nil, err } + h.ipAllocationMutex.Lock() + defer h.ipAllocationMutex.Unlock() + ips, err := h.getAvailableIPs() if err != nil { log.Error(). diff --git a/machine_test.go b/machine_test.go index b1cd3419..e9c91f8b 100644 --- a/machine_test.go +++ b/machine_test.go @@ -118,7 +118,7 @@ func (s *Suite) TestHardDeleteMachine(c *check.C) { c.Assert(err, check.NotNil) } -func (s *Suite) TestGetDirectPeers(c *check.C) { +func (s *Suite) TestListPeers(c *check.C) { namespace, err := app.CreateNamespace("test") c.Assert(err, check.IsNil) @@ -149,7 +149,7 @@ func (s *Suite) TestGetDirectPeers(c *check.C) { _, err = machine0ByID.GetHostInfo() c.Assert(err, check.IsNil) - peersOfMachine0, err := app.getDirectPeers(machine0ByID) + peersOfMachine0, err := app.ListPeers(machine0ByID) c.Assert(err, check.IsNil) c.Assert(len(peersOfMachine0), check.Equals, 9) @@ -222,7 +222,7 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) { _, err = testMachine.GetHostInfo() c.Assert(err, check.IsNil) - machines, err := app.ListAllMachines() + machines, err := app.ListMachines() c.Assert(err, check.IsNil) peersOfTestMachine := getFilteredByACLPeers(machines, app.aclRules, testMachine) diff --git a/namespaces.go b/namespaces.go index bdd440cf..31517841 100644 --- a/namespaces.go +++ b/namespaces.go @@ -2,7 +2,10 @@ package headscale import ( "errors" + "fmt" + "regexp" "strconv" + "strings" "time" v1 "github.com/juanfont/headscale/gen/go/headscale/v1" @@ -16,8 +19,16 @@ const ( errNamespaceExists = Error("Namespace already exists") errNamespaceNotFound = Error("Namespace not found") errNamespaceNotEmptyOfNodes = Error("Namespace not empty: node(s) found") + errInvalidNamespaceName = Error("Invalid namespace name") ) +const ( + // value related to RFC 1123 and 952. + labelHostnameLength = 63 +) + +var invalidCharsInNamespaceRegex = regexp.MustCompile("[^a-z0-9-.]+") + // Namespace is the way Headscale implements the concept of users in Tailscale // // At the end of the day, users in Tailscale are some kind of 'bubbles' or namespaces @@ -30,6 +41,10 @@ type Namespace struct { // CreateNamespace creates a new Namespace. Returns error if could not be created // or another namespace already exists. func (h *Headscale) CreateNamespace(name string) (*Namespace, error) { + err := CheckNamespaceName(name) + if err != nil { + return nil, err + } namespace := Namespace{} if err := h.db.Where("name = ?", name).First(&namespace).Error; err == nil { return nil, errNamespaceExists @@ -84,10 +99,15 @@ func (h *Headscale) DestroyNamespace(name string) error { // RenameNamespace renames a Namespace. Returns error if the Namespace does // not exist or if another Namespace exists with the new name. func (h *Headscale) RenameNamespace(oldName, newName string) error { + var err error oldNamespace, err := h.GetNamespace(oldName) if err != nil { return err } + err = CheckNamespaceName(newName) + if err != nil { + return err + } _, err = h.GetNamespace(newName) if err == nil { return errNamespaceExists @@ -130,6 +150,10 @@ func (h *Headscale) ListNamespaces() ([]Namespace, error) { // ListMachinesInNamespace gets all the nodes in a given namespace. func (h *Headscale) ListMachinesInNamespace(name string) ([]Machine, error) { + err := CheckNamespaceName(name) + if err != nil { + return nil, err + } namespace, err := h.GetNamespace(name) if err != nil { return nil, err @@ -143,33 +167,12 @@ func (h *Headscale) ListMachinesInNamespace(name string) ([]Machine, error) { return machines, nil } -// ListSharedMachinesInNamespace returns all the machines that are shared to the specified namespace. -func (h *Headscale) ListSharedMachinesInNamespace(name string) ([]Machine, error) { - namespace, err := h.GetNamespace(name) - if err != nil { - return nil, err - } - sharedMachines := []SharedMachine{} - if err := h.db.Preload("Namespace").Where(&SharedMachine{NamespaceID: namespace.ID}).Find(&sharedMachines).Error; err != nil { - return nil, err - } - - machines := []Machine{} - for _, sharedMachine := range sharedMachines { - machine, err := h.GetMachineByID( - sharedMachine.MachineID, - ) // otherwise not everything comes filled - if err != nil { - return nil, err - } - machines = append(machines, *machine) - } - - return machines, nil -} - // SetMachineNamespace assigns a Machine to a namespace. func (h *Headscale) SetMachineNamespace(machine *Machine, namespaceName string) error { + err := CheckNamespaceName(namespaceName) + if err != nil { + return err + } namespace, err := h.GetNamespace(namespaceName) if err != nil { return err @@ -233,3 +236,55 @@ func (n *Namespace) toProto() *v1.Namespace { CreatedAt: timestamppb.New(n.CreatedAt), } } + +// NormalizeNamespaceName will replace forbidden chars in namespace +// it can also return an error if the namespace doesn't respect RFC 952 and 1123. +func NormalizeNamespaceName(name string, stripEmailDomain bool) (string, error) { + name = strings.ToLower(name) + name = strings.ReplaceAll(name, "'", "") + atIdx := strings.Index(name, "@") + if stripEmailDomain && atIdx > 0 { + name = name[:atIdx] + } else { + name = strings.ReplaceAll(name, "@", ".") + } + name = invalidCharsInNamespaceRegex.ReplaceAllString(name, "-") + + for _, elt := range strings.Split(name, ".") { + if len(elt) > labelHostnameLength { + return "", fmt.Errorf( + "label %v is more than 63 chars: %w", + elt, + errInvalidNamespaceName, + ) + } + } + + return name, nil +} + +func CheckNamespaceName(name string) error { + if len(name) > labelHostnameLength { + return fmt.Errorf( + "Namespace must not be over 63 chars. %v doesn't comply with this rule: %w", + name, + errInvalidNamespaceName, + ) + } + if strings.ToLower(name) != name { + return fmt.Errorf( + "Namespace name should be lowercase. %v doesn't comply with this rule: %w", + name, + errInvalidNamespaceName, + ) + } + if invalidCharsInNamespaceRegex.MatchString(name) { + return fmt.Errorf( + "Namespace name should only be composed of lowercase ASCII letters numbers, hyphen and dots. %v doesn't comply with theses rules: %w", + name, + errInvalidNamespaceName, + ) + } + + return nil +} diff --git a/namespaces_test.go b/namespaces_test.go index d07deb96..585ba938 100644 --- a/namespaces_test.go +++ b/namespaces_test.go @@ -1,7 +1,8 @@ package headscale import ( - "github.com/rs/zerolog/log" + "testing" + "gopkg.in/check.v1" "gorm.io/gorm" "inet.af/netaddr" @@ -72,23 +73,23 @@ func (s *Suite) TestRenameNamespace(c *check.C) { c.Assert(err, check.IsNil) c.Assert(len(namespaces), check.Equals, 1) - err = app.RenameNamespace("test", "test_renamed") + err = app.RenameNamespace("test", "test-renamed") c.Assert(err, check.IsNil) _, err = app.GetNamespace("test") c.Assert(err, check.Equals, errNamespaceNotFound) - _, err = app.GetNamespace("test_renamed") + _, err = app.GetNamespace("test-renamed") c.Assert(err, check.IsNil) - err = app.RenameNamespace("test_does_not_exit", "test") + err = app.RenameNamespace("test-does-not-exit", "test") c.Assert(err, check.Equals, errNamespaceNotFound) namespaceTest2, err := app.CreateNamespace("test2") c.Assert(err, check.IsNil) c.Assert(namespaceTest2.Name, check.Equals, "test2") - err = app.RenameNamespace("test2", "test_renamed") + err = app.RenameNamespace("test2", "test-renamed") c.Assert(err, check.Equals, errNamespaceExists) } @@ -206,8 +207,6 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) { } app.db.Save(machine2InShared1) - err = app.AddSharedMachineToNamespace(machineInShared2, namespaceShared1) - c.Assert(err, check.IsNil) peersOfMachine1InShared1, err := app.getPeers(machineInShared1) c.Assert(err, check.IsNil) @@ -216,8 +215,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) { peersOfMachine1InShared1, ) - log.Trace().Msgf("userProfiles %#v", userProfiles) - c.Assert(len(userProfiles), check.Equals, 2) + c.Assert(len(userProfiles), check.Equals, 3) found := false for _, userProfiles := range userProfiles { @@ -239,3 +237,143 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) { } c.Assert(found, check.Equals, true) } + +func TestNormalizeNamespaceName(t *testing.T) { + type args struct { + name string + stripEmailDomain bool + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "normalize simple name", + args: args{ + name: "normalize-simple.name", + stripEmailDomain: false, + }, + want: "normalize-simple.name", + wantErr: false, + }, + { + name: "normalize an email", + args: args{ + name: "foo.bar@example.com", + stripEmailDomain: false, + }, + want: "foo.bar.example.com", + wantErr: false, + }, + { + name: "normalize an email domain should be removed", + args: args{ + name: "foo.bar@example.com", + stripEmailDomain: true, + }, + want: "foo.bar", + wantErr: false, + }, + { + name: "strip enabled no email passed as argument", + args: args{ + name: "not-email-and-strip-enabled", + stripEmailDomain: true, + }, + want: "not-email-and-strip-enabled", + wantErr: false, + }, + { + name: "normalize complex email", + args: args{ + name: "foo.bar+complex-email@example.com", + stripEmailDomain: false, + }, + want: "foo.bar-complex-email.example.com", + wantErr: false, + }, + { + name: "namespace name with space", + args: args{ + name: "name space", + stripEmailDomain: false, + }, + want: "name-space", + wantErr: false, + }, + { + name: "namespace with quote", + args: args{ + name: "Jamie's iPhone 5", + stripEmailDomain: false, + }, + want: "jamies-iphone-5", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NormalizeNamespaceName(tt.args.name, tt.args.stripEmailDomain) + if (err != nil) != tt.wantErr { + t.Errorf( + "NormalizeNamespaceName() error = %v, wantErr %v", + err, + tt.wantErr, + ) + + return + } + if got != tt.want { + t.Errorf("NormalizeNamespaceName() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCheckNamespaceName(t *testing.T) { + type args struct { + name string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid: namespace", + args: args{name: "valid-namespace"}, + wantErr: false, + }, + { + name: "invalid: capitalized namespace", + args: args{name: "Invalid-CapItaLIzed-namespace"}, + wantErr: true, + }, + { + name: "invalid: email as namespace", + args: args{name: "foo.bar@example.com"}, + wantErr: true, + }, + { + name: "invalid: chars in namespace name", + args: args{name: "super-namespace+name"}, + wantErr: true, + }, + { + name: "invalid: too long name for namespace", + args: args{ + name: "super-long-namespace-name-that-should-be-a-little-more-than-63-chars", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := CheckNamespaceName(tt.args.name); (err != nil) != tt.wantErr { + t.Errorf("CheckNamespaceName() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/oidc.go b/oidc.go index a47863ff..edea32a8 100644 --- a/oidc.go +++ b/oidc.go @@ -9,7 +9,6 @@ import ( "fmt" "html/template" "net/http" - "regexp" "strings" "time" @@ -282,109 +281,92 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { now := time.Now().UTC() - if namespaceName, ok := h.getNamespaceFromEmail(claims.Email); ok { - // register the machine if it's new - if !machine.Registered { - log.Debug().Msg("Registering new machine after successful callback") - - namespace, err := h.GetNamespace(namespaceName) - if errors.Is(err, gorm.ErrRecordNotFound) { - namespace, err = h.CreateNamespace(namespaceName) - - if err != nil { - log.Error(). - Err(err). - Caller(). - Msgf("could not create new namespace '%s'", namespaceName) - ctx.String( - http.StatusInternalServerError, - "could not create new namespace", - ) - - return - } - } else if err != nil { - log.Error(). - Caller(). - Err(err). - Str("namespace", namespaceName). - Msg("could not find or create namespace") - ctx.String( - http.StatusInternalServerError, - "could not find or create namespace", - ) - - return - } - - ips, err := h.getAvailableIPs() - if err != nil { - log.Error(). - Caller(). - Err(err). - Msg("could not get an IP from the pool") - ctx.String( - http.StatusInternalServerError, - "could not get an IP from the pool", - ) - - return - } - - machine.IPAddresses = ips - machine.NamespaceID = namespace.ID - machine.Registered = true - machine.RegisterMethod = RegisterMethodOIDC - machine.LastSuccessfulUpdate = &now - machine.Expiry = &requestedTime - h.db.Save(&machine) - } - - var content bytes.Buffer - if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{ - User: claims.Email, - Verb: "Authenticated", - }); err != nil { - log.Error(). - Str("func", "OIDCCallback"). - Str("type", "authenticate"). - Err(err). - Msg("Could not render OIDC callback template") - ctx.Data( - http.StatusInternalServerError, - "text/html; charset=utf-8", - []byte("Could not render OIDC callback template"), - ) - } - - ctx.Data(http.StatusOK, "text/html; charset=utf-8", content.Bytes()) + namespaceName, err := NormalizeNamespaceName( + claims.Email, + h.cfg.OIDC.StripEmaildomain, + ) + if err != nil { + log.Error().Err(err).Caller().Msgf("couldn't normalize email") + ctx.String( + http.StatusInternalServerError, + "couldn't normalize email", + ) return } + // register the machine if it's new + if !machine.Registered { + log.Debug().Msg("Registering new machine after successful callback") - log.Error(). - Caller(). - Str("email", claims.Email). - Str("username", claims.Username). - Str("machine", machine.Name). - Msg("Email could not be mapped to a namespace") - ctx.String( - http.StatusBadRequest, - "email from claim could not be mapped to a namespace", - ) -} + namespace, err := h.GetNamespace(namespaceName) + if errors.Is(err, gorm.ErrRecordNotFound) { + namespace, err = h.CreateNamespace(namespaceName) -// getNamespaceFromEmail passes the users email through a list of "matchers" -// and iterates through them until it matches and returns a namespace. -// If no match is found, an empty string will be returned. -// TODO(kradalby): golang Maps key order is not stable, so this list is _not_ deterministic. Find a way to make the list of keys stable, preferably in the order presented in a users configuration. -func (h *Headscale) getNamespaceFromEmail(email string) (string, bool) { - for match, namespace := range h.cfg.OIDC.MatchMap { - regex := regexp.MustCompile(match) - if regex.MatchString(email) { - return namespace, true + if err != nil { + log.Error(). + Err(err). + Caller(). + Msgf("could not create new namespace '%s'", namespaceName) + ctx.String( + http.StatusInternalServerError, + "could not create new namespace", + ) + + return + } + } else if err != nil { + log.Error(). + Caller(). + Err(err). + Str("namespace", namespaceName). + Msg("could not find or create namespace") + ctx.String( + http.StatusInternalServerError, + "could not find or create namespace", + ) + + return } + + ips, err := h.getAvailableIPs() + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("could not get an IP from the pool") + ctx.String( + http.StatusInternalServerError, + "could not get an IP from the pool", + ) + + return + } + + machine.IPAddresses = ips + machine.NamespaceID = namespace.ID + machine.Registered = true + machine.RegisterMethod = RegisterMethodOIDC + machine.LastSuccessfulUpdate = &now + machine.Expiry = &requestedTime + h.db.Save(&machine) } - return "", false + var content bytes.Buffer + if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{ + User: claims.Email, + Verb: "Authenticated", + }); err != nil { + log.Error(). + Str("func", "OIDCCallback"). + Str("type", "authenticate"). + Err(err). + Msg("Could not render OIDC callback template") + ctx.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Could not render OIDC callback template"), + ) + } + + ctx.Data(http.StatusOK, "text/html; charset=utf-8", content.Bytes()) } diff --git a/oidc_test.go b/oidc_test.go deleted file mode 100644 index d50027a9..00000000 --- a/oidc_test.go +++ /dev/null @@ -1,180 +0,0 @@ -package headscale - -import ( - "sync" - "testing" - - "github.com/coreos/go-oidc/v3/oidc" - "github.com/patrickmn/go-cache" - "golang.org/x/oauth2" - "gorm.io/gorm" - "tailscale.com/tailcfg" - "tailscale.com/types/key" -) - -func TestHeadscale_getNamespaceFromEmail(t *testing.T) { - type fields struct { - cfg Config - db *gorm.DB - dbString string - dbType string - dbDebug bool - privateKey *key.MachinePrivate - aclPolicy *ACLPolicy - aclRules []tailcfg.FilterRule - lastStateChange sync.Map - oidcProvider *oidc.Provider - oauth2Config *oauth2.Config - oidcStateCache *cache.Cache - } - type args struct { - email string - } - tests := []struct { - name string - fields fields - args args - want string - want1 bool - }{ - { - name: "match all", - fields: fields{ - cfg: Config{ - OIDC: OIDCConfig{ - MatchMap: map[string]string{ - ".*": "space", - }, - }, - }, - }, - args: args{ - email: "test@example.no", - }, - want: "space", - want1: true, - }, - { - name: "match user", - fields: fields{ - cfg: Config{ - OIDC: OIDCConfig{ - MatchMap: map[string]string{ - "specific@user\\.no": "user-namespace", - }, - }, - }, - }, - args: args{ - email: "specific@user.no", - }, - want: "user-namespace", - want1: true, - }, - { - name: "match domain", - fields: fields{ - cfg: Config{ - OIDC: OIDCConfig{ - MatchMap: map[string]string{ - ".*@example\\.no": "example", - }, - }, - }, - }, - args: args{ - email: "test@example.no", - }, - want: "example", - want1: true, - }, - { - name: "multi match domain", - fields: fields{ - cfg: Config{ - OIDC: OIDCConfig{ - MatchMap: map[string]string{ - ".*@example\\.no": "exammple", - ".*@gmail\\.com": "gmail", - }, - }, - }, - }, - args: args{ - email: "someuser@gmail.com", - }, - want: "gmail", - want1: true, - }, - { - name: "no match domain", - fields: fields{ - cfg: Config{ - OIDC: OIDCConfig{ - MatchMap: map[string]string{ - ".*@dontknow.no": "never", - }, - }, - }, - }, - args: args{ - email: "test@wedontknow.no", - }, - want: "", - want1: false, - }, - { - name: "multi no match domain", - fields: fields{ - cfg: Config{ - OIDC: OIDCConfig{ - MatchMap: map[string]string{ - ".*@dontknow.no": "never", - ".*@wedontknow.no": "other", - ".*\\.no": "stuffy", - }, - }, - }, - }, - args: args{ - email: "tasy@nonofthem.com", - }, - want: "", - want1: false, - }, - } - //nolint - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - app := &Headscale{ - cfg: test.fields.cfg, - db: test.fields.db, - dbString: test.fields.dbString, - dbType: test.fields.dbType, - dbDebug: test.fields.dbDebug, - privateKey: test.fields.privateKey, - aclPolicy: test.fields.aclPolicy, - aclRules: test.fields.aclRules, - lastStateChange: test.fields.lastStateChange, - oidcProvider: test.fields.oidcProvider, - oauth2Config: test.fields.oauth2Config, - oidcStateCache: test.fields.oidcStateCache, - } - got, got1 := app.getNamespaceFromEmail(test.args.email) - if got != test.want { - t.Errorf( - "Headscale.getNamespaceFromEmail() got = %v, want %v", - got, - test.want, - ) - } - if got1 != test.want1 { - t.Errorf( - "Headscale.getNamespaceFromEmail() got1 = %v, want %v", - got1, - test.want1, - ) - } - }) - } -} diff --git a/proto/headscale/v1/headscale.proto b/proto/headscale/v1/headscale.proto index 3cbbb8ed..d6571b0d 100644 --- a/proto/headscale/v1/headscale.proto +++ b/proto/headscale/v1/headscale.proto @@ -104,18 +104,6 @@ service HeadscaleService { get: "/api/v1/machine" }; } - - rpc ShareMachine(ShareMachineRequest) returns (ShareMachineResponse) { - option (google.api.http) = { - post: "/api/v1/machine/{machine_id}/share/{namespace}" - }; - } - - rpc UnshareMachine(UnshareMachineRequest) returns (UnshareMachineResponse) { - option (google.api.http) = { - post: "/api/v1/machine/{machine_id}/unshare/{namespace}" - }; - } // --- Machine end --- // --- Route start --- diff --git a/proto/headscale/v1/machine.proto b/proto/headscale/v1/machine.proto index 47664e15..7451db83 100644 --- a/proto/headscale/v1/machine.proto +++ b/proto/headscale/v1/machine.proto @@ -80,24 +80,6 @@ message ListMachinesResponse { repeated Machine machines = 1; } -message ShareMachineRequest { - uint64 machine_id = 1; - string namespace = 2; -} - -message ShareMachineResponse { - Machine machine = 1; -} - -message UnshareMachineRequest { - uint64 machine_id = 1; - string namespace = 2; -} - -message UnshareMachineResponse { - Machine machine = 1; -} - message DebugCreateMachineRequest { string namespace = 1; string key = 2; diff --git a/sharing.go b/sharing.go deleted file mode 100644 index caac5319..00000000 --- a/sharing.go +++ /dev/null @@ -1,81 +0,0 @@ -package headscale - -import "gorm.io/gorm" - -const ( - errSameNamespace = Error("Destination namespace same as origin") - errMachineAlreadyShared = Error("Node already shared to this namespace") - errMachineNotShared = Error("Machine not shared to this namespace") -) - -// SharedMachine is a join table to support sharing nodes between namespaces. -type SharedMachine struct { - gorm.Model - MachineID uint64 - Machine Machine - NamespaceID uint - Namespace Namespace -} - -// AddSharedMachineToNamespace adds a machine as a shared node to a namespace. -func (h *Headscale) AddSharedMachineToNamespace( - machine *Machine, - namespace *Namespace, -) error { - if machine.NamespaceID == namespace.ID { - return errSameNamespace - } - - sharedMachines := []SharedMachine{} - if err := h.db.Where("machine_id = ? AND namespace_id = ?", machine.ID, namespace.ID).Find(&sharedMachines).Error; err != nil { - return err - } - if len(sharedMachines) > 0 { - return errMachineAlreadyShared - } - - sharedMachine := SharedMachine{ - MachineID: machine.ID, - Machine: *machine, - NamespaceID: namespace.ID, - Namespace: *namespace, - } - h.db.Save(&sharedMachine) - - return nil -} - -// RemoveSharedMachineFromNamespace removes a shared machine from a namespace. -func (h *Headscale) RemoveSharedMachineFromNamespace( - machine *Machine, - namespace *Namespace, -) error { - if machine.NamespaceID == namespace.ID { - // Can't unshare from primary namespace - return errMachineNotShared - } - - sharedMachine := SharedMachine{} - result := h.db.Where("machine_id = ? AND namespace_id = ?", machine.ID, namespace.ID). - Unscoped(). - Delete(&sharedMachine) - if result.Error != nil { - return result.Error - } - - if result.RowsAffected == 0 { - return errMachineNotShared - } - - return nil -} - -// RemoveSharedMachineFromAllNamespaces removes a machine as a shared node from all namespaces. -func (h *Headscale) RemoveSharedMachineFromAllNamespaces(machine *Machine) error { - sharedMachine := SharedMachine{} - if result := h.db.Where("machine_id = ?", machine.ID).Unscoped().Delete(&sharedMachine); result.Error != nil { - return result.Error - } - - return nil -} diff --git a/sharing_test.go b/sharing_test.go deleted file mode 100644 index b7fef4e2..00000000 --- a/sharing_test.go +++ /dev/null @@ -1,341 +0,0 @@ -package headscale - -import ( - "gopkg.in/check.v1" - "inet.af/netaddr" -) - -func CreateNodeNamespace( - c *check.C, - namespaceName, node, key, ip string, -) (*Namespace, *Machine) { - namespace, err := app.CreateNamespace(namespaceName) - c.Assert(err, check.IsNil) - - pak1, err := app.CreatePreAuthKey(namespace.Name, false, false, nil) - c.Assert(err, check.IsNil) - - _, err = app.GetMachine(namespace.Name, node) - c.Assert(err, check.NotNil) - - machine := &Machine{ - ID: 0, - MachineKey: key, - NodeKey: key, - DiscoKey: key, - Name: node, - NamespaceID: namespace.ID, - Registered: true, - RegisterMethod: RegisterMethodAuthKey, - IPAddresses: []netaddr.IP{netaddr.MustParseIP("100.64.0.1")}, - AuthKeyID: uint(pak1.ID), - } - app.db.Save(machine) - - _, err = app.GetMachine(namespace.Name, machine.Name) - c.Assert(err, check.IsNil) - - return namespace, machine -} - -func (s *Suite) TestBasicSharedNodesInNamespace(c *check.C) { - namespace1, machine1 := CreateNodeNamespace( - c, - "shared1", - "test_get_shared_nodes_1", - "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", - "100.64.0.1", - ) - _, machine2 := CreateNodeNamespace( - c, - "shared2", - "test_get_shared_nodes_2", - "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", - "100.64.0.2", - ) - - peersOfMachine1BeforeShared, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1BeforeShared), check.Equals, 0) - - err = app.AddSharedMachineToNamespace(machine2, namespace1) - c.Assert(err, check.IsNil) - - peersOfMachine1AfterShared, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1AfterShared), check.Equals, 1) - c.Assert(peersOfMachine1AfterShared[0].ID, check.Equals, machine2.ID) -} - -func (s *Suite) TestSameNamespace(c *check.C) { - namespace1, machine1 := CreateNodeNamespace( - c, - "shared1", - "test_get_shared_nodes_1", - "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", - "100.64.0.1", - ) - - peersOfMachine1BeforeShare, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1BeforeShare), check.Equals, 0) - - err = app.AddSharedMachineToNamespace(machine1, namespace1) - c.Assert(err, check.Equals, errSameNamespace) -} - -func (s *Suite) TestUnshare(c *check.C) { - namespace1, machine1 := CreateNodeNamespace( - c, - "shared1", - "test_unshare_1", - "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", - "100.64.0.1", - ) - _, machine2 := CreateNodeNamespace( - c, - "shared2", - "test_unshare_2", - "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", - "100.64.0.2", - ) - - peersOfMachine1BeforeShare, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1BeforeShare), check.Equals, 0) - - err = app.AddSharedMachineToNamespace(machine2, namespace1) - c.Assert(err, check.IsNil) - - peersOfMachine1BeforeShare, err = app.getShared(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1BeforeShare), check.Equals, 1) - - err = app.RemoveSharedMachineFromNamespace(machine2, namespace1) - c.Assert(err, check.IsNil) - - peersOfMachine1BeforeShare, err = app.getShared(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1BeforeShare), check.Equals, 0) - - err = app.RemoveSharedMachineFromNamespace(machine2, namespace1) - c.Assert(err, check.Equals, errMachineNotShared) - - err = app.RemoveSharedMachineFromNamespace(machine1, namespace1) - c.Assert(err, check.Equals, errMachineNotShared) -} - -func (s *Suite) TestAlreadyShared(c *check.C) { - namespace1, machine1 := CreateNodeNamespace( - c, - "shared1", - "test_get_shared_nodes_1", - "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", - "100.64.0.1", - ) - _, machine2 := CreateNodeNamespace( - c, - "shared2", - "test_get_shared_nodes_2", - "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", - "100.64.0.2", - ) - - peersOfMachine1BeforeShare, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1BeforeShare), check.Equals, 0) - - err = app.AddSharedMachineToNamespace(machine2, namespace1) - c.Assert(err, check.IsNil) - err = app.AddSharedMachineToNamespace(machine2, namespace1) - c.Assert(err, check.Equals, errMachineAlreadyShared) -} - -func (s *Suite) TestDoNotIncludeRoutesOnShared(c *check.C) { - namespace1, machine1 := CreateNodeNamespace( - c, - "shared1", - "test_get_shared_nodes_1", - "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", - "100.64.0.1", - ) - _, machine2 := CreateNodeNamespace( - c, - "shared2", - "test_get_shared_nodes_2", - "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", - "100.64.0.2", - ) - - peersOfMachine1BeforeShare, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1BeforeShare), check.Equals, 0) - - err = app.AddSharedMachineToNamespace(machine2, namespace1) - c.Assert(err, check.IsNil) - - peersOfMachine1AfterShare, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1AfterShare), check.Equals, 1) - c.Assert(peersOfMachine1AfterShare[0].Name, check.Equals, "test_get_shared_nodes_2") -} - -func (s *Suite) TestComplexSharingAcrossNamespaces(c *check.C) { - namespace1, machine1 := CreateNodeNamespace( - c, - "shared1", - "test_get_shared_nodes_1", - "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", - "100.64.0.1", - ) - _, machine2 := CreateNodeNamespace( - c, - "shared2", - "test_get_shared_nodes_2", - "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", - "100.64.0.2", - ) - _, machine3 := CreateNodeNamespace( - c, - "shared3", - "test_get_shared_nodes_3", - "6e704bee83eb93db6fc2c417d7882964cd3f8cc87082cbb645982e34020c76c8", - "100.64.0.3", - ) - - pak4, err := app.CreatePreAuthKey(namespace1.Name, false, false, nil) - c.Assert(err, check.IsNil) - - machine4 := &Machine{ - ID: 4, - MachineKey: "4c3e07c3ecd40e9c945bb6797557c451850691c0409740578325e17009dd298f", - NodeKey: "4c3e07c3ecd40e9c945bb6797557c451850691c0409740578325e17009dd298f", - DiscoKey: "4c3e07c3ecd40e9c945bb6797557c451850691c0409740578325e17009dd298f", - Name: "test_get_shared_nodes_4", - NamespaceID: namespace1.ID, - Registered: true, - RegisterMethod: RegisterMethodAuthKey, - IPAddresses: []netaddr.IP{netaddr.MustParseIP("100.64.0.4")}, - AuthKeyID: uint(pak4.ID), - } - app.db.Save(machine4) - - _, err = app.GetMachine(namespace1.Name, machine4.Name) - c.Assert(err, check.IsNil) - - peersOfMachine1BeforeShare, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1BeforeShare), check.Equals, 1) // node1 can see node4 - c.Assert(peersOfMachine1BeforeShare[0].Name, check.Equals, machine4.Name) - - err = app.AddSharedMachineToNamespace(machine2, namespace1) - c.Assert(err, check.IsNil) - - peersOfMachine1AfterShare, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert( - len(peersOfMachine1AfterShare), - check.Equals, - 2, - ) // node1 can see node2 (shared) and node4 (same namespace) - c.Assert(peersOfMachine1AfterShare[0].Name, check.Equals, machine2.Name) - c.Assert(peersOfMachine1AfterShare[1].Name, check.Equals, machine4.Name) - - sharedOfMachine1, err := app.getShared(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(sharedOfMachine1), check.Equals, 1) // node1 can see node2 as shared - c.Assert(sharedOfMachine1[0].Name, check.Equals, machine2.Name) - - peersOfMachine3, err := app.getPeers(machine3) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine3), check.Equals, 0) // node3 is alone - - peersOfMachine2, err := app.getPeers(machine2) - c.Assert(err, check.IsNil) - c.Assert( - len(peersOfMachine2), - check.Equals, - 2, - ) // node2 should see node1 (sharedTo) and node4 (sharedTo), as is shared in namespace1 - c.Assert(peersOfMachine2[0].Name, check.Equals, machine1.Name) - c.Assert(peersOfMachine2[1].Name, check.Equals, machine4.Name) -} - -func (s *Suite) TestDeleteSharedMachine(c *check.C) { - namespace1, machine1 := CreateNodeNamespace( - c, - "shared1", - "test_get_shared_nodes_1", - "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", - "100.64.0.1", - ) - _, machine2 := CreateNodeNamespace( - c, - "shared2", - "test_get_shared_nodes_2", - "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", - "100.64.0.2", - ) - _, machine3 := CreateNodeNamespace( - c, - "shared3", - "test_get_shared_nodes_3", - "6e704bee83eb93db6fc2c417d7882964cd3f8cc87082cbb645982e34020c76c8", - "100.64.0.3", - ) - - pak4n1, err := app.CreatePreAuthKey(namespace1.Name, false, false, nil) - c.Assert(err, check.IsNil) - machine4 := &Machine{ - ID: 4, - MachineKey: "4c3e07c3ecd40e9c945bb6797557c451850691c0409740578325e17009dd298f", - NodeKey: "4c3e07c3ecd40e9c945bb6797557c451850691c0409740578325e17009dd298f", - DiscoKey: "4c3e07c3ecd40e9c945bb6797557c451850691c0409740578325e17009dd298f", - Name: "test_get_shared_nodes_4", - NamespaceID: namespace1.ID, - Registered: true, - RegisterMethod: RegisterMethodAuthKey, - IPAddresses: []netaddr.IP{netaddr.MustParseIP("100.64.0.4")}, - AuthKeyID: uint(pak4n1.ID), - } - app.db.Save(machine4) - - _, err = app.GetMachine(namespace1.Name, machine4.Name) - c.Assert(err, check.IsNil) - - peersOfMachine1BeforeShare, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1BeforeShare), check.Equals, 1) // nodes 1 and 4 - c.Assert(peersOfMachine1BeforeShare[0].Name, check.Equals, machine4.Name) - - err = app.AddSharedMachineToNamespace(machine2, namespace1) - c.Assert(err, check.IsNil) - - peersOfMachine1AfterShare, err := app.getPeers(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine1AfterShare), check.Equals, 2) // nodes 1, 2, 4 - c.Assert(peersOfMachine1AfterShare[0].Name, check.Equals, machine2.Name) - c.Assert(peersOfMachine1AfterShare[1].Name, check.Equals, machine4.Name) - - sharedOfMachine1, err := app.getShared(machine1) - c.Assert(err, check.IsNil) - c.Assert(len(sharedOfMachine1), check.Equals, 1) // nodes 1, 2, 4 - c.Assert(sharedOfMachine1[0].Name, check.Equals, machine2.Name) - - peersOfMachine3, err := app.getPeers(machine3) - c.Assert(err, check.IsNil) - c.Assert(len(peersOfMachine3), check.Equals, 0) // node 3 is alone - - sharedMachinesInNamespace1, err := app.ListSharedMachinesInNamespace( - namespace1.Name, - ) - c.Assert(err, check.IsNil) - c.Assert(len(sharedMachinesInNamespace1), check.Equals, 1) - - err = app.DeleteMachine(machine2) - c.Assert(err, check.IsNil) - - sharedMachinesInNamespace1, err = app.ListSharedMachinesInNamespace(namespace1.Name) - c.Assert(err, check.IsNil) - c.Assert(len(sharedMachinesInNamespace1), check.Equals, 0) -} diff --git a/utils.go b/utils.go index 3cee5e35..004bf306 100644 --- a/utils.go +++ b/utils.go @@ -157,9 +157,6 @@ func GetIPPrefixEndpoints(na netaddr.IPPrefix) (network, broadcast netaddr.IP) { return } -// TODO: Is this concurrency safe? -// What would happen if multiple hosts were to register at the same time? -// Would we attempt to assign the same addresses to multiple nodes? func (h *Headscale) getAvailableIP(ipPrefix netaddr.IPPrefix) (*netaddr.IP, error) { usedIps, err := h.getUsedIPs() if err != nil { @@ -179,7 +176,7 @@ func (h *Headscale) getAvailableIP(ipPrefix netaddr.IPPrefix) (*netaddr.IP, erro switch { case ip.Compare(ipPrefixBroadcastAddress) == 0: fallthrough - case containsIPs(usedIps, ip): + case usedIps.Contains(ip): fallthrough case ip.IsZero() || ip.IsLoopback(): ip = ip.Next() @@ -192,24 +189,46 @@ func (h *Headscale) getAvailableIP(ipPrefix netaddr.IPPrefix) (*netaddr.IP, erro } } -func (h *Headscale) getUsedIPs() ([]netaddr.IP, error) { +func (h *Headscale) getUsedIPs() (*netaddr.IPSet, error) { // FIXME: This really deserves a better data model, // but this was quick to get running and it should be enough // to begin experimenting with a dual stack tailnet. var addressesSlices []string h.db.Model(&Machine{}).Pluck("ip_addresses", &addressesSlices) - ips := make([]netaddr.IP, 0, len(h.cfg.IPPrefixes)*len(addressesSlices)) + log.Trace(). + Strs("addresses", addressesSlices). + Msg("Got allocated ip addresses from databases") + + var ips netaddr.IPSetBuilder for _, slice := range addressesSlices { - var a MachineAddresses - err := a.Scan(slice) + var machineAddresses MachineAddresses + err := machineAddresses.Scan(slice) if err != nil { - return nil, fmt.Errorf("failed to read ip from database: %w", err) + return &netaddr.IPSet{}, fmt.Errorf( + "failed to read ip from database: %w", + err, + ) + } + + for _, ip := range machineAddresses { + ips.Add(ip) } - ips = append(ips, a...) } - return ips, nil + log.Trace(). + Interface("addresses", ips). + Msg("Parsed ip addresses that has been allocated from databases") + + ipSet, err := ips.IPSet() + if err != nil { + return &netaddr.IPSet{}, fmt.Errorf( + "failed to build IP Set: %w", + err, + ) + } + + return ipSet, nil } func containsString(ss []string, s string) bool { @@ -222,16 +241,6 @@ func containsString(ss []string, s string) bool { return false } -func containsIPs(ips []netaddr.IP, ip netaddr.IP) bool { - for _, v := range ips { - if v == ip { - return true - } - } - - return false -} - func tailNodesToString(nodes []*tailcfg.Node) string { temp := make([]string, len(nodes)) diff --git a/utils_test.go b/utils_test.go index feb44d5a..271013a1 100644 --- a/utils_test.go +++ b/utils_test.go @@ -20,7 +20,7 @@ func (s *Suite) TestGetUsedIps(c *check.C) { ips, err := app.getAvailableIPs() c.Assert(err, check.IsNil) - namespace, err := app.CreateNamespace("test_ip") + namespace, err := app.CreateNamespace("test-ip") c.Assert(err, check.IsNil) pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil) @@ -48,9 +48,12 @@ func (s *Suite) TestGetUsedIps(c *check.C) { c.Assert(err, check.IsNil) expected := netaddr.MustParseIP("10.27.0.1") + expectedIPSetBuilder := netaddr.IPSetBuilder{} + expectedIPSetBuilder.Add(expected) + expectedIPSet, _ := expectedIPSetBuilder.IPSet() - c.Assert(len(usedIps), check.Equals, 1) - c.Assert(usedIps[0], check.Equals, expected) + c.Assert(usedIps.Equal(expectedIPSet), check.Equals, true) + c.Assert(usedIps.Contains(expected), check.Equals, true) machine1, err := app.GetMachineByID(0) c.Assert(err, check.IsNil) @@ -64,6 +67,8 @@ func (s *Suite) TestGetMultiIp(c *check.C) { c.Assert(err, check.IsNil) for index := 1; index <= 350; index++ { + app.ipAllocationMutex.Lock() + ips, err := app.getAvailableIPs() c.Assert(err, check.IsNil) @@ -86,17 +91,30 @@ func (s *Suite) TestGetMultiIp(c *check.C) { IPAddresses: ips, } app.db.Save(&machine) + + app.ipAllocationMutex.Unlock() } usedIps, err := app.getUsedIPs() - c.Assert(err, check.IsNil) - c.Assert(len(usedIps), check.Equals, 350) + expected0 := netaddr.MustParseIP("10.27.0.1") + expected9 := netaddr.MustParseIP("10.27.0.10") + expected300 := netaddr.MustParseIP("10.27.0.45") - c.Assert(usedIps[0], check.Equals, netaddr.MustParseIP("10.27.0.1")) - c.Assert(usedIps[9], check.Equals, netaddr.MustParseIP("10.27.0.10")) - c.Assert(usedIps[300], check.Equals, netaddr.MustParseIP("10.27.1.45")) + notExpectedIPSetBuilder := netaddr.IPSetBuilder{} + notExpectedIPSetBuilder.Add(expected0) + notExpectedIPSetBuilder.Add(expected9) + notExpectedIPSetBuilder.Add(expected300) + notExpectedIPSet, err := notExpectedIPSetBuilder.IPSet() + c.Assert(err, check.IsNil) + + // We actually expect it to be a lot larger + c.Assert(usedIps.Equal(notExpectedIPSet), check.Equals, false) + + c.Assert(usedIps.Contains(expected0), check.Equals, true) + c.Assert(usedIps.Contains(expected9), check.Equals, true) + c.Assert(usedIps.Contains(expected300), check.Equals, true) // Check that we can read back the IPs machine1, err := app.GetMachineByID(1) @@ -142,7 +160,7 @@ func (s *Suite) TestGetAvailableIpMachineWithoutIP(c *check.C) { c.Assert(len(ips), check.Equals, 1) c.Assert(ips[0].String(), check.Equals, expected.String()) - namespace, err := app.CreateNamespace("test_ip") + namespace, err := app.CreateNamespace("test-ip") c.Assert(err, check.IsNil) pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil)