mirror of
https://github.com/juanfont/headscale.git
synced 2024-11-26 08:53:05 +00:00
Merge branch 'main' into show-nodes-online
This commit is contained in:
commit
bfa9ed814d
9 changed files with 61 additions and 51 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -31,3 +31,5 @@ test_output/
|
||||||
# Nix build output
|
# Nix build output
|
||||||
result
|
result
|
||||||
.direnv/
|
.direnv/
|
||||||
|
|
||||||
|
integration_test/etc/config.dump.yaml
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
- Use new ACL syntax [#618](https://github.com/juanfont/headscale/pull/618)
|
- Use new ACL syntax [#618](https://github.com/juanfont/headscale/pull/618)
|
||||||
- Add -c option to specify config file from command line [#285](https://github.com/juanfont/headscale/issues/285) [#612](https://github.com/juanfont/headscale/pull/601)
|
- Add -c option to specify config file from command line [#285](https://github.com/juanfont/headscale/issues/285) [#612](https://github.com/juanfont/headscale/pull/601)
|
||||||
- Add configuration option to allow Tailscale clients to use a random WireGuard port. [kb/1181/firewalls](https://tailscale.com/kb/1181/firewalls) [#624](https://github.com/juanfont/headscale/pull/624)
|
- Add configuration option to allow Tailscale clients to use a random WireGuard port. [kb/1181/firewalls](https://tailscale.com/kb/1181/firewalls) [#624](https://github.com/juanfont/headscale/pull/624)
|
||||||
|
- Improve obtuse UX regarding missing configuration (`ephemeral_node_inactivity_timeout` not set) [#639](https://github.com/juanfont/headscale/pull/639)
|
||||||
- Fix nodes being shown as 'offline' in `tailscale status` [648](https://github.com/juanfont/headscale/pull/648)
|
- Fix nodes being shown as 'offline' in `tailscale status` [648](https://github.com/juanfont/headscale/pull/648)
|
||||||
|
|
||||||
## 0.15.0 (2022-03-20)
|
## 0.15.0 (2022-03-20)
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -1,5 +1,5 @@
|
||||||
# Calculate version
|
# Calculate version
|
||||||
version = $(git describe --always --tags --dirty)
|
version ?= $(shell git describe --always --tags --dirty)
|
||||||
|
|
||||||
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
|
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
|
||||||
|
|
||||||
|
|
32
README.md
32
README.md
|
@ -195,6 +195,15 @@ make build
|
||||||
<sub style="font-size:14px"><b>Nico</b></sub>
|
<sub style="font-size:14px"><b>Nico</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
|
<a href=https://github.com/huskyii>
|
||||||
|
<img src=https://avatars.githubusercontent.com/u/5499746?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Jiang Zhu/>
|
||||||
|
<br />
|
||||||
|
<sub style="font-size:14px"><b>Jiang Zhu</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/e-zk>
|
<a href=https://github.com/e-zk>
|
||||||
<img src=https://avatars.githubusercontent.com/u/58356365?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=e-zk/>
|
<img src=https://avatars.githubusercontent.com/u/58356365?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=e-zk/>
|
||||||
|
@ -202,8 +211,6 @@ make build
|
||||||
<sub style="font-size:14px"><b>e-zk</b></sub>
|
<sub style="font-size:14px"><b>e-zk</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/arch4ngel>
|
<a href=https://github.com/arch4ngel>
|
||||||
<img src=https://avatars.githubusercontent.com/u/11574161?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Justin Angel/>
|
<img src=https://avatars.githubusercontent.com/u/11574161?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Justin Angel/>
|
||||||
|
@ -218,13 +225,6 @@ make build
|
||||||
<sub style="font-size:14px"><b>Alessandro (Ale) Segala</b></sub>
|
<sub style="font-size:14px"><b>Alessandro (Ale) Segala</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
|
||||||
<a href=https://github.com/huskyii>
|
|
||||||
<img src=https://avatars.githubusercontent.com/u/5499746?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Jiang Zhu/>
|
|
||||||
<br />
|
|
||||||
<sub style="font-size:14px"><b>Jiang Zhu</b></sub>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/unreality>
|
<a href=https://github.com/unreality>
|
||||||
<img src=https://avatars.githubusercontent.com/u/352522?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=unreality/>
|
<img src=https://avatars.githubusercontent.com/u/352522?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=unreality/>
|
||||||
|
@ -292,6 +292,13 @@ make build
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
|
<a href=https://github.com/iSchluff>
|
||||||
|
<img src=https://avatars.githubusercontent.com/u/1429641?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Anton Schubert/>
|
||||||
|
<br />
|
||||||
|
<sub style="font-size:14px"><b>Anton Schubert</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/deonthomasgy>
|
<a href=https://github.com/deonthomasgy>
|
||||||
<img src=https://avatars.githubusercontent.com/u/150036?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Deon Thomas/>
|
<img src=https://avatars.githubusercontent.com/u/150036?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Deon Thomas/>
|
||||||
|
@ -327,13 +334,6 @@ make build
|
||||||
<sub style="font-size:14px"><b>Stefan Majer</b></sub>
|
<sub style="font-size:14px"><b>Stefan Majer</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
|
||||||
<a href=https://github.com/iSchluff>
|
|
||||||
<img src=https://avatars.githubusercontent.com/u/1429641?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Anton Schubert/>
|
|
||||||
<br />
|
|
||||||
<sub style="font-size:14px"><b>Anton Schubert</b></sub>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
|
|
|
@ -7,12 +7,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/juanfont/headscale"
|
"github.com/juanfont/headscale"
|
||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/viper"
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
@ -29,21 +27,6 @@ func getHeadscaleApp() (*headscale.Headscale, error) {
|
||||||
return nil, fmt.Errorf("failed to load configuration while creating headscale instance: %w", err)
|
return nil, fmt.Errorf("failed to load configuration while creating headscale instance: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Minimum inactivity time out is keepalive timeout (60s) plus a few seconds
|
|
||||||
// to avoid races
|
|
||||||
minInactivityTimeout, _ := time.ParseDuration("65s")
|
|
||||||
if viper.GetDuration("ephemeral_node_inactivity_timeout") <= minInactivityTimeout {
|
|
||||||
// TODO: Find a better way to return this text
|
|
||||||
//nolint
|
|
||||||
err := fmt.Errorf(
|
|
||||||
"ephemeral_node_inactivity_timeout (%s) is set too low, must be more than %s",
|
|
||||||
viper.GetString("ephemeral_node_inactivity_timeout"),
|
|
||||||
minInactivityTimeout,
|
|
||||||
)
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
app, err := headscale.NewHeadscale(cfg)
|
app, err := headscale.NewHeadscale(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
15
config.go
15
config.go
|
@ -160,7 +160,11 @@ func LoadConfig(path string, isFile bool) error {
|
||||||
viper.SetDefault("logtail.enabled", false)
|
viper.SetDefault("logtail.enabled", false)
|
||||||
viper.SetDefault("randomize_client_port", false)
|
viper.SetDefault("randomize_client_port", false)
|
||||||
|
|
||||||
|
viper.SetDefault("ephemeral_node_inactivity_timeout", "120s")
|
||||||
|
|
||||||
if err := viper.ReadInConfig(); err != nil {
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
|
log.Warn().Err(err).Msg("Failed to read configuration from disk")
|
||||||
|
|
||||||
return fmt.Errorf("fatal error reading config file: %w", err)
|
return fmt.Errorf("fatal error reading config file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,6 +206,17 @@ func LoadConfig(path string, isFile bool) error {
|
||||||
EnforcedClientAuth)
|
EnforcedClientAuth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Minimum inactivity time out is keepalive timeout (60s) plus a few seconds
|
||||||
|
// to avoid races
|
||||||
|
minInactivityTimeout, _ := time.ParseDuration("65s")
|
||||||
|
if viper.GetDuration("ephemeral_node_inactivity_timeout") <= minInactivityTimeout {
|
||||||
|
errorText += fmt.Sprintf(
|
||||||
|
"Fatal config error: ephemeral_node_inactivity_timeout (%s) is set too low, must be more than %s",
|
||||||
|
viper.GetString("ephemeral_node_inactivity_timeout"),
|
||||||
|
minInactivityTimeout,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if errorText != "" {
|
if errorText != "" {
|
||||||
//nolint
|
//nolint
|
||||||
return errors.New(strings.TrimSuffix(errorText, "\n"))
|
return errors.New(strings.TrimSuffix(errorText, "\n"))
|
||||||
|
|
11
derp.go
11
derp.go
|
@ -152,16 +152,7 @@ func (h *Headscale) scheduledDERPMapUpdateWorker(cancelChan <-chan struct{}) {
|
||||||
h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region
|
h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region
|
||||||
}
|
}
|
||||||
|
|
||||||
namespaces, err := h.ListNamespaces()
|
h.setLastStateChangeToNow()
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to fetch namespaces")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, namespace := range namespaces {
|
|
||||||
h.setLastStateChangeToNow(namespace.Name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
utils.go
14
utils.go
|
@ -325,11 +325,17 @@ func GenerateRandomStringURLSafe(n int) (string, error) {
|
||||||
// number generator fails to function correctly, in which
|
// number generator fails to function correctly, in which
|
||||||
// case the caller should not continue.
|
// case the caller should not continue.
|
||||||
func GenerateRandomStringDNSSafe(n int) (string, error) {
|
func GenerateRandomStringDNSSafe(n int) (string, error) {
|
||||||
str, err := GenerateRandomStringURLSafe(n)
|
var str string
|
||||||
|
var err error
|
||||||
|
for len(str) < n {
|
||||||
|
str, err = GenerateRandomStringURLSafe(n)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
str = strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(str, "_", ""), "-", ""))
|
||||||
|
}
|
||||||
|
|
||||||
str = strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(str, "_", ""), "-", ""))
|
return str[:n], nil
|
||||||
|
|
||||||
return str[:n], err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsStringInSlice(slice []string, str string) bool {
|
func IsStringInSlice(slice []string, str string) bool {
|
||||||
|
|
|
@ -34,7 +34,7 @@ func (s *Suite) TestGetUsedIps(c *check.C) {
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testmachine",
|
||||||
NamespaceID: namespace.ID,
|
NamespaceID: namespace.ID,
|
||||||
RegisterMethod: RegisterMethodAuthKey,
|
RegisterMethod: RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
|
@ -82,7 +82,7 @@ func (s *Suite) TestGetMultiIp(c *check.C) {
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testmachine",
|
||||||
NamespaceID: namespace.ID,
|
NamespaceID: namespace.ID,
|
||||||
RegisterMethod: RegisterMethodAuthKey,
|
RegisterMethod: RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
|
@ -172,7 +172,7 @@ func (s *Suite) TestGetAvailableIpMachineWithoutIP(c *check.C) {
|
||||||
MachineKey: "foo",
|
MachineKey: "foo",
|
||||||
NodeKey: "bar",
|
NodeKey: "bar",
|
||||||
DiscoKey: "faa",
|
DiscoKey: "faa",
|
||||||
Hostname: "testmachine",
|
Hostname: "testmachine",
|
||||||
NamespaceID: namespace.ID,
|
NamespaceID: namespace.ID,
|
||||||
RegisterMethod: RegisterMethodAuthKey,
|
RegisterMethod: RegisterMethodAuthKey,
|
||||||
AuthKeyID: uint(pak.ID),
|
AuthKeyID: uint(pak.ID),
|
||||||
|
@ -185,3 +185,15 @@ func (s *Suite) TestGetAvailableIpMachineWithoutIP(c *check.C) {
|
||||||
c.Assert(len(ips2), check.Equals, 1)
|
c.Assert(len(ips2), check.Equals, 1)
|
||||||
c.Assert(ips2[0].String(), check.Equals, expected.String())
|
c.Assert(ips2[0].String(), check.Equals, expected.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Suite) TestGenerateRandomStringDNSSafe(c *check.C) {
|
||||||
|
for i := 0; i < 100000; i++ {
|
||||||
|
str, err := GenerateRandomStringDNSSafe(8)
|
||||||
|
if err != nil {
|
||||||
|
c.Error(err)
|
||||||
|
}
|
||||||
|
if len(str) != 8 {
|
||||||
|
c.Error("invalid length", len(str), str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue