From 911c5bddce34b3474e4915fab5e1ed43fbe33978 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 27 Jun 2022 11:56:37 +0000 Subject: [PATCH 01/33] Make saving logs from tests an option (default false) We currently have a bit of flaky logic which prevents the docker plugin from cleaning up the containers if the tests or setup fatals or crashes, this is due to a limitation in the save / passed stats handling. This change makes it an environment variable which by default ditches the logs and makes the containers clean up "correctly" in the teardown method. --- integration_common_test.go | 31 ++++++++++++++++- integration_embedded_derp_test.go | 58 ++++++++++++++++++++++--------- integration_test.go | 56 +++++++++++++++++++++-------- 3 files changed, 113 insertions(+), 32 deletions(-) diff --git a/integration_common_test.go b/integration_common_test.go index f1c4e868..4ee2d3b3 100644 --- a/integration_common_test.go +++ b/integration_common_test.go @@ -6,7 +6,10 @@ package headscale import ( "bytes" "encoding/json" + "errors" "fmt" + "os" + "strconv" "strings" "time" @@ -16,9 +19,13 @@ import ( "inet.af/netaddr" ) -const DOCKER_EXECUTE_TIMEOUT = 10 * time.Second +const ( + DOCKER_EXECUTE_TIMEOUT = 10 * time.Second +) var ( + errEnvVarEmpty = errors.New("getenv: environment variable empty") + IpPrefix4 = netaddr.MustParseIPPrefix("100.64.0.0/10") IpPrefix6 = netaddr.MustParseIPPrefix("fd7a:115c:a1e0::/48") @@ -283,3 +290,25 @@ func getMagicFQDN( return hostnames, nil } + +func GetEnvStr(key string) (string, error) { + v := os.Getenv(key) + if v == "" { + return v, errEnvVarEmpty + } + + return v, nil +} + +func GetEnvBool(key string) (bool, error) { + s, err := GetEnvStr(key) + if err != nil { + return false, err + } + v, err := strconv.ParseBool(s) + if err != nil { + return false, err + } + + return v, nil +} diff --git a/integration_embedded_derp_test.go b/integration_embedded_derp_test.go index 5f388694..d8918f4e 100644 --- a/integration_embedded_derp_test.go +++ b/integration_embedded_derp_test.go @@ -40,41 +40,50 @@ type IntegrationDERPTestSuite struct { pool dockertest.Pool networks map[int]dockertest.Network // so we keep the containers isolated headscale dockertest.Resource + saveLogs bool tailscales map[string]dockertest.Resource joinWaitGroup sync.WaitGroup } func TestDERPIntegrationTestSuite(t *testing.T) { + saveLogs, err := GetEnvBool("HEADSCALE_INTEGRATION_SAVE_LOG") + if err != nil { + saveLogs = false + } + s := new(IntegrationDERPTestSuite) s.tailscales = make(map[string]dockertest.Resource) s.networks = make(map[int]dockertest.Network) + s.saveLogs = saveLogs suite.Run(t, s) // HandleStats, which allows us to check if we passed and save logs // is called after TearDown, so we cannot tear down containers before // we have potentially saved the logs. - for _, tailscale := range s.tailscales { - if err := s.pool.Purge(&tailscale); err != nil { + if s.saveLogs { + for _, tailscale := range s.tailscales { + if err := s.pool.Purge(&tailscale); err != nil { + log.Printf("Could not purge resource: %s\n", err) + } + } + + if !s.stats.Passed() { + err := s.saveLog(&s.headscale, "test_output") + if err != nil { + log.Printf("Could not save log: %s\n", err) + } + } + if err := s.pool.Purge(&s.headscale); err != nil { log.Printf("Could not purge resource: %s\n", err) } - } - if !s.stats.Passed() { - err := s.saveLog(&s.headscale, "test_output") - if err != nil { - log.Printf("Could not save log: %s\n", err) - } - } - if err := s.pool.Purge(&s.headscale); err != nil { - log.Printf("Could not purge resource: %s\n", err) - } - - for _, network := range s.networks { - if err := network.Close(); err != nil { - log.Printf("Could not close network: %s\n", err) + for _, network := range s.networks { + if err := network.Close(); err != nil { + log.Printf("Could not close network: %s\n", err) + } } } } @@ -290,6 +299,23 @@ func (s *IntegrationDERPTestSuite) tailscaleContainer( } func (s *IntegrationDERPTestSuite) TearDownSuite() { + if !s.saveLogs { + for _, tailscale := range s.tailscales { + if err := s.pool.Purge(&tailscale); err != nil { + log.Printf("Could not purge resource: %s\n", err) + } + } + + if err := s.pool.Purge(&s.headscale); err != nil { + log.Printf("Could not purge resource: %s\n", err) + } + + for _, network := range s.networks { + if err := network.Close(); err != nil { + log.Printf("Could not close network: %s\n", err) + } + } + } } func (s *IntegrationDERPTestSuite) HandleStats( diff --git a/integration_test.go b/integration_test.go index 18f28b28..22cc0ae5 100644 --- a/integration_test.go +++ b/integration_test.go @@ -36,6 +36,7 @@ type IntegrationTestSuite struct { pool dockertest.Pool network dockertest.Network headscale dockertest.Resource + saveLogs bool namespaces map[string]TestNamespace @@ -43,6 +44,11 @@ type IntegrationTestSuite struct { } func TestIntegrationTestSuite(t *testing.T) { + saveLogs, err := GetEnvBool("HEADSCALE_INTEGRATION_SAVE_LOG") + if err != nil { + saveLogs = false + } + s := new(IntegrationTestSuite) s.namespaces = map[string]TestNamespace{ @@ -55,32 +61,35 @@ func TestIntegrationTestSuite(t *testing.T) { tailscales: make(map[string]dockertest.Resource), }, } + s.saveLogs = saveLogs suite.Run(t, s) // HandleStats, which allows us to check if we passed and save logs // is called after TearDown, so we cannot tear down containers before // we have potentially saved the logs. - for _, scales := range s.namespaces { - for _, tailscale := range scales.tailscales { - if err := s.pool.Purge(&tailscale); err != nil { - log.Printf("Could not purge resource: %s\n", err) + if s.saveLogs { + for _, scales := range s.namespaces { + for _, tailscale := range scales.tailscales { + if err := s.pool.Purge(&tailscale); err != nil { + log.Printf("Could not purge resource: %s\n", err) + } } } - } - if !s.stats.Passed() { - err := s.saveLog(&s.headscale, "test_output") - if err != nil { - log.Printf("Could not save log: %s\n", err) + if !s.stats.Passed() { + err := s.saveLog(&s.headscale, "test_output") + if err != nil { + log.Printf("Could not save log: %s\n", err) + } + } + if err := s.pool.Purge(&s.headscale); err != nil { + log.Printf("Could not purge resource: %s\n", err) } - } - if err := s.pool.Purge(&s.headscale); err != nil { - log.Printf("Could not purge resource: %s\n", err) - } - if err := s.network.Close(); err != nil { - log.Printf("Could not close network: %s\n", err) + if err := s.network.Close(); err != nil { + log.Printf("Could not close network: %s\n", err) + } } } @@ -338,6 +347,23 @@ func (s *IntegrationTestSuite) SetupSuite() { } func (s *IntegrationTestSuite) TearDownSuite() { + if !s.saveLogs { + for _, scales := range s.namespaces { + for _, tailscale := range scales.tailscales { + if err := s.pool.Purge(&tailscale); err != nil { + log.Printf("Could not purge resource: %s\n", err) + } + } + } + + if err := s.pool.Purge(&s.headscale); err != nil { + log.Printf("Could not purge resource: %s\n", err) + } + + if err := s.network.Close(); err != nil { + log.Printf("Could not close network: %s\n", err) + } + } } func (s *IntegrationTestSuite) HandleStats( From 8cae4f80d79a5baeccd2f41e4d09c1faa17b6f18 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 27 Jun 2022 11:58:16 +0000 Subject: [PATCH 02/33] Fail tests instead of fatal Currently we exit the program if the setup does not work, this can cause is to leave containers and other resources behind since we dont run TearDown. This change will just fail the test if we cant set up, which should mean that the TearDown runs aswell. --- integration_embedded_derp_test.go | 8 ++++---- integration_test.go | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/integration_embedded_derp_test.go b/integration_embedded_derp_test.go index d8918f4e..03501395 100644 --- a/integration_embedded_derp_test.go +++ b/integration_embedded_derp_test.go @@ -92,14 +92,14 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { if ppool, err := dockertest.NewPool(""); err == nil { s.pool = *ppool } else { - log.Fatalf("Could not connect to docker: %s", err) + s.FailNow(fmt.Sprintf("Could not connect to docker: %s", err), "") } for i := 0; i < totalContainers; i++ { if pnetwork, err := s.pool.CreateNetwork(fmt.Sprintf("headscale-derp-%d", i)); err == nil { s.networks[i] = *pnetwork } else { - log.Fatalf("Could not create network: %s", err) + s.FailNow(fmt.Sprintf("Could not create network: %s", err), "") } } @@ -110,7 +110,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { currentPath, err := os.Getwd() if err != nil { - log.Fatalf("Could not determine current path: %s", err) + s.FailNow(fmt.Sprintf("Could not determine current path: %s", err), "") } headscaleOptions := &dockertest.RunOptions{ @@ -133,7 +133,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil { s.headscale = *pheadscale } else { - log.Fatalf("Could not start headscale container: %s", err) + s.FailNow(fmt.Sprintf("Could not start headscale container: %s", err), "") } log.Println("Created headscale container to test DERP") diff --git a/integration_test.go b/integration_test.go index 22cc0ae5..119fd4f7 100644 --- a/integration_test.go +++ b/integration_test.go @@ -218,13 +218,13 @@ func (s *IntegrationTestSuite) SetupSuite() { if ppool, err := dockertest.NewPool(""); err == nil { s.pool = *ppool } else { - log.Fatalf("Could not connect to docker: %s", err) + s.FailNow(fmt.Sprintf("Could not connect to docker: %s", err), "") } if pnetwork, err := s.pool.CreateNetwork("headscale-test"); err == nil { s.network = *pnetwork } else { - log.Fatalf("Could not create network: %s", err) + s.FailNow(fmt.Sprintf("Could not create network: %s", err), "") } headscaleBuildOptions := &dockertest.BuildOptions{ @@ -234,7 +234,7 @@ func (s *IntegrationTestSuite) SetupSuite() { currentPath, err := os.Getwd() if err != nil { - log.Fatalf("Could not determine current path: %s", err) + s.FailNow(fmt.Sprintf("Could not determine current path: %s", err), "") } headscaleOptions := &dockertest.RunOptions{ @@ -250,7 +250,7 @@ func (s *IntegrationTestSuite) SetupSuite() { if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil { s.headscale = *pheadscale } else { - log.Fatalf("Could not start headscale container: %s", err) + s.FailNow(fmt.Sprintf("Could not start headscale container: %s", err), "") } log.Println("Created headscale container") From 3777de7133ebf0cb55c6c1820df264a60544e403 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 27 Jun 2022 12:00:21 +0000 Subject: [PATCH 03/33] Use failnow for cli tests aswell --- integration_cli_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/integration_cli_test.go b/integration_cli_test.go index 8ac6ee4d..11daae9d 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -40,13 +40,13 @@ func (s *IntegrationCLITestSuite) SetupTest() { if ppool, err := dockertest.NewPool(""); err == nil { s.pool = *ppool } else { - log.Fatalf("Could not connect to docker: %s", err) + s.FailNow(fmt.Sprintf("Could not connect to docker: %s", err), "") } if pnetwork, err := s.pool.CreateNetwork("headscale-test"); err == nil { s.network = *pnetwork } else { - log.Fatalf("Could not create network: %s", err) + s.FailNow(fmt.Sprintf("Could not create network: %s", err), "") } headscaleBuildOptions := &dockertest.BuildOptions{ @@ -56,7 +56,7 @@ func (s *IntegrationCLITestSuite) SetupTest() { currentPath, err := os.Getwd() if err != nil { - log.Fatalf("Could not determine current path: %s", err) + s.FailNow(fmt.Sprintf("Could not determine current path: %s", err), "") } headscaleOptions := &dockertest.RunOptions{ @@ -72,7 +72,7 @@ func (s *IntegrationCLITestSuite) SetupTest() { if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil { s.headscale = *pheadscale } else { - log.Fatalf("Could not start headscale container: %s", err) + s.FailNow(fmt.Sprintf("Could not start headscale container: %s", err), "") } fmt.Println("Created headscale container") From 32a6151df95c38eb58ca53ea95609474f6b164ef Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 27 Jun 2022 12:02:29 +0000 Subject: [PATCH 04/33] Rerun integration tests 5 times if error --- .github/workflows/test-integration.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml index 2ac023ac..70b36b1c 100644 --- a/.github/workflows/test-integration.yml +++ b/.github/workflows/test-integration.yml @@ -27,4 +27,9 @@ jobs: - name: Run Integration tests if: steps.changed-files.outputs.any_changed == 'true' - run: nix develop --command -- make test_integration + uses: nick-fields/retry@v2 + with: + timeout_minutes: 240 + max_attempts: 5 + retry_on: error + command: nix develop --command -- make test_integration From 566b8c3df34575fbf2fbd0d340059905c87616b2 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 27 Jun 2022 12:07:30 +0000 Subject: [PATCH 05/33] Fix issue were dockertest fails to start because of container mismatch --- integration_cli_test.go | 5 +++++ integration_embedded_derp_test.go | 5 +++++ integration_test.go | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/integration_cli_test.go b/integration_cli_test.go index 11daae9d..f9ff5ec0 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -68,6 +68,11 @@ func (s *IntegrationCLITestSuite) SetupTest() { Cmd: []string{"headscale", "serve"}, } + err = s.pool.RemoveContainerByName(headscaleHostname) + if err != nil { + s.FailNow(fmt.Sprintf("Could not remove existing container before building test: %s", err), "") + } + fmt.Println("Creating headscale container") if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil { s.headscale = *pheadscale diff --git a/integration_embedded_derp_test.go b/integration_embedded_derp_test.go index 03501395..ecca8ba5 100644 --- a/integration_embedded_derp_test.go +++ b/integration_embedded_derp_test.go @@ -129,6 +129,11 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { }, } + err = s.pool.RemoveContainerByName(headscaleHostname) + if err != nil { + s.FailNow(fmt.Sprintf("Could not remove existing container before building test: %s", err), "") + } + log.Println("Creating headscale container") if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil { s.headscale = *pheadscale diff --git a/integration_test.go b/integration_test.go index 119fd4f7..2214b893 100644 --- a/integration_test.go +++ b/integration_test.go @@ -246,6 +246,11 @@ func (s *IntegrationTestSuite) SetupSuite() { Cmd: []string{"headscale", "serve"}, } + err = s.pool.RemoveContainerByName(headscaleHostname) + if err != nil { + s.FailNow(fmt.Sprintf("Could not remove existing container before building test: %s", err), "") + } + log.Println("Creating headscale container") if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil { s.headscale = *pheadscale From cf3fc85196e13e52db055dbc594d437dcc9765ac Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Tue, 12 Jul 2022 12:27:28 +0200 Subject: [PATCH 06/33] Make tailnet updates check configurable --- config-example.yaml | 6 ++++++ config.go | 16 ++++++++++++++++ poll.go | 5 ++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/config-example.yaml b/config-example.yaml index 9740f3ad..c32f9416 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -103,6 +103,12 @@ disable_check_updates: false # Time before an inactive ephemeral node is deleted? ephemeral_node_inactivity_timeout: 30m +# Period to check for changes in the tailnet. A value too low will severily affect +# CPU consumption of Headscale. A value too high (over 60s) will cause problems +# to the nodes, as they won't get updates or keep alive messages on time. +# In case of doubts, do not touch the default 10s. +changes_check_interval: 10s + # SQLite config db_type: sqlite3 db_path: /var/lib/headscale/db.sqlite diff --git a/config.go b/config.go index 9e71a750..0ef09110 100644 --- a/config.go +++ b/config.go @@ -26,6 +26,7 @@ type Config struct { GRPCAddr string GRPCAllowInsecure bool EphemeralNodeInactivityTimeout time.Duration + ChangesCheckInterval time.Duration IPPrefixes []netaddr.IPPrefix PrivateKeyPath string BaseDomain string @@ -162,6 +163,8 @@ func LoadConfig(path string, isFile bool) error { viper.SetDefault("ephemeral_node_inactivity_timeout", "120s") + viper.SetDefault("changes_check_interval", "10s") + if err := viper.ReadInConfig(); err != nil { log.Warn().Err(err).Msg("Failed to read configuration from disk") @@ -217,6 +220,15 @@ func LoadConfig(path string, isFile bool) error { ) } + maxChangesCheckInterval, _ := time.ParseDuration("60s") + if viper.GetDuration("changes_check_interval") > maxChangesCheckInterval { + errorText += fmt.Sprintf( + "Fatal config error: changes_check_interval (%s) is set too high, must be less than %s", + viper.GetString("changes_check_interval"), + maxChangesCheckInterval, + ) + } + if errorText != "" { //nolint return errors.New(strings.TrimSuffix(errorText, "\n")) @@ -478,6 +490,10 @@ func GetHeadscaleConfig() (*Config, error) { "ephemeral_node_inactivity_timeout", ), + ChangesCheckInterval: viper.GetDuration( + "changes_check_interval", + ), + DBtype: viper.GetString("db_type"), DBpath: AbsolutePathFromConfigPath(viper.GetString("db_path")), DBhost: viper.GetString("db_host"), diff --git a/poll.go b/poll.go index 9218495d..95fb542c 100644 --- a/poll.go +++ b/poll.go @@ -16,8 +16,7 @@ import ( ) const ( - keepAliveInterval = 60 * time.Second - updateCheckInterval = 10 * time.Second + keepAliveInterval = 60 * time.Second ) type contextKey string @@ -640,7 +639,7 @@ func (h *Headscale) scheduledPollWorker( machine *Machine, ) { keepAliveTicker := time.NewTicker(keepAliveInterval) - updateCheckerTicker := time.NewTicker(updateCheckInterval) + updateCheckerTicker := time.NewTicker(h.cfg.ChangesCheckInterval) defer closeChanWithLog( updateChan, From 8e0939f403147f7cb5c3f294e0df6ea6f76d1688 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Tue, 12 Jul 2022 12:33:42 +0200 Subject: [PATCH 07/33] Updated changelog --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e916056..23064ac1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,11 +30,10 @@ - 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) - 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) - Improve shutdown behaviour [#651](https://github.com/juanfont/headscale/pull/651) - Drop Gin as web framework in Headscale [648](https://github.com/juanfont/headscale/pull/648) - +- Make tailnet updates check interval configurable [#675](https://github.com/juanfont/headscale/pull/675) ## 0.15.0 (2022-03-20) From 5b5298b0255098a0653da985f3b412fc133cbb40 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Tue, 12 Jul 2022 12:52:03 +0200 Subject: [PATCH 08/33] Renamed config param for node update check internal --- CHANGELOG.md | 2 +- config-example.yaml | 6 +++--- config.go | 18 +++++++++--------- poll.go | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23064ac1..1c63ae49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ - Fix nodes being shown as 'offline' in `tailscale status` [#648](https://github.com/juanfont/headscale/pull/648) - Improve shutdown behaviour [#651](https://github.com/juanfont/headscale/pull/651) - Drop Gin as web framework in Headscale [648](https://github.com/juanfont/headscale/pull/648) -- Make tailnet updates check interval configurable [#675](https://github.com/juanfont/headscale/pull/675) +- Make tailnet node updates check interval configurable [#675](https://github.com/juanfont/headscale/pull/675) ## 0.15.0 (2022-03-20) diff --git a/config-example.yaml b/config-example.yaml index c32f9416..d3d155e2 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -103,11 +103,11 @@ disable_check_updates: false # Time before an inactive ephemeral node is deleted? ephemeral_node_inactivity_timeout: 30m -# Period to check for changes in the tailnet. A value too low will severily affect +# Period to check for node updates in the tailnet. A value too low will severily affect # CPU consumption of Headscale. A value too high (over 60s) will cause problems -# to the nodes, as they won't get updates or keep alive messages on time. +# to the nodes, as they won't get updates or keep alive messages in time. # In case of doubts, do not touch the default 10s. -changes_check_interval: 10s +node_update_check_interval: 10s # SQLite config db_type: sqlite3 diff --git a/config.go b/config.go index 0ef09110..6789f6f0 100644 --- a/config.go +++ b/config.go @@ -26,7 +26,7 @@ type Config struct { GRPCAddr string GRPCAllowInsecure bool EphemeralNodeInactivityTimeout time.Duration - ChangesCheckInterval time.Duration + NodeUpdateCheckInterval time.Duration IPPrefixes []netaddr.IPPrefix PrivateKeyPath string BaseDomain string @@ -163,7 +163,7 @@ func LoadConfig(path string, isFile bool) error { viper.SetDefault("ephemeral_node_inactivity_timeout", "120s") - viper.SetDefault("changes_check_interval", "10s") + viper.SetDefault("node_update_check_interval", "10s") if err := viper.ReadInConfig(); err != nil { log.Warn().Err(err).Msg("Failed to read configuration from disk") @@ -220,12 +220,12 @@ func LoadConfig(path string, isFile bool) error { ) } - maxChangesCheckInterval, _ := time.ParseDuration("60s") - if viper.GetDuration("changes_check_interval") > maxChangesCheckInterval { + maxNodeUpdateCheckInterval, _ := time.ParseDuration("60s") + if viper.GetDuration("node_update_check_interval") > maxNodeUpdateCheckInterval { errorText += fmt.Sprintf( - "Fatal config error: changes_check_interval (%s) is set too high, must be less than %s", - viper.GetString("changes_check_interval"), - maxChangesCheckInterval, + "Fatal config error: node_update_check_interval (%s) is set too high, must be less than %s", + viper.GetString("node_update_check_interval"), + maxNodeUpdateCheckInterval, ) } @@ -490,8 +490,8 @@ func GetHeadscaleConfig() (*Config, error) { "ephemeral_node_inactivity_timeout", ), - ChangesCheckInterval: viper.GetDuration( - "changes_check_interval", + NodeUpdateCheckInterval: viper.GetDuration( + "node_update_check_interval", ), DBtype: viper.GetString("db_type"), diff --git a/poll.go b/poll.go index 95fb542c..6628a179 100644 --- a/poll.go +++ b/poll.go @@ -639,7 +639,7 @@ func (h *Headscale) scheduledPollWorker( machine *Machine, ) { keepAliveTicker := time.NewTicker(keepAliveInterval) - updateCheckerTicker := time.NewTicker(h.cfg.ChangesCheckInterval) + updateCheckerTicker := time.NewTicker(h.cfg.NodeUpdateCheckInterval) defer closeChanWithLog( updateChan, From 4ccff8bf2891d36225983ad42d0b36f28b9b368a Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Tue, 12 Jul 2022 13:13:04 +0200 Subject: [PATCH 09/33] Added the new parameter to the integration test params --- integration_test/etc/alt-config.dump.gold.yaml | 1 + integration_test/etc/alt-config.yaml | 1 + integration_test/etc/config.dump.gold.yaml | 1 + integration_test/etc/config.yaml | 1 + integration_test/etc_embedded_derp/config.yaml | 1 + 5 files changed, 5 insertions(+) diff --git a/integration_test/etc/alt-config.dump.gold.yaml b/integration_test/etc/alt-config.dump.gold.yaml index a3d7adb0..e8934230 100644 --- a/integration_test/etc/alt-config.dump.gold.yaml +++ b/integration_test/etc/alt-config.dump.gold.yaml @@ -20,6 +20,7 @@ dns_config: nameservers: - 1.1.1.1 ephemeral_node_inactivity_timeout: 30m +node_update_check_interval: 10s grpc_allow_insecure: false grpc_listen_addr: :50443 ip_prefixes: diff --git a/integration_test/etc/alt-config.yaml b/integration_test/etc/alt-config.yaml index 8de9a828..fa1bfcb3 100644 --- a/integration_test/etc/alt-config.yaml +++ b/integration_test/etc/alt-config.yaml @@ -2,6 +2,7 @@ log_level: trace acl_policy_path: "" db_type: sqlite3 ephemeral_node_inactivity_timeout: 30m +node_update_check_interval: 10s ip_prefixes: - fd7a:115c:a1e0::/48 - 100.64.0.0/10 diff --git a/integration_test/etc/config.dump.gold.yaml b/integration_test/etc/config.dump.gold.yaml index 4d03d74e..17bb0ca0 100644 --- a/integration_test/etc/config.dump.gold.yaml +++ b/integration_test/etc/config.dump.gold.yaml @@ -20,6 +20,7 @@ dns_config: nameservers: - 1.1.1.1 ephemeral_node_inactivity_timeout: 30m +node_update_check_interval: 10s grpc_allow_insecure: false grpc_listen_addr: :50443 ip_prefixes: diff --git a/integration_test/etc/config.yaml b/integration_test/etc/config.yaml index f055b4ca..e6b34afa 100644 --- a/integration_test/etc/config.yaml +++ b/integration_test/etc/config.yaml @@ -2,6 +2,7 @@ log_level: trace acl_policy_path: "" db_type: sqlite3 ephemeral_node_inactivity_timeout: 30m +node_update_check_interval: 10s ip_prefixes: - fd7a:115c:a1e0::/48 - 100.64.0.0/10 diff --git a/integration_test/etc_embedded_derp/config.yaml b/integration_test/etc_embedded_derp/config.yaml index a8b57af5..e6ad3b00 100644 --- a/integration_test/etc_embedded_derp/config.yaml +++ b/integration_test/etc_embedded_derp/config.yaml @@ -2,6 +2,7 @@ log_level: trace acl_policy_path: "" db_type: sqlite3 ephemeral_node_inactivity_timeout: 30m +node_update_check_interval: 10s ip_prefixes: - fd7a:115c:a1e0::/48 - 100.64.0.0/10 From b8c3387892896e1bbc50b5db9deed5e30cb2216b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Jul 2022 11:35:28 +0000 Subject: [PATCH 10/33] docs(README): update contributors --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 262d5535..f00772e2 100644 --- a/README.md +++ b/README.md @@ -572,9 +572,9 @@ make build - ZiYuan/ + Ziyuan
- ZiYuan + Ziyuan Han
From c6aaa37f2d120490cb65de5071e269ac4b0a2c60 Mon Sep 17 00:00:00 2001 From: Anton Schubert Date: Wed, 6 Jul 2022 13:39:10 +0200 Subject: [PATCH 11/33] ping db in health check --- api.go | 38 ++++++++++++++++++++++++++++++++++++++ app.go | 14 +------------- db.go | 12 ++++++++++++ 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/api.go b/api.go index fc27e46b..ff0de0c4 100644 --- a/api.go +++ b/api.go @@ -30,6 +30,44 @@ const ( ) ) +func (h *Headscale) HealthHandler( + writer http.ResponseWriter, + req *http.Request, +) { + respond := func(err error) { + writer.Header().Set("Content-Type", "application/health+json; charset=utf-8") + + res := struct { + Status string `json:"status"` + }{ + Status: "pass", + } + + if err != nil { + writer.WriteHeader(http.StatusInternalServerError) + log.Error().Caller().Err(err).Msg("health check failed") + res.Status = "fail" + } + + buf, err := json.Marshal(res) + if err != nil { + log.Error().Caller().Err(err).Msg("marshal failed") + } + _, err = writer.Write(buf) + if err != nil { + log.Error().Caller().Err(err).Msg("write failed") + } + } + + if err := h.pingDB(); err != nil { + respond(err) + + return + } + + respond(nil) +} + // KeyHandler provides the Headscale pub key // Listens in /key. func (h *Headscale) KeyHandler( diff --git a/app.go b/app.go index e4e69105..f988048f 100644 --- a/app.go +++ b/app.go @@ -423,19 +423,7 @@ func (h *Headscale) createPrometheusRouter() *gin.Engine { func (h *Headscale) createRouter(grpcMux *runtime.ServeMux) *mux.Router { router := mux.NewRouter() - router.HandleFunc( - "/health", - func(writer http.ResponseWriter, req *http.Request) { - writer.WriteHeader(http.StatusOK) - _, err := writer.Write([]byte("{\"healthy\": \"ok\"}")) - if err != nil { - log.Error(). - Caller(). - Err(err). - Msg("Failed to write response") - } - }).Methods(http.MethodGet) - + router.HandleFunc("/health", h.HealthHandler).Methods(http.MethodGet) router.HandleFunc("/key", h.KeyHandler).Methods(http.MethodGet) router.HandleFunc("/register", h.RegisterWebAPI).Methods(http.MethodGet) router.HandleFunc("/machine/{mkey}/map", h.PollNetMapHandler).Methods(http.MethodPost) diff --git a/db.go b/db.go index e412468d..5df9c23b 100644 --- a/db.go +++ b/db.go @@ -1,6 +1,7 @@ package headscale import ( + "context" "database/sql/driver" "encoding/json" "errors" @@ -220,6 +221,17 @@ func (h *Headscale) setValue(key string, value string) error { return nil } +func (h *Headscale) pingDB() error { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + db, err := h.db.DB() + if err != nil { + return err + } + + return db.PingContext(ctx) +} + // This is a "wrapper" type around tailscales // Hostinfo to allow us to add database "serialization" // methods. This allows us to use a typed values throughout From aca5646032da4bd3bfe163766926ce170c48815e Mon Sep 17 00:00:00 2001 From: Jiang Zhu Date: Sat, 16 Jul 2022 02:03:46 +0800 Subject: [PATCH 12/33] remove gin completely, ~2MB reduction on final binary --- app.go | 17 ++++------------- go.mod | 11 ----------- go.sum | 23 ----------------------- 3 files changed, 4 insertions(+), 47 deletions(-) diff --git a/app.go b/app.go index e4e69105..11c8d685 100644 --- a/app.go +++ b/app.go @@ -17,17 +17,16 @@ import ( "time" "github.com/coreos/go-oidc/v3/oidc" - "github.com/gin-gonic/gin" "github.com/gorilla/mux" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/patrickmn/go-cache" zerolog "github.com/philip-bui/grpc-zerolog" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/puzpuzpuz/xsync" zl "github.com/rs/zerolog" "github.com/rs/zerolog/log" - ginprometheus "github.com/zsais/go-gin-prometheus" "golang.org/x/crypto/acme" "golang.org/x/crypto/acme/autocert" "golang.org/x/oauth2" @@ -411,15 +410,6 @@ func (h *Headscale) ensureUnixSocketIsAbsent() error { return os.Remove(h.cfg.UnixSocket) } -func (h *Headscale) createPrometheusRouter() *gin.Engine { - promRouter := gin.Default() - - prometheus := ginprometheus.NewPrometheus("gin") - prometheus.Use(promRouter) - - return promRouter -} - func (h *Headscale) createRouter(grpcMux *runtime.ServeMux) *mux.Router { router := mux.NewRouter() @@ -647,11 +637,12 @@ func (h *Headscale) Serve() error { log.Info(). Msgf("listening and serving HTTP on: %s", h.cfg.Addr) - promRouter := h.createPrometheusRouter() + promMux := http.NewServeMux() + promMux.Handle("/metrics", promhttp.Handler()) promHTTPServer := &http.Server{ Addr: h.cfg.MetricsAddr, - Handler: promRouter, + Handler: promMux, ReadTimeout: HTTPReadTimeout, WriteTimeout: 0, } diff --git a/go.mod b/go.mod index e10ae35e..80a3e488 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/coreos/go-oidc/v3 v3.1.0 github.com/deckarep/golang-set/v2 v2.1.0 github.com/efekarakus/termcolor v1.0.1 - github.com/gin-gonic/gin v1.7.7 github.com/glebarez/sqlite v1.4.3 github.com/gofrs/uuid v4.2.0+incompatible github.com/gorilla/mux v1.8.0 @@ -28,7 +27,6 @@ require ( github.com/stretchr/testify v1.7.1 github.com/tailscale/hujson v0.0.0-20220506202205-92b4b88a9e17 github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e - github.com/zsais/go-gin-prometheus v0.1.0 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 @@ -61,11 +59,7 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect github.com/glebarez/go-sqlite v1.16.0 // indirect - github.com/go-playground/locales v0.13.0 // indirect - github.com/go-playground/universal-translator v0.17.0 // indirect - github.com/go-playground/validator/v10 v10.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.8 // indirect @@ -90,11 +84,9 @@ require ( github.com/jinzhu/now v1.1.4 // indirect github.com/josharian/native v1.0.0 // indirect github.com/jsimonetti/rtnetlink v1.1.2-0.20220408201609-d380b505068b // indirect - github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/kr/text v0.2.0 // indirect - github.com/leodido/go-urn v1.2.0 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect @@ -106,8 +98,6 @@ require ( github.com/mitchellh/go-ps v1.0.0 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 // indirect github.com/opencontainers/runc v1.0.2 // indirect @@ -126,7 +116,6 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.2.0 // indirect - github.com/ugorji/go/codec v1.1.7 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect diff --git a/go.sum b/go.sum index b4d03b90..3290d9cd 100644 --- a/go.sum +++ b/go.sum @@ -236,10 +236,6 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5 github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= -github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/glebarez/go-sqlite v1.16.0 h1:h28rHued+hGof3fNLksBcLwz/a71fiGZ/eIJHK0SsLI= github.com/glebarez/go-sqlite v1.16.0/go.mod h1:i8/JtqoqzBAFkrUTxbQFkQ05odCOds3j7NlDaXjqiPY= github.com/glebarez/sqlite v1.4.3 h1:ZABNo+2YIau8F8sZ7Qh/1h/ZnlSUMHFGD4zJKPval7A= @@ -256,14 +252,6 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -546,10 +534,8 @@ github.com/jsimonetti/rtnetlink v1.1.2-0.20220408201609-d380b505068b h1:Yws7RV6k github.com/jsimonetti/rtnetlink v1.1.2-0.20220408201609-d380b505068b/go.mod h1:TzDCVOZKUa79z6iXbbXqhtAflVgUKaFkZ21M5tK5tzY= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -595,8 +581,6 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= github.com/ldez/gomoddirectives v0.2.2/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= github.com/ldez/tagliatelle v0.2.0/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -686,11 +670,9 @@ github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2J github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= @@ -925,10 +907,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1 github.com/tomarrell/wrapcheck/v2 v2.4.0/go.mod h1:68bQ/eJg55BROaRTbMjC7vuhL2OgfoG8bLp9ZyoBfyY= github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= github.com/tommy-muehle/go-mnd/v2 v2.4.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -962,8 +941,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -github.com/zsais/go-gin-prometheus v0.1.0 h1:bkLv1XCdzqVgQ36ScgRi09MA2UC1t3tAB6nsfErsGO4= -github.com/zsais/go-gin-prometheus v0.1.0/go.mod h1:Slirjzuz8uM8Cw0jmPNqbneoqcUtY2GGjn2bEd4NRLY= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k= From 091b05f15505f4b1032eadc1e01f6c1c8a2d6462 Mon Sep 17 00:00:00 2001 From: ohdearaugustin Date: Wed, 6 Jul 2022 21:23:01 +0200 Subject: [PATCH 13/33] Change build os --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index b9139f09..ad021858 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Builder image -FROM docker.io/golang:1.18.0-bullseye AS build +FROM --platform=$BUILDPLATFORM docker.io/golang:1.18.0-bullseye AS build ARG VERSION=dev ENV GOPATH /go WORKDIR /go/src/headscale @@ -8,8 +8,8 @@ COPY go.mod go.sum /go/src/headscale/ RUN go mod download COPY . . - -RUN CGO_ENABLED=0 GOOS=linux go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale +ARG TARGETOS TARGETARCH +RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale RUN strip /go/bin/headscale RUN test -e /go/bin/headscale From 34d261179eeb56bd7bb8f0435956ccb14f4238bc Mon Sep 17 00:00:00 2001 From: ohdearaugustin Date: Wed, 6 Jul 2022 23:29:34 +0200 Subject: [PATCH 14/33] Speedup docker container build --- Dockerfile | 3 +-- Dockerfile.alpine | 6 +++--- Dockerfile.debug | 3 ++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index ad021858..33aa5780 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,8 +9,7 @@ RUN go mod download COPY . . ARG TARGETOS TARGETARCH -RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale -RUN strip /go/bin/headscale +RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /go/bin/headscale -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale RUN test -e /go/bin/headscale # Production image diff --git a/Dockerfile.alpine b/Dockerfile.alpine index de683f2d..b8d9e33a 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # Builder image -FROM docker.io/golang:1.18.0-alpine AS build +FROM --platform=$BUILDPLATFORM docker.io/golang:1.18.0-alpine AS build ARG VERSION=dev ENV GOPATH /go WORKDIR /go/src/headscale @@ -10,8 +10,8 @@ RUN go mod download COPY . . -RUN CGO_ENABLED=0 GOOS=linux go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale -RUN strip /go/bin/headscale +ARG TARGETOS TARGETARCH +RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /go/bin/headscale -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale RUN test -e /go/bin/headscale # Production image diff --git a/Dockerfile.debug b/Dockerfile.debug index 9b1b7c6b..4333e94d 100644 --- a/Dockerfile.debug +++ b/Dockerfile.debug @@ -1,5 +1,5 @@ # Builder image -FROM docker.io/golang:1.18.0-bullseye AS build +FROM --platform=$BUILDPLATFORM docker.io/golang:1.18.0-bullseye AS build ARG VERSION=dev ENV GOPATH /go WORKDIR /go/src/headscale @@ -9,6 +9,7 @@ RUN go mod download COPY . . +ARG TARGETOS TARGETARCH RUN CGO_ENABLED=0 GOOS=linux go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale RUN test -e /go/bin/headscale From 96221cc4f7d980a472281445deae27c0c7aeca55 Mon Sep 17 00:00:00 2001 From: ohdearaugustin Date: Sun, 17 Jul 2022 21:15:35 +0200 Subject: [PATCH 15/33] docs: add bulding container docs --- docs/build-headscale-container.md | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/build-headscale-container.md diff --git a/docs/build-headscale-container.md b/docs/build-headscale-container.md new file mode 100644 index 00000000..b0220167 --- /dev/null +++ b/docs/build-headscale-container.md @@ -0,0 +1,32 @@ +# Build docker from scratch + +The Dockerfiles included in the repository are using the [buildx plugin](https://docs.docker.com/buildx/working-with-buildx/). This plugin is includes in docker newer than Docker-ce CLI 19.03.2. The plugin is used to be able to build different container arches. Building the Dockerfiles without buildx is not possible. + +# Build native + +To build the container on the native arch you can just use: +``` +$ sudo docker buildx build -t headscale:custom-arch . +``` + +For example: This will build a amd64(x86_64) container if your hostsystem is amd64(x86_64). Or a arm64 container on a arm64 hostsystem (raspberry pi4). + +# Build cross platform + +To build a arm64 container on a amd64 hostsystem you could use: +``` +$ sudo docker buildx build --platform linux/arm64 -t headscale:custom-arm64 . + +``` + +**Import: Currently arm32 build are not supported as there is a problem with a library used by headscale. Hopefully this will be fixed soon.** + +# Build multiple arches + +To build multiple archres you could use: + +``` +$ sudo docker buildx create --use +$ sudo docker buildx build --platform linux/amd64,linux/arm64 . + +``` From b755d4765258027584b505e03a606f65380ada82 Mon Sep 17 00:00:00 2001 From: Jiang Zhu Date: Tue, 19 Jul 2022 20:45:23 +0800 Subject: [PATCH 16/33] update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c63ae49..e1ec1b60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ - 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) - Improve shutdown behaviour [#651](https://github.com/juanfont/headscale/pull/651) -- Drop Gin as web framework in Headscale [648](https://github.com/juanfont/headscale/pull/648) +- Drop Gin as web framework in Headscale [648](https://github.com/juanfont/headscale/pull/648) [677](https://github.com/juanfont/headscale/pull/677) - Make tailnet node updates check interval configurable [#675](https://github.com/juanfont/headscale/pull/675) ## 0.15.0 (2022-03-20) From 5724f4607c0bc24ccb6ceca2e84870eed63f7d0e Mon Sep 17 00:00:00 2001 From: Jiang Zhu Date: Tue, 19 Jul 2022 20:45:32 +0800 Subject: [PATCH 17/33] fix nix build --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index afa8c8bb..f9f3c83d 100644 --- a/flake.nix +++ b/flake.nix @@ -24,7 +24,7 @@ # When updating go.mod or go.sum, a new sha will need to be calculated, # update this if you have a mismatch after doing a change to thos files. - vendorSha256 = "sha256-T6rH+aqofFmCPxDfoA5xd3kNUJeZkT4GRyuFEnenps8="; + vendorSha256 = "sha256-b9C6F+7N0ecW0HiTx+rztZnxb+n6U6YTSOJvp3GqnWQ="; ldflags = [ "-s" "-w" "-X github.com/juanfont/headscale/cmd/headscale/cli.Version=v${version}" ]; }; From 02c7a46b977462d47240de2a3a8a3476306c08e6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 20 Jul 2022 07:21:19 +0000 Subject: [PATCH 18/33] docs(README): update contributors --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f00772e2..38578c3d 100644 --- a/README.md +++ b/README.md @@ -188,13 +188,6 @@ make build Ward Vandewege - - - Nico/ -
- Nico -
- Jiang @@ -202,6 +195,13 @@ make build Jiang Zhu + + + Nico/ +
+ Nico +
+ From 889eff265fdcaff348c406270666fa3067194559 Mon Sep 17 00:00:00 2001 From: Grigoriy Mikhalkin Date: Thu, 30 Jun 2022 23:35:22 +0200 Subject: [PATCH 19/33] graceful shutdown fix --- app.go | 23 +++++++++++++++++------ poll.go | 21 ++++++++++++--------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/app.go b/app.go index 11c8d685..de6ef669 100644 --- a/app.go +++ b/app.go @@ -95,6 +95,7 @@ type Headscale struct { ipAllocationMutex sync.Mutex shutdownChan chan struct{} + wg sync.WaitGroup } // Look up the TLS constant relative to user-supplied TLS client @@ -153,6 +154,7 @@ func NewHeadscale(cfg *Config) (*Headscale, error) { privateKey: privKey, aclRules: tailcfg.FilterAllowAll, // default allowall registrationCache: registrationCache, + wg: sync.WaitGroup{}, } err = app.initDB() @@ -567,6 +569,8 @@ func (h *Headscale) Serve() error { // https://github.com/soheilhy/cmux/issues/68 // https://github.com/soheilhy/cmux/issues/91 + var grpcServer *grpc.Server + var grpcListener net.Listener if tlsConfig != nil || h.cfg.GRPCAllowInsecure { log.Info().Msgf("Enabling remote gRPC at %s", h.cfg.GRPCAddr) @@ -587,12 +591,12 @@ func (h *Headscale) Serve() error { log.Warn().Msg("gRPC is running without security") } - grpcServer := grpc.NewServer(grpcOptions...) + grpcServer = grpc.NewServer(grpcOptions...) v1.RegisterHeadscaleServiceServer(grpcServer, newHeadscaleV1APIServer(h)) reflection.Register(grpcServer) - grpcListener, err := net.Listen("tcp", h.cfg.GRPCAddr) + grpcListener, err = net.Listen("tcp", h.cfg.GRPCAddr) if err != nil { return fmt.Errorf("failed to bind to TCP address: %w", err) } @@ -668,7 +672,7 @@ func (h *Headscale) Serve() error { syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP) - go func(c chan os.Signal) { + sig_func := func(c chan os.Signal) { // Wait for a SIGINT or SIGKILL: for { sig := <-c @@ -678,7 +682,7 @@ func (h *Headscale) Serve() error { Str("signal", sig.String()). Msg("Received SIGHUP, reloading ACL and Config") - // TODO(kradalby): Reload config on SIGHUP + // TODO(kradalby): Reload config on SIGHUP if h.cfg.ACL.PolicyPath != "" { aclPath := AbsolutePathFromConfigPath(h.cfg.ACL.PolicyPath) @@ -698,7 +702,8 @@ func (h *Headscale) Serve() error { Str("signal", sig.String()). Msg("Received signal to stop, shutting down gracefully") - h.shutdownChan <- struct{}{} + close(h.shutdownChan) + h.wg.Wait() // Gracefully shut down servers ctx, cancel := context.WithTimeout(context.Background(), HTTPShutdownTimeout) @@ -710,6 +715,11 @@ func (h *Headscale) Serve() error { } grpcSocket.GracefulStop() + if grpcServer != nil { + grpcServer.GracefulStop() + grpcListener.Close() + } + // Close network listeners promHTTPListener.Close() httpListener.Close() @@ -736,7 +746,8 @@ func (h *Headscale) Serve() error { os.Exit(0) } } - }(sigc) + } + errorGroup.Go(func() error { sig_func(sigc); return nil }) return errorGroup.Wait() } diff --git a/poll.go b/poll.go index 6628a179..94941aa3 100644 --- a/poll.go +++ b/poll.go @@ -290,6 +290,9 @@ func (h *Headscale) PollNetMapStream( keepAliveChan chan []byte, updateChan chan struct{}, ) { + h.wg.Add(1) + defer h.wg.Done() + ctx := context.WithValue(req.Context(), machineNameContextKey, machine.Hostname) ctx, cancel := context.WithCancel(ctx) @@ -353,9 +356,9 @@ func (h *Headscale) PollNetMapStream( Str("channel", "pollData"). Int("bytes", len(data)). Msg("Data from pollData channel written successfully") - // TODO(kradalby): Abstract away all the database calls, this can cause race conditions - // when an outdated machine object is kept alive, e.g. db is update from - // command line, but then overwritten. + // TODO(kradalby): Abstract away all the database calls, this can cause race conditions + // when an outdated machine object is kept alive, e.g. db is update from + // command line, but then overwritten. err = h.UpdateMachineFromDatabase(machine) if err != nil { log.Error(). @@ -431,9 +434,9 @@ func (h *Headscale) PollNetMapStream( Str("channel", "keepAlive"). Int("bytes", len(data)). Msg("Keep alive sent successfully") - // TODO(kradalby): Abstract away all the database calls, this can cause race conditions - // when an outdated machine object is kept alive, e.g. db is update from - // command line, but then overwritten. + // TODO(kradalby): Abstract away all the database calls, this can cause race conditions + // when an outdated machine object is kept alive, e.g. db is update from + // command line, but then overwritten. err = h.UpdateMachineFromDatabase(machine) if err != nil { log.Error(). @@ -588,9 +591,9 @@ func (h *Headscale) PollNetMapStream( Str("handler", "PollNetMapStream"). Str("machine", machine.Hostname). Msg("The client has closed the connection") - // TODO: Abstract away all the database calls, this can cause race conditions - // when an outdated machine object is kept alive, e.g. db is update from - // command line, but then overwritten. + // TODO: Abstract away all the database calls, this can cause race conditions + // when an outdated machine object is kept alive, e.g. db is update from + // command line, but then overwritten. err := h.UpdateMachineFromDatabase(machine) if err != nil { log.Error(). From 3f0639c87ddbb86fd9af3d210eafa98b80301ad1 Mon Sep 17 00:00:00 2001 From: Grigoriy Mikhalkin Date: Mon, 11 Jul 2022 20:33:24 +0200 Subject: [PATCH 20/33] graceful shutdown lint fixes --- app.go | 32 ++++++++++++++++++-------------- config.go | 13 +++++++++---- poll.go | 4 ++-- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/app.go b/app.go index de6ef669..5f5e2611 100644 --- a/app.go +++ b/app.go @@ -94,8 +94,8 @@ type Headscale struct { ipAllocationMutex sync.Mutex - shutdownChan chan struct{} - wg sync.WaitGroup + shutdownChan chan struct{} + pollNetMapStreamWG sync.WaitGroup } // Look up the TLS constant relative to user-supplied TLS client @@ -148,13 +148,13 @@ func NewHeadscale(cfg *Config) (*Headscale, error) { ) app := Headscale{ - cfg: cfg, - dbType: cfg.DBtype, - dbString: dbString, - privateKey: privKey, - aclRules: tailcfg.FilterAllowAll, // default allowall - registrationCache: registrationCache, - wg: sync.WaitGroup{}, + cfg: cfg, + dbType: cfg.DBtype, + dbString: dbString, + privateKey: privKey, + aclRules: tailcfg.FilterAllowAll, // default allowall + registrationCache: registrationCache, + pollNetMapStreamWG: sync.WaitGroup{}, } err = app.initDB() @@ -672,7 +672,7 @@ func (h *Headscale) Serve() error { syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP) - sig_func := func(c chan os.Signal) { + sigFunc := func(c chan os.Signal) { // Wait for a SIGINT or SIGKILL: for { sig := <-c @@ -703,7 +703,7 @@ func (h *Headscale) Serve() error { Msg("Received signal to stop, shutting down gracefully") close(h.shutdownChan) - h.wg.Wait() + h.pollNetMapStreamWG.Wait() // Gracefully shut down servers ctx, cancel := context.WithTimeout(context.Background(), HTTPShutdownTimeout) @@ -747,7 +747,11 @@ func (h *Headscale) Serve() error { } } } - errorGroup.Go(func() error { sig_func(sigc); return nil }) + errorGroup.Go(func() error { + sigFunc(sigc) + + return nil + }) return errorGroup.Wait() } @@ -771,13 +775,13 @@ func (h *Headscale) getTLSSettings() (*tls.Config, error) { } switch h.cfg.TLS.LetsEncrypt.ChallengeType { - case "TLS-ALPN-01": + case tlsALPN01ChallengeType: // Configuration via autocert with TLS-ALPN-01 (https://tools.ietf.org/html/rfc8737) // The RFC requires that the validation is done on port 443; in other words, headscale // must be reachable on port 443. return certManager.TLSConfig(), nil - case "HTTP-01": + case http01ChallengeType: // Configuration via autocert with HTTP-01. This requires listening on // port 80 for the certificate validation in addition to the headscale // service, which can be configured to run on any other port. diff --git a/config.go b/config.go index 6789f6f0..69358401 100644 --- a/config.go +++ b/config.go @@ -18,6 +18,11 @@ import ( "tailscale.com/types/dnstype" ) +const ( + tlsALPN01ChallengeType = "TLS-ALPN-01" + http01ChallengeType = "HTTP-01" +) + // Config contains the initial Headscale configuration. type Config struct { ServerURL string @@ -136,7 +141,7 @@ func LoadConfig(path string, isFile bool) error { viper.AutomaticEnv() viper.SetDefault("tls_letsencrypt_cache_dir", "/var/www/.cache") - viper.SetDefault("tls_letsencrypt_challenge_type", "HTTP-01") + viper.SetDefault("tls_letsencrypt_challenge_type", http01ChallengeType) viper.SetDefault("tls_client_auth_mode", "relaxed") viper.SetDefault("log_level", "info") @@ -179,15 +184,15 @@ func LoadConfig(path string, isFile bool) error { } if (viper.GetString("tls_letsencrypt_hostname") != "") && - (viper.GetString("tls_letsencrypt_challenge_type") == "TLS-ALPN-01") && + (viper.GetString("tls_letsencrypt_challenge_type") == tlsALPN01ChallengeType) && (!strings.HasSuffix(viper.GetString("listen_addr"), ":443")) { // this is only a warning because there could be something sitting in front of headscale that redirects the traffic (e.g. an iptables rule) log.Warn(). Msg("Warning: when using tls_letsencrypt_hostname with TLS-ALPN-01 as challenge type, headscale must be reachable on port 443, i.e. listen_addr should probably end in :443") } - if (viper.GetString("tls_letsencrypt_challenge_type") != "HTTP-01") && - (viper.GetString("tls_letsencrypt_challenge_type") != "TLS-ALPN-01") { + if (viper.GetString("tls_letsencrypt_challenge_type") != http01ChallengeType) && + (viper.GetString("tls_letsencrypt_challenge_type") != tlsALPN01ChallengeType) { errorText += "Fatal config error: the only supported values for tls_letsencrypt_challenge_type are HTTP-01 and TLS-ALPN-01\n" } diff --git a/poll.go b/poll.go index 94941aa3..b9a757aa 100644 --- a/poll.go +++ b/poll.go @@ -290,8 +290,8 @@ func (h *Headscale) PollNetMapStream( keepAliveChan chan []byte, updateChan chan struct{}, ) { - h.wg.Add(1) - defer h.wg.Done() + h.pollNetMapStreamWG.Add(1) + defer h.pollNetMapStreamWG.Done() ctx := context.WithValue(req.Context(), machineNameContextKey, machine.Hostname) From 395caaad421797ac7fba6a0ca0e7df87d13262f2 Mon Sep 17 00:00:00 2001 From: Grigoriy Mikhalkin Date: Mon, 11 Jul 2022 23:25:13 +0200 Subject: [PATCH 21/33] decompose OIDCCallback method --- oidc.go | 240 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 187 insertions(+), 53 deletions(-) diff --git a/oidc.go b/oidc.go index 8b5f0242..5509bd47 100644 --- a/oidc.go +++ b/oidc.go @@ -136,6 +136,82 @@ func (h *Headscale) OIDCCallback( writer http.ResponseWriter, req *http.Request, ) { + code, state, ok := validateOIDCCallbackParams(writer, req) + if !ok { + return + } + + rawIDToken, ok := h.getIDTokenForOIDCCallback(writer, code, state) + if !ok { + return + } + + idToken, ok := h.verifyIDTokenForOIDCCallback(writer, rawIDToken) + if !ok { + return + } + + // TODO: we can use userinfo at some point to grab additional information about the user (groups membership, etc) + // userInfo, err := oidcProvider.UserInfo(context.Background(), oauth2.StaticTokenSource(oauth2Token)) + // if err != nil { + // c.String(http.StatusBadRequest, fmt.Sprintf("Failed to retrieve userinfo")) + // return + // } + + claims, ok := extractIDTokenClaims(writer, idToken) + if !ok { + return + } + + if ok := validateOIDCAllowedDomains(writer, h.cfg.OIDC.AllowedDomains, claims); !ok { + return + } + + if ok := validateOIDCAllowedUsers(writer, h.cfg.OIDC.AllowedUsers, claims); !ok { + return + } + + machineKey, ok := h.validateMachineForOIDCCallback(writer, state, claims) + if !ok { + return + } + + namespaceName, ok := getNamespaceName(writer, claims, h.cfg.OIDC.StripEmaildomain) + if !ok { + return + } + + // register the machine if it's new + log.Debug().Msg("Registering new machine after successful callback") + + namespace, ok := h.findOrCreateNewNamespaceForOIDCCallback(writer, namespaceName) + if !ok { + return + } + + if ok := h.registerMachineForOIDCCallback(writer, namespace, machineKey); !ok { + return + } + + content, ok := renderOIDCCallbackTemplate(writer, claims) + if !ok { + return + } + + writer.Header().Set("Content-Type", "text/html; charset=utf-8") + writer.WriteHeader(http.StatusOK) + if _, err := writer.Write(content.Bytes()); err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } +} + +func validateOIDCCallbackParams( + writer http.ResponseWriter, + req *http.Request, +) (string, string, bool) { code := req.URL.Query().Get("code") state := req.URL.Query().Get("state") @@ -150,9 +226,16 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return "", "", false } + return code, state, true +} + +func (h *Headscale) getIDTokenForOIDCCallback( + writer http.ResponseWriter, + code, state string, +) (string, bool) { oauth2Token, err := h.oauth2Config.Exchange(context.Background(), code) if err != nil { log.Error(). @@ -169,7 +252,7 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return "", false } log.Trace(). @@ -190,11 +273,17 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return "", false } - verifier := h.oidcProvider.Verifier(&oidc.Config{ClientID: h.cfg.OIDC.ClientID}) + return rawIDToken, true +} +func (h *Headscale) verifyIDTokenForOIDCCallback( + writer http.ResponseWriter, + rawIDToken string, +) (*oidc.IDToken, bool) { + verifier := h.oidcProvider.Verifier(&oidc.Config{ClientID: h.cfg.OIDC.ClientID}) idToken, err := verifier.Verify(context.Background(), rawIDToken) if err != nil { log.Error(). @@ -211,19 +300,18 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return nil, false } - // TODO: we can use userinfo at some point to grab additional information about the user (groups membership, etc) - // userInfo, err := oidcProvider.UserInfo(context.Background(), oauth2.StaticTokenSource(oauth2Token)) - // if err != nil { - // c.String(http.StatusBadRequest, fmt.Sprintf("Failed to retrieve userinfo")) - // return - // } + return idToken, true +} - // Extract custom claims +func extractIDTokenClaims( + writer http.ResponseWriter, + idToken *oidc.IDToken, +) (*IDTokenClaims, bool) { var claims IDTokenClaims - if err = idToken.Claims(&claims); err != nil { + if err := idToken.Claims(claims); err != nil { log.Error(). Err(err). Caller(). @@ -238,13 +326,22 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return nil, false } - // If AllowedDomains is provided, check that the authenticated principal ends with @. - if len(h.cfg.OIDC.AllowedDomains) > 0 { + return &claims, true +} + +// validateOIDCAllowedDomains checks that if AllowedDomains is provided, +// that the authenticated principal ends with @. +func validateOIDCAllowedDomains( + writer http.ResponseWriter, + allowedDomains []string, + claims *IDTokenClaims, +) bool { + if len(allowedDomains) > 0 { if at := strings.LastIndex(claims.Email, "@"); at < 0 || - !IsStringInSlice(h.cfg.OIDC.AllowedDomains, claims.Email[at+1:]) { + !IsStringInSlice(allowedDomains, claims.Email[at+1:]) { log.Error().Msg("authenticated principal does not match any allowed domain") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) @@ -256,13 +353,22 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return false } } - // If AllowedUsers is provided, check that the authenticated princial is part of that list. - if len(h.cfg.OIDC.AllowedUsers) > 0 && - !IsStringInSlice(h.cfg.OIDC.AllowedUsers, claims.Email) { + return true +} + +// validateOIDCAllowedUsers checks that if AllowedUsers is provided, +// that the authenticated principal is part of that list. +func validateOIDCAllowedUsers( + writer http.ResponseWriter, + allowedUsers []string, + claims *IDTokenClaims, +) bool { + if len(allowedUsers) > 0 && + !IsStringInSlice(allowedUsers, claims.Email) { log.Error().Msg("authenticated principal does not match any allowed user") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) @@ -274,12 +380,23 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return false } + return true +} + +// validateMachine retrieves machine information if it exist +// The error is not important, because if it does not +// exist, then this is a new machine and we will move +// on to registration. +func (h *Headscale) validateMachineForOIDCCallback( + writer http.ResponseWriter, + state string, + claims *IDTokenClaims, +) (*key.MachinePublic, bool) { // retrieve machinekey from state cache machineKeyIf, machineKeyFound := h.registrationCache.Get(state) - if !machineKeyFound { log.Error(). Msg("requested machine state key expired before authorisation completed") @@ -293,13 +410,12 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return nil, false } - machineKeyFromCache, machineKeyOK := machineKeyIf.(string) - var machineKey key.MachinePublic - err = machineKey.UnmarshalText( + machineKeyFromCache, machineKeyOK := machineKeyIf.(string) + err := machineKey.UnmarshalText( []byte(MachinePublicKeyEnsurePrefix(machineKeyFromCache)), ) if err != nil { @@ -315,7 +431,7 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return nil, false } if !machineKeyOK { @@ -330,7 +446,7 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return nil, false } // retrieve machine information if it exist @@ -353,7 +469,7 @@ func (h *Headscale) OIDCCallback( Msg("Failed to refresh machine") http.Error(writer, "Failed to refresh machine", http.StatusInternalServerError) - return + return nil, false } var content bytes.Buffer @@ -377,7 +493,7 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return nil, false } writer.Header().Set("Content-Type", "text/html; charset=utf-8") @@ -390,12 +506,20 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return nil, false } + return &machineKey, true +} + +func getNamespaceName( + writer http.ResponseWriter, + claims *IDTokenClaims, + stripEmaildomain bool, +) (string, bool) { namespaceName, err := NormalizeToFQDNRules( claims.Email, - h.cfg.OIDC.StripEmaildomain, + stripEmaildomain, ) if err != nil { log.Error().Err(err).Caller().Msgf("couldn't normalize email") @@ -409,12 +533,16 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return "", false } - // register the machine if it's new - log.Debug().Msg("Registering new machine after successful callback") + return namespaceName, true +} +func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback( + writer http.ResponseWriter, + namespaceName string, +) (*Namespace, bool) { namespace, err := h.GetNamespace(namespaceName) if errors.Is(err, errNamespaceNotFound) { namespace, err = h.CreateNamespace(namespaceName) @@ -434,7 +562,7 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return nil, false } } else if err != nil { log.Error(). @@ -452,17 +580,24 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return nil, false } - machineKeyStr := MachinePublicKeyStripPrefix(machineKey) + return namespace, true +} - _, err = h.RegisterMachineFromAuthCallback( +func (h *Headscale) registerMachineForOIDCCallback( + writer http.ResponseWriter, + namespace *Namespace, + machineKey *key.MachinePublic, +) bool { + machineKeyStr := MachinePublicKeyStripPrefix(*machineKey) + + if _, err := h.RegisterMachineFromAuthCallback( machineKeyStr, namespace.Name, RegisterMethodOIDC, - ) - if err != nil { + ); err != nil { log.Error(). Caller(). Err(err). @@ -477,9 +612,16 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return false } + return true +} + +func renderOIDCCallbackTemplate( + writer http.ResponseWriter, + claims *IDTokenClaims, +) (*bytes.Buffer, bool) { var content bytes.Buffer if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{ User: claims.Email, @@ -501,16 +643,8 @@ func (h *Headscale) OIDCCallback( Msg("Failed to write response") } - return + return nil, false } - writer.Header().Set("Content-Type", "text/html; charset=utf-8") - writer.WriteHeader(http.StatusOK) - _, err = writer.Write(content.Bytes()) - if err != nil { - log.Error(). - Caller(). - Err(err). - Msg("Failed to write response") - } + return &content, true } From 56858a56dbd50cc1c0547542a0b78948318e0f30 Mon Sep 17 00:00:00 2001 From: Grigoriy Mikhalkin Date: Thu, 21 Jul 2022 23:47:59 +0200 Subject: [PATCH 22/33] Revert "decompose OIDCCallback method" This reverts commit 395caaad421797ac7fba6a0ca0e7df87d13262f2. --- oidc.go | 240 +++++++++++++------------------------------------------- poll.go | 18 ++--- 2 files changed, 62 insertions(+), 196 deletions(-) diff --git a/oidc.go b/oidc.go index 5509bd47..8b5f0242 100644 --- a/oidc.go +++ b/oidc.go @@ -136,82 +136,6 @@ func (h *Headscale) OIDCCallback( writer http.ResponseWriter, req *http.Request, ) { - code, state, ok := validateOIDCCallbackParams(writer, req) - if !ok { - return - } - - rawIDToken, ok := h.getIDTokenForOIDCCallback(writer, code, state) - if !ok { - return - } - - idToken, ok := h.verifyIDTokenForOIDCCallback(writer, rawIDToken) - if !ok { - return - } - - // TODO: we can use userinfo at some point to grab additional information about the user (groups membership, etc) - // userInfo, err := oidcProvider.UserInfo(context.Background(), oauth2.StaticTokenSource(oauth2Token)) - // if err != nil { - // c.String(http.StatusBadRequest, fmt.Sprintf("Failed to retrieve userinfo")) - // return - // } - - claims, ok := extractIDTokenClaims(writer, idToken) - if !ok { - return - } - - if ok := validateOIDCAllowedDomains(writer, h.cfg.OIDC.AllowedDomains, claims); !ok { - return - } - - if ok := validateOIDCAllowedUsers(writer, h.cfg.OIDC.AllowedUsers, claims); !ok { - return - } - - machineKey, ok := h.validateMachineForOIDCCallback(writer, state, claims) - if !ok { - return - } - - namespaceName, ok := getNamespaceName(writer, claims, h.cfg.OIDC.StripEmaildomain) - if !ok { - return - } - - // register the machine if it's new - log.Debug().Msg("Registering new machine after successful callback") - - namespace, ok := h.findOrCreateNewNamespaceForOIDCCallback(writer, namespaceName) - if !ok { - return - } - - if ok := h.registerMachineForOIDCCallback(writer, namespace, machineKey); !ok { - return - } - - content, ok := renderOIDCCallbackTemplate(writer, claims) - if !ok { - return - } - - writer.Header().Set("Content-Type", "text/html; charset=utf-8") - writer.WriteHeader(http.StatusOK) - if _, err := writer.Write(content.Bytes()); err != nil { - log.Error(). - Caller(). - Err(err). - Msg("Failed to write response") - } -} - -func validateOIDCCallbackParams( - writer http.ResponseWriter, - req *http.Request, -) (string, string, bool) { code := req.URL.Query().Get("code") state := req.URL.Query().Get("state") @@ -226,16 +150,9 @@ func validateOIDCCallbackParams( Msg("Failed to write response") } - return "", "", false + return } - return code, state, true -} - -func (h *Headscale) getIDTokenForOIDCCallback( - writer http.ResponseWriter, - code, state string, -) (string, bool) { oauth2Token, err := h.oauth2Config.Exchange(context.Background(), code) if err != nil { log.Error(). @@ -252,7 +169,7 @@ func (h *Headscale) getIDTokenForOIDCCallback( Msg("Failed to write response") } - return "", false + return } log.Trace(). @@ -273,17 +190,11 @@ func (h *Headscale) getIDTokenForOIDCCallback( Msg("Failed to write response") } - return "", false + return } - return rawIDToken, true -} - -func (h *Headscale) verifyIDTokenForOIDCCallback( - writer http.ResponseWriter, - rawIDToken string, -) (*oidc.IDToken, bool) { verifier := h.oidcProvider.Verifier(&oidc.Config{ClientID: h.cfg.OIDC.ClientID}) + idToken, err := verifier.Verify(context.Background(), rawIDToken) if err != nil { log.Error(). @@ -300,18 +211,19 @@ func (h *Headscale) verifyIDTokenForOIDCCallback( Msg("Failed to write response") } - return nil, false + return } - return idToken, true -} + // TODO: we can use userinfo at some point to grab additional information about the user (groups membership, etc) + // userInfo, err := oidcProvider.UserInfo(context.Background(), oauth2.StaticTokenSource(oauth2Token)) + // if err != nil { + // c.String(http.StatusBadRequest, fmt.Sprintf("Failed to retrieve userinfo")) + // return + // } -func extractIDTokenClaims( - writer http.ResponseWriter, - idToken *oidc.IDToken, -) (*IDTokenClaims, bool) { + // Extract custom claims var claims IDTokenClaims - if err := idToken.Claims(claims); err != nil { + if err = idToken.Claims(&claims); err != nil { log.Error(). Err(err). Caller(). @@ -326,22 +238,13 @@ func extractIDTokenClaims( Msg("Failed to write response") } - return nil, false + return } - return &claims, true -} - -// validateOIDCAllowedDomains checks that if AllowedDomains is provided, -// that the authenticated principal ends with @. -func validateOIDCAllowedDomains( - writer http.ResponseWriter, - allowedDomains []string, - claims *IDTokenClaims, -) bool { - if len(allowedDomains) > 0 { + // If AllowedDomains is provided, check that the authenticated principal ends with @. + if len(h.cfg.OIDC.AllowedDomains) > 0 { if at := strings.LastIndex(claims.Email, "@"); at < 0 || - !IsStringInSlice(allowedDomains, claims.Email[at+1:]) { + !IsStringInSlice(h.cfg.OIDC.AllowedDomains, claims.Email[at+1:]) { log.Error().Msg("authenticated principal does not match any allowed domain") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) @@ -353,22 +256,13 @@ func validateOIDCAllowedDomains( Msg("Failed to write response") } - return false + return } } - return true -} - -// validateOIDCAllowedUsers checks that if AllowedUsers is provided, -// that the authenticated principal is part of that list. -func validateOIDCAllowedUsers( - writer http.ResponseWriter, - allowedUsers []string, - claims *IDTokenClaims, -) bool { - if len(allowedUsers) > 0 && - !IsStringInSlice(allowedUsers, claims.Email) { + // If AllowedUsers is provided, check that the authenticated princial is part of that list. + if len(h.cfg.OIDC.AllowedUsers) > 0 && + !IsStringInSlice(h.cfg.OIDC.AllowedUsers, claims.Email) { log.Error().Msg("authenticated principal does not match any allowed user") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) @@ -380,23 +274,12 @@ func validateOIDCAllowedUsers( Msg("Failed to write response") } - return false + return } - return true -} - -// validateMachine retrieves machine information if it exist -// The error is not important, because if it does not -// exist, then this is a new machine and we will move -// on to registration. -func (h *Headscale) validateMachineForOIDCCallback( - writer http.ResponseWriter, - state string, - claims *IDTokenClaims, -) (*key.MachinePublic, bool) { // retrieve machinekey from state cache machineKeyIf, machineKeyFound := h.registrationCache.Get(state) + if !machineKeyFound { log.Error(). Msg("requested machine state key expired before authorisation completed") @@ -410,12 +293,13 @@ func (h *Headscale) validateMachineForOIDCCallback( Msg("Failed to write response") } - return nil, false + return } - var machineKey key.MachinePublic machineKeyFromCache, machineKeyOK := machineKeyIf.(string) - err := machineKey.UnmarshalText( + + var machineKey key.MachinePublic + err = machineKey.UnmarshalText( []byte(MachinePublicKeyEnsurePrefix(machineKeyFromCache)), ) if err != nil { @@ -431,7 +315,7 @@ func (h *Headscale) validateMachineForOIDCCallback( Msg("Failed to write response") } - return nil, false + return } if !machineKeyOK { @@ -446,7 +330,7 @@ func (h *Headscale) validateMachineForOIDCCallback( Msg("Failed to write response") } - return nil, false + return } // retrieve machine information if it exist @@ -469,7 +353,7 @@ func (h *Headscale) validateMachineForOIDCCallback( Msg("Failed to refresh machine") http.Error(writer, "Failed to refresh machine", http.StatusInternalServerError) - return nil, false + return } var content bytes.Buffer @@ -493,7 +377,7 @@ func (h *Headscale) validateMachineForOIDCCallback( Msg("Failed to write response") } - return nil, false + return } writer.Header().Set("Content-Type", "text/html; charset=utf-8") @@ -506,20 +390,12 @@ func (h *Headscale) validateMachineForOIDCCallback( Msg("Failed to write response") } - return nil, false + return } - return &machineKey, true -} - -func getNamespaceName( - writer http.ResponseWriter, - claims *IDTokenClaims, - stripEmaildomain bool, -) (string, bool) { namespaceName, err := NormalizeToFQDNRules( claims.Email, - stripEmaildomain, + h.cfg.OIDC.StripEmaildomain, ) if err != nil { log.Error().Err(err).Caller().Msgf("couldn't normalize email") @@ -533,16 +409,12 @@ func getNamespaceName( Msg("Failed to write response") } - return "", false + return } - return namespaceName, true -} + // register the machine if it's new + log.Debug().Msg("Registering new machine after successful callback") -func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback( - writer http.ResponseWriter, - namespaceName string, -) (*Namespace, bool) { namespace, err := h.GetNamespace(namespaceName) if errors.Is(err, errNamespaceNotFound) { namespace, err = h.CreateNamespace(namespaceName) @@ -562,7 +434,7 @@ func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback( Msg("Failed to write response") } - return nil, false + return } } else if err != nil { log.Error(). @@ -580,24 +452,17 @@ func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback( Msg("Failed to write response") } - return nil, false + return } - return namespace, true -} + machineKeyStr := MachinePublicKeyStripPrefix(machineKey) -func (h *Headscale) registerMachineForOIDCCallback( - writer http.ResponseWriter, - namespace *Namespace, - machineKey *key.MachinePublic, -) bool { - machineKeyStr := MachinePublicKeyStripPrefix(*machineKey) - - if _, err := h.RegisterMachineFromAuthCallback( + _, err = h.RegisterMachineFromAuthCallback( machineKeyStr, namespace.Name, RegisterMethodOIDC, - ); err != nil { + ) + if err != nil { log.Error(). Caller(). Err(err). @@ -612,16 +477,9 @@ func (h *Headscale) registerMachineForOIDCCallback( Msg("Failed to write response") } - return false + return } - return true -} - -func renderOIDCCallbackTemplate( - writer http.ResponseWriter, - claims *IDTokenClaims, -) (*bytes.Buffer, bool) { var content bytes.Buffer if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{ User: claims.Email, @@ -643,8 +501,16 @@ func renderOIDCCallbackTemplate( Msg("Failed to write response") } - return nil, false + return } - return &content, true + writer.Header().Set("Content-Type", "text/html; charset=utf-8") + writer.WriteHeader(http.StatusOK) + _, err = writer.Write(content.Bytes()) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } diff --git a/poll.go b/poll.go index b9a757aa..9c17b5cb 100644 --- a/poll.go +++ b/poll.go @@ -356,9 +356,9 @@ func (h *Headscale) PollNetMapStream( Str("channel", "pollData"). Int("bytes", len(data)). Msg("Data from pollData channel written successfully") - // TODO(kradalby): Abstract away all the database calls, this can cause race conditions - // when an outdated machine object is kept alive, e.g. db is update from - // command line, but then overwritten. + // TODO(kradalby): Abstract away all the database calls, this can cause race conditions + // when an outdated machine object is kept alive, e.g. db is update from + // command line, but then overwritten. err = h.UpdateMachineFromDatabase(machine) if err != nil { log.Error(). @@ -434,9 +434,9 @@ func (h *Headscale) PollNetMapStream( Str("channel", "keepAlive"). Int("bytes", len(data)). Msg("Keep alive sent successfully") - // TODO(kradalby): Abstract away all the database calls, this can cause race conditions - // when an outdated machine object is kept alive, e.g. db is update from - // command line, but then overwritten. + // TODO(kradalby): Abstract away all the database calls, this can cause race conditions + // when an outdated machine object is kept alive, e.g. db is update from + // command line, but then overwritten. err = h.UpdateMachineFromDatabase(machine) if err != nil { log.Error(). @@ -591,9 +591,9 @@ func (h *Headscale) PollNetMapStream( Str("handler", "PollNetMapStream"). Str("machine", machine.Hostname). Msg("The client has closed the connection") - // TODO: Abstract away all the database calls, this can cause race conditions - // when an outdated machine object is kept alive, e.g. db is update from - // command line, but then overwritten. + // TODO: Abstract away all the database calls, this can cause race conditions + // when an outdated machine object is kept alive, e.g. db is update from + // command line, but then overwritten. err := h.UpdateMachineFromDatabase(machine) if err != nil { log.Error(). From a4d0efbe8d1cfc61b4b3934d8e15d6032be71781 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Thu, 21 Jul 2022 23:57:07 +0200 Subject: [PATCH 23/33] Fix API router --- app.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app.go b/app.go index 11c8d685..d7d5ea52 100644 --- a/app.go +++ b/app.go @@ -445,11 +445,9 @@ func (h *Headscale) createRouter(grpcMux *runtime.ServeMux) *mux.Router { router.HandleFunc("/bootstrap-dns", h.DERPBootstrapDNSHandler) } - api := router.PathPrefix("/api").Subrouter() - api.Use(h.httpAuthenticationMiddleware) - { - api.HandleFunc("/v1/*any", grpcMux.ServeHTTP) - } + apiRouter := router.PathPrefix("/api").Subrouter() + apiRouter.Use(h.httpAuthenticationMiddleware) + apiRouter.PathPrefix("/v1/").HandlerFunc(grpcMux.ServeHTTP) router.PathPrefix("/").HandlerFunc(stdoutHandler) From 6c9f3420e250c610fa164af64ce8ac9d6c2d7779 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Thu, 21 Jul 2022 23:59:44 +0200 Subject: [PATCH 24/33] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1ec1b60..f43dfea4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ - Improve shutdown behaviour [#651](https://github.com/juanfont/headscale/pull/651) - Drop Gin as web framework in Headscale [648](https://github.com/juanfont/headscale/pull/648) [677](https://github.com/juanfont/headscale/pull/677) - Make tailnet node updates check interval configurable [#675](https://github.com/juanfont/headscale/pull/675) +- Fix regression with HTTP API [#684](https://github.com/juanfont/headscale/pull/684) ## 0.15.0 (2022-03-20) From 936adb7d2c0abfcd9333f5166d240deaf2fc16b5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Jul 2022 07:36:16 +0000 Subject: [PATCH 25/33] docs(README): update contributors --- README.md | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 38578c3d..d0887675 100644 --- a/README.md +++ b/README.md @@ -283,6 +283,15 @@ make build Fernando De Lucchi + + + GrigoriyMikhalkin/ +
+ GrigoriyMikhalkin +
+ + + Hoàng @@ -290,8 +299,6 @@ make build Hoàng Đức Hiếu - - bravechamp/ @@ -327,6 +334,8 @@ make build Michael G. + + Paul @@ -334,8 +343,6 @@ make build Paul Tötterman - - Samuel @@ -371,6 +378,8 @@ make build Pavlos Vinieratos + + Silver @@ -378,8 +387,6 @@ make build Silver Bullet - - lachy2849/ @@ -415,6 +422,8 @@ make build Aofei Sheng + + Arthur @@ -422,8 +431,6 @@ make build Arthur Woimbée - - Bryan @@ -459,6 +466,8 @@ make build Felix Yan + + JJGadgets/ @@ -466,8 +475,6 @@ make build JJGadgets - - Jamie @@ -503,6 +510,8 @@ make build WhiteSource Renovate + + Ryan @@ -510,8 +519,6 @@ make build Ryan Fowler - - Shaanan @@ -547,6 +554,8 @@ make build Tianon Gravi + + Tjerk @@ -554,8 +563,6 @@ make build Tjerk Woudsma - - Yang @@ -591,6 +598,8 @@ make build henning mueller + + ignoramous/ @@ -598,8 +607,6 @@ make build ignoramous - - lion24/ From dc94570c4ad5a120b14751200605c181f43a94d3 Mon Sep 17 00:00:00 2001 From: Jiang Zhu Date: Sat, 23 Jul 2022 01:33:11 +0800 Subject: [PATCH 26/33] more intuitive output of node ls --- cmd/headscale/cli/nodes.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/headscale/cli/nodes.go b/cmd/headscale/cli/nodes.go index 059a16df..c2b1e950 100644 --- a/cmd/headscale/cli/nodes.go +++ b/cmd/headscale/cli/nodes.go @@ -465,6 +465,7 @@ func nodesToPtables( ) (pterm.TableData, error) { tableHeader := []string{ "ID", + "Hostname", "Name", "NodeKey", "Namespace", @@ -566,6 +567,7 @@ func nodesToPtables( nodeData := []string{ strconv.FormatUint(machine.Id, headscale.Base10), machine.Name, + machine.GetGivenName(), nodeKey.ShortString(), namespace, strings.Join([]string{IPV4Address, IPV6Address}, ", "), From 49354f678efa1b58cc53727afb26daa249414c5f Mon Sep 17 00:00:00 2001 From: Jiang Zhu Date: Sat, 23 Jul 2022 04:47:37 +0800 Subject: [PATCH 27/33] update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f43dfea4..2c2ae625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ - Drop Gin as web framework in Headscale [648](https://github.com/juanfont/headscale/pull/648) [677](https://github.com/juanfont/headscale/pull/677) - Make tailnet node updates check interval configurable [#675](https://github.com/juanfont/headscale/pull/675) - Fix regression with HTTP API [#684](https://github.com/juanfont/headscale/pull/684) +- nodes ls now print both Hostname and Name(Issue [#647](https://github.com/juanfont/headscale/issues/647) PR [#687](https://github.com/juanfont/headscale/pull/687)) ## 0.15.0 (2022-03-20) From 693f59ba2f07d4ac3ea7146ac0882b6a0ddf062b Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Mon, 25 Jul 2022 10:35:21 +0200 Subject: [PATCH 28/33] Prepare changelog structure for 0.17.0 --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c2ae625..cca31521 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # CHANGELOG -## 0.16.0 (2022-xx-xx) + +## 0.17.0 (2022-xx-xx) + + +## 0.16.0 (2022-07-25) + +**Note:** Take a backup of your database before upgrading. ### BREAKING From c46a34e6b848d7e5147f35b5a176db2d69c4d117 Mon Sep 17 00:00:00 2001 From: Adrien Raffin-Caboisse Date: Mon, 25 Jul 2022 10:54:51 +0200 Subject: [PATCH 29/33] fix(machine): remove duplicate in forcedTags --- machine.go | 8 +++++++- machine_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/machine.go b/machine.go index 1bed2955..dda49020 100644 --- a/machine.go +++ b/machine.go @@ -374,7 +374,13 @@ func (h *Headscale) UpdateMachineFromDatabase(machine *Machine) error { // SetTags takes a Machine struct pointer and update the forced tags. func (h *Headscale) SetTags(machine *Machine, tags []string) error { - machine.ForcedTags = tags + newTags := []string{} + for _, tag := range tags { + if !contains(newTags, tag) { + newTags = append(newTags, tag) + } + } + machine.ForcedTags = newTags if err := h.UpdateACLRules(); err != nil && !errors.Is(err, errEmptyPolicy) { return err } diff --git a/machine_test.go b/machine_test.go index a06d0db2..35c3eed9 100644 --- a/machine_test.go +++ b/machine_test.go @@ -280,6 +280,49 @@ func (s *Suite) TestSerdeAddressStrignSlice(c *check.C) { } } +func (s *Suite) TestSetTags(c *check.C) { + namespace, err := app.CreateNamespace("test") + c.Assert(err, check.IsNil) + + pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil) + c.Assert(err, check.IsNil) + + _, err = app.GetMachine("test", "testmachine") + c.Assert(err, check.NotNil) + + machine := &Machine{ + ID: 0, + MachineKey: "foo", + NodeKey: "bar", + DiscoKey: "faa", + Hostname: "testmachine", + NamespaceID: namespace.ID, + RegisterMethod: RegisterMethodAuthKey, + AuthKeyID: uint(pak.ID), + } + app.db.Save(machine) + + // assign simple tags + sTags := []string{"tag:test", "tag:foo"} + err = app.SetTags(machine, sTags) + c.Assert(err, check.IsNil) + machine, err = app.GetMachine("test", "testmachine") + c.Assert(err, check.IsNil) + c.Assert(machine.ForcedTags, check.DeepEquals, StringList(sTags)) + + // assign duplicat tags, expect no errors but no doubles in DB + eTags := []string{"tag:bar", "tag:test", "tag:unknown", "tag:test"} + err = app.SetTags(machine, eTags) + c.Assert(err, check.IsNil) + machine, err = app.GetMachine("test", "testmachine") + c.Assert(err, check.IsNil) + c.Assert( + machine.ForcedTags, + check.DeepEquals, + StringList([]string{"tag:bar", "tag:test", "tag:unknown"}), + ) +} + func Test_getTags(t *testing.T) { type args struct { aclPolicy *ACLPolicy From c90e862460ab9b48d93e14f325efe9250ea2a0b5 Mon Sep 17 00:00:00 2001 From: Adrien Raffin-Caboisse Date: Mon, 25 Jul 2022 11:25:20 +0200 Subject: [PATCH 30/33] fix(grpc): add more checks for tag validation --- grpcv1.go | 22 ++++++++++++++++----- grpcv1_test.go | 42 +++++++++++++++++++++++++++++++++++++++++ integration_cli_test.go | 2 +- 3 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 grpcv1_test.go diff --git a/grpcv1.go b/grpcv1.go index 1c891b94..b1e5c1ee 100644 --- a/grpcv1.go +++ b/grpcv1.go @@ -3,6 +3,7 @@ package headscale import ( "context" + "fmt" "strings" "time" @@ -195,13 +196,11 @@ func (api headscaleV1APIServer) SetTags( } for _, tag := range request.GetTags() { - if strings.Index(tag, "tag:") != 0 { + err := validateTag(tag) + if err != nil { return &v1.SetTagsResponse{ Machine: nil, - }, status.Error( - codes.InvalidArgument, - "Invalid tag detected. Each tag must start with the string 'tag:'", - ) + }, status.Error(codes.InvalidArgument, err.Error()) } } @@ -220,6 +219,19 @@ func (api headscaleV1APIServer) SetTags( return &v1.SetTagsResponse{Machine: machine.toProto()}, nil } +func validateTag(tag string) error { + if strings.Index(tag, "tag:") != 0 { + return fmt.Errorf("tag must start with the string 'tag:'") + } + if strings.ToLower(tag) != tag { + return fmt.Errorf("tag should be lowercase") + } + if len(strings.Fields(tag)) > 1 { + return fmt.Errorf("tag should not contains space") + } + return nil +} + func (api headscaleV1APIServer) DeleteMachine( ctx context.Context, request *v1.DeleteMachineRequest, diff --git a/grpcv1_test.go b/grpcv1_test.go new file mode 100644 index 00000000..e48ae1ef --- /dev/null +++ b/grpcv1_test.go @@ -0,0 +1,42 @@ +package headscale + +import "testing" + +func Test_validateTag(t *testing.T) { + type args struct { + tag string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid tag", + args: args{tag: "tag:test"}, + wantErr: false, + }, + { + name: "tag without tag prefix", + args: args{tag: "test"}, + wantErr: true, + }, + { + name: "uppercase tag", + args: args{tag: "tag:tEST"}, + wantErr: true, + }, + { + name: "tag that contains space", + args: args{tag: "tag:this is a spaced tag"}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := validateTag(tt.args.tag); (err != nil) != tt.wantErr { + t.Errorf("validateTag() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/integration_cli_test.go b/integration_cli_test.go index f9ff5ec0..2f58e71d 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -625,7 +625,7 @@ func (s *IntegrationCLITestSuite) TestNodeTagCommand() { var errorOutput errOutput err = json.Unmarshal([]byte(wrongTagResult), &errorOutput) assert.Nil(s.T(), err) - assert.Contains(s.T(), errorOutput.Error, "Invalid tag detected") + assert.Contains(s.T(), errorOutput.Error, "tag must start with the string 'tag:'") // Test list all nodes after added seconds listAllResult, err := ExecuteCommand( From 6f4d5a532e168787933cf084c095f618c01d3cfe Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Tue, 26 Jul 2022 11:25:20 +0200 Subject: [PATCH 31/33] fixed linting errors --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cca31521..d9a3a132 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,7 @@ # CHANGELOG - ## 0.17.0 (2022-xx-xx) - ## 0.16.0 (2022-07-25) **Note:** Take a backup of your database before upgrading. From b344524a6d084323587d92c17676628a49007276 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Tue, 26 Jul 2022 12:02:58 +0200 Subject: [PATCH 32/33] Update runc dependencies to fix security notification --- go.mod | 8 ++++---- go.sum | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 80a3e488..4784ef29 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.0 github.com/klauspost/compress v1.15.4 - github.com/ory/dockertest/v3 v3.8.1 + github.com/ory/dockertest/v3 v3.9.1 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/philip-bui/grpc-zerolog v1.0.1 github.com/prometheus/client_golang v1.12.1 @@ -50,9 +50,9 @@ require ( github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 // indirect github.com/atomicgo/cursor v0.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.1.2 // indirect + github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 // indirect + github.com/containerd/continuity v0.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/cli v20.10.16+incompatible // indirect github.com/docker/docker v20.10.16+incompatible // indirect @@ -100,7 +100,7 @@ require ( github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 // indirect - github.com/opencontainers/runc v1.0.2 // indirect + github.com/opencontainers/runc v1.1.2 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index 3290d9cd..c2a781ae 100644 --- a/go.sum +++ b/go.sum @@ -131,6 +131,8 @@ github.com/ccding/go-stun/stun v0.0.0-20200514191101-4dc67bcdb029 h1:POmUHfxXdey github.com/ccding/go-stun/stun v0.0.0-20200514191101-4dc67bcdb029/go.mod h1:Rpr5n9cGHYdM3S3IK8ROSUUUYjQOu+MSUCZDcJbYWi8= github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -139,10 +141,12 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/cilium/ebpf v0.8.1 h1:bLSSEbBLqGPXxls55pGr5qWZaTqcmfDJHhou7t254ao= github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -159,8 +163,11 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 h1:NmTXa/uVnDyp0TY5MKi197+3HWcnYWfnHGyaFthlnGw= github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc/v3 v3.1.0 h1:6avEvcdvTa1qYsOZ6I5PRkSYHzpTNWgKYmaJfaYbrRw= @@ -184,6 +191,7 @@ github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/daixiang0/gci v0.2.9/go.mod h1:+4dZ7TISfSmqfAGv59ePaHfNzgGtIkHAhhdKggP1JAc= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -271,6 +279,7 @@ github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2 github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= @@ -667,6 +676,7 @@ github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -710,11 +720,16 @@ github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 h1:+cz github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198/go.mod h1:j4h1pJW6ZcJTgMZWP3+7RlG3zTaP02aDZ/Qw0sppK7Q= github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runc v1.1.2 h1:2VSZwLx5k/BfsBxMMipG/LYUnmqOD/BPkIVgQUcTlLw= +github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/ory/dockertest/v3 v3.8.1 h1:vU/8d1We4qIad2YM0kOwRVtnyue7ExvacPiw1yDm17g= github.com/ory/dockertest/v3 v3.8.1/go.mod h1:wSRQ3wmkz+uSARYMk7kVJFDBGm8x5gSxIhI7NDc+BAQ= +github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= +github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= @@ -820,6 +835,7 @@ github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dms github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/securego/gosec/v2 v2.9.1/go.mod h1:oDcDLcatOJxkCGaCaq8lua1jTnYf6Sou4wdiJ1n4iHc= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= @@ -1222,6 +1238,8 @@ golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 75af83bb81439c1a454fc6a4ffad4095744fadd0 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Tue, 26 Jul 2022 12:11:15 +0200 Subject: [PATCH 33/33] Update checksum for nix --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index f9f3c83d..ec83d41c 100644 --- a/flake.nix +++ b/flake.nix @@ -24,7 +24,7 @@ # When updating go.mod or go.sum, a new sha will need to be calculated, # update this if you have a mismatch after doing a change to thos files. - vendorSha256 = "sha256-b9C6F+7N0ecW0HiTx+rztZnxb+n6U6YTSOJvp3GqnWQ="; + vendorSha256 = "sha256-2o78hsi0B9U5NOcYXRqkBmg34p71J/R8FibXsgwEcSo="; ldflags = [ "-s" "-w" "-X github.com/juanfont/headscale/cmd/headscale/cli.Version=v${version}" ]; };