From 93082b809267b8f543452a336f9d8e69c35348fb Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 23 Sep 2022 10:39:42 +0200 Subject: [PATCH 01/55] Protect against user injection for registration CLI page This commit addresses a potential issue where we allowed unsanitised content to be passed through a go template without validation. We now try to unmarshall the incoming node key and fails to render the template if it is not a valid node key. Signed-off-by: Kristoffer Dalby --- api.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/api.go b/api.go index f5de5038..23aa7c5a 100644 --- a/api.go +++ b/api.go @@ -9,6 +9,7 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog/log" + "tailscale.com/types/key" ) const ( @@ -93,7 +94,18 @@ func (h *Headscale) RegisterWebAPI( ) { vars := mux.Vars(req) nodeKeyStr, ok := vars["nkey"] - if !ok || nodeKeyStr == "" { + + // We need to make sure we dont open for XSS style injections, if the parameter that + // is passed as a key is not parsable/validated as a NodePublic key, then fail to render + // the template and log an error. + var nodeKey key.NodePublic + err := nodeKey.UnmarshalText( + []byte(NodePublicKeyEnsurePrefix(nodeKeyStr)), + ) + + if !ok || nodeKeyStr == "" || err != nil { + log.Warn().Err(err).Msg("Failed to parse incoming nodekey") + writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) _, err := writer.Write([]byte("Wrong params")) @@ -130,7 +142,7 @@ func (h *Headscale) RegisterWebAPI( writer.Header().Set("Content-Type", "text/html; charset=utf-8") writer.WriteHeader(http.StatusOK) - _, err := writer.Write(content.Bytes()) + _, err = writer.Write(content.Bytes()) if err != nil { log.Error(). Caller(). From 75a8fc8b3e503d1c9d5eaeb481b689351cbbc97e Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 23 Sep 2022 10:44:29 +0200 Subject: [PATCH 02/55] Update changelog Signed-off-by: Kristoffer Dalby --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 443305da..2b4f6260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - Give a warning when running Headscale with reverse proxy improperly configured for WebSockets [#788](https://github.com/juanfont/headscale/pull/788) - Fix subnet routers with Primary Routes [#811](https://github.com/juanfont/headscale/pull/811) - Added support for JSON logs [#653](https://github.com/juanfont/headscale/issues/653) +- Sanitise the node key passed to registration url [#823](https://github.com/juanfont/headscale/pull/823) ## 0.16.4 (2022-08-21) From 2bb34751d19dcdfdf188db437e93a75ed9b6c14a Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 23 Sep 2022 11:51:38 +0200 Subject: [PATCH 03/55] Validate the incoming nodekey with regex before attempting to parse Signed-off-by: Kristoffer Dalby --- api.go | 16 ++++++++++++++++ utils.go | 3 +++ 2 files changed, 19 insertions(+) diff --git a/api.go b/api.go index 23aa7c5a..4c3a6ca8 100644 --- a/api.go +++ b/api.go @@ -95,6 +95,22 @@ func (h *Headscale) RegisterWebAPI( vars := mux.Vars(req) nodeKeyStr, ok := vars["nkey"] + if !NodePublicKeyRegex.Match([]byte(nodeKeyStr)) { + log.Warn().Str("node_key", nodeKeyStr).Msg("Invalid node key passed to registration url") + + writer.Header().Set("Content-Type", "text/plain; charset=utf-8") + writer.WriteHeader(http.StatusUnauthorized) + _, err := writer.Write([]byte("Unauthorized")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } + + return + } + // We need to make sure we dont open for XSS style injections, if the parameter that // is passed as a key is not parsable/validated as a NodePublic key, then fail to render // the template and log an error. diff --git a/utils.go b/utils.go index 666683cf..7ef054de 100644 --- a/utils.go +++ b/utils.go @@ -17,6 +17,7 @@ import ( "os" "path/filepath" "reflect" + "regexp" "strconv" "strings" @@ -64,6 +65,8 @@ const ( ZstdCompression = "zstd" ) +var NodePublicKeyRegex = regexp.MustCompile("nodekey:[a-fA-F0-9]+") + func MachinePublicKeyStripPrefix(machineKey key.MachinePublic) string { return strings.TrimPrefix(machineKey.String(), machinePublicHexPrefix) } From 8be14ef6feb160bf67f83be54624d0a83af95a16 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 23 Sep 2022 11:51:46 +0200 Subject: [PATCH 04/55] gofumpt Signed-off-by: Kristoffer Dalby --- utils.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils.go b/utils.go index 7ef054de..fc1fafa2 100644 --- a/utils.go +++ b/utils.go @@ -328,7 +328,9 @@ func GenerateRandomStringDNSSafe(size int) (string, error) { if err != nil { return "", err } - str = strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(str, "_", ""), "-", "")) + str = strings.ToLower( + strings.ReplaceAll(strings.ReplaceAll(str, "_", ""), "-", ""), + ) } return str[:size], nil From 6b67584d477946cd83b8fa70d9cb3e4ce53703d7 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 3 Oct 2022 13:27:18 +0200 Subject: [PATCH 05/55] Fix DERP name in integration tests Signed-off-by: Kristoffer Dalby --- integration_common_test.go | 2 +- integration_embedded_derp_test.go | 5 +++-- integration_general_test.go | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/integration_common_test.go b/integration_common_test.go index 9cce12fa..a72af91f 100644 --- a/integration_common_test.go +++ b/integration_common_test.go @@ -19,7 +19,7 @@ import ( ) const ( - headscaleHostname = "headscale-derp" + headscaleHostname = "headscale" DOCKER_EXECUTE_TIMEOUT = 10 * time.Second ) diff --git a/integration_embedded_derp_test.go b/integration_embedded_derp_test.go index a31006e1..4a8a337f 100644 --- a/integration_embedded_derp_test.go +++ b/integration_embedded_derp_test.go @@ -27,6 +27,7 @@ import ( ) const ( + headscaleDerpHostname = "headscale-derp" namespaceName = "derpnamespace" totalContainers = 3 ) @@ -112,7 +113,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { } headscaleOptions := &dockertest.RunOptions{ - Name: headscaleHostname, + Name: headscaleDerpHostname, Mounts: []string{ fmt.Sprintf( "%s/integration_test/etc_embedded_derp:/etc/headscale", @@ -127,7 +128,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { }, } - err = s.pool.RemoveContainerByName(headscaleHostname) + err = s.pool.RemoveContainerByName(headscaleDerpHostname) if err != nil { s.FailNow( fmt.Sprintf( diff --git a/integration_general_test.go b/integration_general_test.go index 5abdccbb..2f61cfe9 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -236,7 +236,7 @@ func (s *IntegrationTestSuite) SetupSuite() { } headscaleOptions := &dockertest.RunOptions{ - Name: "headscale", + Name: headscaleHostname, Mounts: []string{ fmt.Sprintf("%s/integration_test/etc:/etc/headscale", currentPath), }, From 4904ccc3c3598a391d46e9150f6f84d6e92156a4 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 3 Oct 2022 13:39:57 +0200 Subject: [PATCH 06/55] Make sure mock container is removed before started Signed-off-by: Kristoffer Dalby --- integration_oidc_test.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/integration_oidc_test.go b/integration_oidc_test.go index 70f793b2..55b87fd8 100644 --- a/integration_oidc_test.go +++ b/integration_oidc_test.go @@ -25,7 +25,8 @@ import ( ) const ( - oidcHeadscaleHostname = "headscale" + oidcHeadscaleHostname = "headscale-oidc" + oidcMockHostname = "headscale-mock-oidc" oidcNamespaceName = "oidcnamespace" totalOidcContainers = 3 ) @@ -113,8 +114,7 @@ func (s *IntegrationOIDCTestSuite) SetupSuite() { s.Suite.T().Log("Setting up mock OIDC") mockOidcOptions := &dockertest.RunOptions{ - Name: "mockoidc", - Hostname: "mockoidc", + Name: oidcMockHostname, Cmd: []string{"headscale", "mockoidc"}, ExposedPorts: []string{"10000/tcp"}, Networks: []*dockertest.Network{&s.network}, @@ -133,6 +133,18 @@ func (s *IntegrationOIDCTestSuite) SetupSuite() { ContextDir: ".", } + err = s.pool.RemoveContainerByName(oidcMockHostname) + if err != nil { + s.FailNow( + fmt.Sprintf( + "Could not remove existing container before building test: %s", + err, + ), + "", + ) + } + + if pmockoidc, err := s.pool.BuildAndRunWithBuildOptions( headscaleBuildOptions, mockOidcOptions, From 201f81ce00a34c867ecc229fbbae4f32aa626cb8 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 3 Oct 2022 14:40:28 +0200 Subject: [PATCH 07/55] Make sure mockoidc is up, has unique name and removed if exist Signed-off-by: Kristoffer Dalby --- cmd/headscale/cli/mockoidc.go | 2 +- integration_general_test.go | 11 +++++++++++ integration_oidc_test.go | 30 +++++++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/cmd/headscale/cli/mockoidc.go b/cmd/headscale/cli/mockoidc.go index 4313bbf6..8f9c904a 100644 --- a/cmd/headscale/cli/mockoidc.go +++ b/cmd/headscale/cli/mockoidc.go @@ -61,7 +61,7 @@ func mockOIDC() error { return err } - listener, err := net.Listen("tcp", fmt.Sprintf("mockoidc:%d", port)) + listener, err := net.Listen("tcp", fmt.Sprintf("headscale-mock-oidc:%d", port)) if err != nil { return err } diff --git a/integration_general_test.go b/integration_general_test.go index 2f61cfe9..5bfebe1d 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -191,6 +191,17 @@ func (s *IntegrationTestSuite) tailscaleContainer( }, } + err = s.pool.RemoveContainerByName(hostname) + if err != nil { + s.FailNow( + fmt.Sprintf( + "Could not remove existing container before building test: %s", + err, + ), + "", + ) + } + pts, err := s.pool.BuildAndRunWithBuildOptions( tailscaleBuildOptions, tailscaleOptions, diff --git a/integration_oidc_test.go b/integration_oidc_test.go index 55b87fd8..3f9a7a9e 100644 --- a/integration_oidc_test.go +++ b/integration_oidc_test.go @@ -144,7 +144,6 @@ func (s *IntegrationOIDCTestSuite) SetupSuite() { ) } - if pmockoidc, err := s.pool.BuildAndRunWithBuildOptions( headscaleBuildOptions, mockOidcOptions, @@ -154,6 +153,31 @@ func (s *IntegrationOIDCTestSuite) SetupSuite() { s.FailNow(fmt.Sprintf("Could not start mockOIDC container: %s", err), "") } + s.Suite.T().Logf("Waiting for headscale mock oidc to be ready for tests") + hostEndpoint := fmt.Sprintf("localhost:%s", s.mockOidc.GetPort("10000/tcp")) + + if err := s.pool.Retry(func() error { + url := fmt.Sprintf("http://%s/oidc/.well-known/openid-configuration", hostEndpoint) + resp, err := http.Get(url) + if err != nil { + log.Printf("headscale mock OIDC tests is not ready: %s\n", err) + return err + } + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("status code not OK") + } + + return nil + }); err != nil { + // TODO(kradalby): If we cannot access headscale, or any other fatal error during + // test setup, we need to abort and tear down. However, testify does not seem to + // support that at the moment: + // https://github.com/stretchr/testify/issues/849 + return // fmt.Errorf("Could not connect to headscale: %s", err) + } + s.Suite.T().Log("headscale-mock-oidc container is ready for embedded OIDC tests") + oidcCfg := fmt.Sprintf(` oidc: issuer: http://%s:10000/oidc @@ -228,10 +252,10 @@ oidc: } s.Suite.T().Logf("Waiting for headscale to be ready for embedded OIDC tests") - hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8443/tcp")) + hostMockEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8443/tcp")) if err := s.pool.Retry(func() error { - url := fmt.Sprintf("https://%s/health", hostEndpoint) + url := fmt.Sprintf("https://%s/health", hostMockEndpoint) insecureTransport := http.DefaultTransport.(*http.Transport).Clone() insecureTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} client := &http.Client{Transport: insecureTransport} From 382a37f1e16a51b35d7975415b96a3e50274068c Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 3 Oct 2022 14:41:20 +0200 Subject: [PATCH 08/55] Test against last patch version Signed-off-by: Kristoffer Dalby --- integration_common_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration_common_test.go b/integration_common_test.go index a72af91f..de85a3bd 100644 --- a/integration_common_test.go +++ b/integration_common_test.go @@ -32,7 +32,7 @@ var ( tailscaleVersions = []string{ // "head", // "unstable", - "1.30.0", + "1.30.2", "1.28.0", "1.26.2", "1.24.2", From 37a4d41d0ef729daf195f6bda4f6d95781940727 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 3 Oct 2022 15:37:41 +0200 Subject: [PATCH 09/55] Make addr configurable Signed-off-by: Kristoffer Dalby --- cmd/headscale/cli/mockoidc.go | 6 +++++- integration_oidc_test.go | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/cmd/headscale/cli/mockoidc.go b/cmd/headscale/cli/mockoidc.go index 8f9c904a..165a5115 100644 --- a/cmd/headscale/cli/mockoidc.go +++ b/cmd/headscale/cli/mockoidc.go @@ -46,6 +46,10 @@ func mockOIDC() error { if clientSecret == "" { return errMockOidcClientSecretNotDefined } + addrStr := os.Getenv("MOCKOIDC_ADDR") + if addrStr == "" { + return errMockOidcPortNotDefined + } portStr := os.Getenv("MOCKOIDC_PORT") if portStr == "" { return errMockOidcPortNotDefined @@ -61,7 +65,7 @@ func mockOIDC() error { return err } - listener, err := net.Listen("tcp", fmt.Sprintf("headscale-mock-oidc:%d", port)) + listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addrStr, port)) if err != nil { return err } diff --git a/integration_oidc_test.go b/integration_oidc_test.go index 3f9a7a9e..4d3b39e1 100644 --- a/integration_oidc_test.go +++ b/integration_oidc_test.go @@ -122,6 +122,7 @@ func (s *IntegrationOIDCTestSuite) SetupSuite() { "10000/tcp": {{HostPort: "10000"}}, }, Env: []string{ + fmt.Sprintf("MOCKOIDC_ADDR=%s", oidcMockHostname), "MOCKOIDC_PORT=10000", "MOCKOIDC_CLIENT_ID=superclient", "MOCKOIDC_CLIENT_SECRET=supersecret", @@ -330,6 +331,8 @@ func (s *IntegrationOIDCTestSuite) AuthenticateOIDC( resp, err := client.Get(loginURL.String()) assert.Nil(s.T(), err) + log.Printf("auth body, err: %#v, %s", resp, err) + body, err := io.ReadAll(resp.Body) assert.Nil(s.T(), err) From a0ec3690b6ea49c2343f8dcd975868811e921ec0 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 3 Oct 2022 16:02:34 +0200 Subject: [PATCH 10/55] Fix error declaration Signed-off-by: Kristoffer Dalby --- integration_general_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration_general_test.go b/integration_general_test.go index 5bfebe1d..7185c606 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -191,7 +191,7 @@ func (s *IntegrationTestSuite) tailscaleContainer( }, } - err = s.pool.RemoveContainerByName(hostname) + err := s.pool.RemoveContainerByName(hostname) if err != nil { s.FailNow( fmt.Sprintf( @@ -202,7 +202,7 @@ func (s *IntegrationTestSuite) tailscaleContainer( ) } - pts, err := s.pool.BuildAndRunWithBuildOptions( + pts, err = s.pool.BuildAndRunWithBuildOptions( tailscaleBuildOptions, tailscaleOptions, DockerRestartPolicy, From aca3a667c49803fcb92052aa3a8a6648cdc99117 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 3 Oct 2022 16:15:39 +0200 Subject: [PATCH 11/55] Fix declaration of pointer Signed-off-by: Kristoffer Dalby --- integration_general_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration_general_test.go b/integration_general_test.go index 7185c606..1f0e8be6 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -202,7 +202,7 @@ func (s *IntegrationTestSuite) tailscaleContainer( ) } - pts, err = s.pool.BuildAndRunWithBuildOptions( + pts, err := s.pool.BuildAndRunWithBuildOptions( tailscaleBuildOptions, tailscaleOptions, DockerRestartPolicy, From 85df2c80a84860290901a249f2cf081e876e66e1 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 7 Oct 2022 10:45:23 +0200 Subject: [PATCH 12/55] Run oidc tests fully in docker Signed-off-by: Kristoffer Dalby --- Makefile | 4 ++- integration_common_test.go | 19 ++++++++++++ integration_oidc_test.go | 36 ++++++++++++---------- integration_test/etc_oidc/base_config.yaml | 2 +- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 84cb63cf..33fc1b50 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,9 @@ test_integration_general: go test -failfast -tags integration_general,integration -timeout 30m -count=1 ./... test_integration_oidc: - go test -failfast -tags integration_oidc,integration -timeout 30m -count=1 ./... + docker network rm $$(docker network ls --filter name=headscale --quiet) || true + docker network create headscale-test || true + docker run -it --rm --network headscale-test -v $$PWD:$$PWD -w $$PWD -v /var/run/docker.sock:/var/run/docker.sock golang:1 go test -failfast -tags integration_oidc,integration -timeout 30m -count=1 ./... coverprofile_func: go tool cover -func=coverage.out diff --git a/integration_common_test.go b/integration_common_test.go index de85a3bd..a11c5b13 100644 --- a/integration_common_test.go +++ b/integration_common_test.go @@ -316,3 +316,22 @@ func GetEnvBool(key string) (bool, error) { return v, nil } + +func GetFirstOrCreateNetwork(pool *dockertest.Pool, name string) (dockertest.Network, error) { + networks, err := pool.NetworksByName(name) + if err != nil || len(networks) == 0 { + + if _, err := pool.CreateNetwork(name); err == nil { + // Create does not give us an updated version of the resource, so we need to + // get it again. + networks, err := pool.NetworksByName(name) + if err != nil { + return dockertest.Network{}, err + } + + return networks[0], nil + } + } + + return networks[0], nil +} diff --git a/integration_oidc_test.go b/integration_oidc_test.go index 4d3b39e1..b438a41b 100644 --- a/integration_oidc_test.go +++ b/integration_oidc_test.go @@ -26,7 +26,7 @@ import ( const ( oidcHeadscaleHostname = "headscale-oidc" - oidcMockHostname = "headscale-mock-oidc" + oidcMockHostname = "headscale-mock-oidc" oidcNamespaceName = "oidcnamespace" totalOidcContainers = 3 ) @@ -96,19 +96,11 @@ func (s *IntegrationOIDCTestSuite) SetupSuite() { 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 { - s.FailNow(fmt.Sprintf("Could not create network: %s", err), "") - } - - // Create does not give us an updated version of the resource, so we need to - // get it again. - networks, err := s.pool.NetworksByName("headscale-test") + network, err := GetFirstOrCreateNetwork(&s.pool, "headscale-test") if err != nil { - s.FailNow(fmt.Sprintf("Could not get network: %s", err), "") + s.FailNow(fmt.Sprintf("Failed to create or get network: %s", err), "") } - s.network = networks[0] + s.network = network log.Printf("Network config: %v", s.network.Network.IPAM.Config[0]) @@ -155,7 +147,11 @@ func (s *IntegrationOIDCTestSuite) SetupSuite() { } s.Suite.T().Logf("Waiting for headscale mock oidc to be ready for tests") - hostEndpoint := fmt.Sprintf("localhost:%s", s.mockOidc.GetPort("10000/tcp")) + hostEndpoint := fmt.Sprintf( + "%s:%s", + s.mockOidc.GetIPInNetwork(&s.network), + s.mockOidc.GetPort("10000/tcp"), + ) if err := s.pool.Retry(func() error { url := fmt.Sprintf("http://%s/oidc/.well-known/openid-configuration", hostEndpoint) @@ -253,7 +249,11 @@ oidc: } s.Suite.T().Logf("Waiting for headscale to be ready for embedded OIDC tests") - hostMockEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8443/tcp")) + hostMockEndpoint := fmt.Sprintf( + "%s:%s", + s.headscale.GetIPInNetwork(&s.network), + s.headscale.GetPort("8443/tcp"), + ) if err := s.pool.Retry(func() error { url := fmt.Sprintf("https://%s/health", hostMockEndpoint) @@ -347,7 +347,6 @@ func (s *IntegrationOIDCTestSuite) joinOIDC( endpoint, hostname string, tailscale dockertest.Resource, ) (*url.URL, error) { - command := []string{ "tailscale", "up", @@ -536,7 +535,12 @@ func (s *IntegrationOIDCTestSuite) TestPingAllPeersByAddress() { []string{}, ) assert.Nil(t, err) - log.Printf("result for %s: stdout: %s, stderr: %s\n", hostname, stdout, stderr) + log.Printf( + "result for %s: stdout: %s, stderr: %s\n", + hostname, + stdout, + stderr, + ) assert.Contains(t, stdout, "pong") }) } diff --git a/integration_test/etc_oidc/base_config.yaml b/integration_test/etc_oidc/base_config.yaml index 10fa7751..7db58a2a 100644 --- a/integration_test/etc_oidc/base_config.yaml +++ b/integration_test/etc_oidc/base_config.yaml @@ -11,7 +11,7 @@ private_key_path: private.key noise: private_key_path: noise_private.key listen_addr: 0.0.0.0:8443 -server_url: https://localhost:8443 +server_url: https://headscale-oidc:8443 tls_cert_path: "/etc/headscale/tls/server.crt" tls_key_path: "/etc/headscale/tls/server.key" tls_client_auth_mode: disabled From f3dbfc9045ca5f49c80e90cbe15770d3c2d00b94 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 7 Oct 2022 10:45:41 +0200 Subject: [PATCH 13/55] Style change Signed-off-by: Kristoffer Dalby --- integration_common_test.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/integration_common_test.go b/integration_common_test.go index a11c5b13..1d69972b 100644 --- a/integration_common_test.go +++ b/integration_common_test.go @@ -115,13 +115,19 @@ func ExecuteCommand( fmt.Println("stdout: ", stdout.String()) fmt.Println("stderr: ", stderr.String()) - return stdout.String(), stderr.String(), fmt.Errorf("command failed with: %s", stderr.String()) + return stdout.String(), stderr.String(), fmt.Errorf( + "command failed with: %s", + stderr.String(), + ) } return stdout.String(), stderr.String(), nil case <-time.After(execConfig.timeout): - return stdout.String(), stderr.String(), fmt.Errorf("command timed out after %s", execConfig.timeout) + return stdout.String(), stderr.String(), fmt.Errorf( + "command timed out after %s", + execConfig.timeout, + ) } } From 88931001fd996ae50b198407fceb8f9ff36279e2 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 7 Oct 2022 10:45:51 +0200 Subject: [PATCH 14/55] Fail correctly if container exist Signed-off-by: Kristoffer Dalby --- integration_oidc_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/integration_oidc_test.go b/integration_oidc_test.go index b438a41b..dd3c99dd 100644 --- a/integration_oidc_test.go +++ b/integration_oidc_test.go @@ -412,7 +412,13 @@ func (s *IntegrationOIDCTestSuite) tailscaleContainer( DockerAllowNetworkAdministration, ) if err != nil { - log.Fatalf("Could not start tailscale container version %s: %s", version, err) + s.FailNow( + fmt.Sprintf( + "Could not start tailscale container version %s: %s", + version, + err, + ), + ) } log.Printf("Created %s container\n", hostname) From 22cabc16d7ce39671ff7e887dc2f6392e4dac290 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 7 Oct 2022 10:56:22 +0200 Subject: [PATCH 15/55] No interactive tty Signed-off-by: Kristoffer Dalby --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 33fc1b50..0369435e 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ test_integration_general: test_integration_oidc: docker network rm $$(docker network ls --filter name=headscale --quiet) || true docker network create headscale-test || true - docker run -it --rm --network headscale-test -v $$PWD:$$PWD -w $$PWD -v /var/run/docker.sock:/var/run/docker.sock golang:1 go test -failfast -tags integration_oidc,integration -timeout 30m -count=1 ./... + docker run -t --rm --network headscale-test -v $$PWD:$$PWD -w $$PWD -v /var/run/docker.sock:/var/run/docker.sock golang:1 go test -failfast -tags integration_oidc,integration -timeout 30m -count=1 ./... coverprofile_func: go tool cover -func=coverage.out From a94ed0586e0b93c2f8fdd86495189fd0c244bfe5 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 7 Oct 2022 13:23:40 +0200 Subject: [PATCH 16/55] Run all integration tests fully in docker Signed-off-by: Kristoffer Dalby --- Makefile | 30 ++++++++++++++++++++---- integration_embedded_derp_test.go | 38 ++++++++++++++++++++----------- integration_general_test.go | 4 +++- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 0369435e..eeac2805 100644 --- a/Makefile +++ b/Makefile @@ -27,18 +27,40 @@ test: test_integration: test_integration_cli test_integration_derp test_integration_oidc test_integration_general test_integration_cli: - go test -failfast -tags integration_cli,integration -timeout 30m -count=1 ./... + docker network rm $$(docker network ls --filter name=headscale --quiet) || true + docker network create headscale-test || true + docker run -t --rm \ + --network headscale-test \ + -v $$PWD:$$PWD -w $$PWD \ + -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ + go test -failfast -tags integration_cli,integration -timeout 30m -count=1 ./... test_integration_derp: - go test -failfast -tags integration_derp,integration -timeout 30m -count=1 ./... + docker network rm $$(docker network ls --filter name=headscale --quiet) || true + docker network create headscale-test || true + docker run -t --rm \ + --network headscale-test \ + -v $$PWD:$$PWD -w $$PWD \ + -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ + go test -failfast -tags integration_derp,integration -timeout 30m -count=1 ./... test_integration_general: - go test -failfast -tags integration_general,integration -timeout 30m -count=1 ./... + docker network rm $$(docker network ls --filter name=headscale --quiet) || true + docker network create headscale-test || true + docker run -t --rm \ + --network headscale-test \ + -v $$PWD:$$PWD -w $$PWD \ + -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ + go test -failfast -tags integration_general,integration -timeout 30m -count=1 ./... test_integration_oidc: docker network rm $$(docker network ls --filter name=headscale --quiet) || true docker network create headscale-test || true - docker run -t --rm --network headscale-test -v $$PWD:$$PWD -w $$PWD -v /var/run/docker.sock:/var/run/docker.sock golang:1 go test -failfast -tags integration_oidc,integration -timeout 30m -count=1 ./... + docker run -t --rm \ + --network headscale-test \ + -v $$PWD:$$PWD -w $$PWD \ + -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ + go test -failfast -tags integration_oidc,integration -timeout 30m -count=1 ./... coverprofile_func: go tool cover -func=coverage.out diff --git a/integration_embedded_derp_test.go b/integration_embedded_derp_test.go index 4a8a337f..421e01d0 100644 --- a/integration_embedded_derp_test.go +++ b/integration_embedded_derp_test.go @@ -28,18 +28,19 @@ import ( const ( headscaleDerpHostname = "headscale-derp" - namespaceName = "derpnamespace" - totalContainers = 3 + namespaceName = "derpnamespace" + totalContainers = 3 ) type IntegrationDERPTestSuite struct { suite.Suite stats *suite.SuiteInformation - pool dockertest.Pool - networks map[int]dockertest.Network // so we keep the containers isolated - headscale dockertest.Resource - saveLogs bool + pool dockertest.Pool + network dockertest.Network + containerNetworks map[int]dockertest.Network // so we keep the containers isolated + headscale dockertest.Resource + saveLogs bool tailscales map[string]dockertest.Resource joinWaitGroup sync.WaitGroup @@ -54,7 +55,7 @@ func TestDERPIntegrationTestSuite(t *testing.T) { s := new(IntegrationDERPTestSuite) s.tailscales = make(map[string]dockertest.Resource) - s.networks = make(map[int]dockertest.Network) + s.containerNetworks = make(map[int]dockertest.Network) s.saveLogs = saveLogs suite.Run(t, s) @@ -79,7 +80,7 @@ func TestDERPIntegrationTestSuite(t *testing.T) { log.Printf("Could not purge resource: %s\n", err) } - for _, network := range s.networks { + for _, network := range s.containerNetworks { if err := network.Close(); err != nil { log.Printf("Could not close network: %s\n", err) } @@ -94,9 +95,15 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { s.FailNow(fmt.Sprintf("Could not connect to docker: %s", err), "") } + network, err := GetFirstOrCreateNetwork(&s.pool, "headscale-test") + if err != nil { + s.FailNow(fmt.Sprintf("Failed to create or get network: %s", err), "") + } + s.network = network + for i := 0; i < totalContainers; i++ { if pnetwork, err := s.pool.CreateNetwork(fmt.Sprintf("headscale-derp-%d", i)); err == nil { - s.networks[i] = *pnetwork + s.containerNetworks[i] = *pnetwork } else { s.FailNow(fmt.Sprintf("Could not create network: %s", err), "") } @@ -121,6 +128,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { ), }, Cmd: []string{"headscale", "serve"}, + Networks: []*dockertest.Network{&s.network}, ExposedPorts: []string{"8443/tcp", "3478/udp"}, PortBindings: map[docker.Port][]docker.PortBinding{ "8443/tcp": {{HostPort: "8443"}}, @@ -154,13 +162,15 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { hostname, container := s.tailscaleContainer( fmt.Sprint(i), version, - s.networks[i], + s.containerNetworks[i], ) s.tailscales[hostname] = *container } log.Println("Waiting for headscale to be ready for embedded DERP tests") - hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8443/tcp")) + hostEndpoint := fmt.Sprintf("%s:%s", + s.headscale.GetIPInNetwork(&s.network), + s.headscale.GetPort("8443/tcp")) if err := s.pool.Retry(func() error { url := fmt.Sprintf("https://%s/health", hostEndpoint) @@ -321,7 +331,7 @@ func (s *IntegrationDERPTestSuite) TearDownSuite() { log.Printf("Could not purge resource: %s\n", err) } - for _, network := range s.networks { + for _, network := range s.containerNetworks { if err := network.Close(); err != nil { log.Printf("Could not close network: %s\n", err) } @@ -429,7 +439,9 @@ func (s *IntegrationDERPTestSuite) TestPingAllPeersByHostname() { } func (s *IntegrationDERPTestSuite) TestDERPSTUN() { - headscaleSTUNAddr := fmt.Sprintf("localhost:%s", s.headscale.GetPort("3478/udp")) + headscaleSTUNAddr := fmt.Sprintf("%s:%s", + s.headscale.GetIPInNetwork(&s.network), + s.headscale.GetPort("3478/udp")) client := stun.NewClient() client.SetVerbose(true) client.SetVVerbose(true) diff --git a/integration_general_test.go b/integration_general_test.go index 1f0e8be6..d24c4d95 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -289,7 +289,9 @@ func (s *IntegrationTestSuite) SetupSuite() { } log.Println("Waiting for headscale to be ready for core integration tests") - hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8080/tcp")) + hostEndpoint := fmt.Sprintf("%s:%s", + s.headscale.GetIPInNetwork(&s.network), + s.headscale.GetPort("8080/tcp")) if err := s.pool.Retry(func() error { url := fmt.Sprintf("http://%s/health", hostEndpoint) From ed2236aa24a8c375f8b8c9d3574b8f1017e323f2 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 7 Oct 2022 13:49:24 +0200 Subject: [PATCH 17/55] Add buildtags to pls Signed-off-by: Kristoffer Dalby --- flake.nix | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 050fd747..f7d0c669 100644 --- a/flake.nix +++ b/flake.nix @@ -128,7 +128,13 @@ }; in rec { # `nix develop` - devShell = pkgs.mkShell {buildInputs = devDeps;}; + devShell = pkgs.mkShell { + buildInputs = devDeps; + + shellHook = '' + export GOFLAGS=-tags="integration,integration_general,integration_oidc,integration_cli,integration_derp" + ''; + }; # `nix build` packages = with pkgs; { From a846e13c78b29e93ea2e11a80572d2d928b012ab Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 7 Oct 2022 14:29:21 +0200 Subject: [PATCH 18/55] Expose and use ports consistently Signed-off-by: Kristoffer Dalby --- integration_cli_test.go | 9 ++++++++- integration_general_test.go | 4 ++++ integration_oidc_test.go | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/integration_cli_test.go b/integration_cli_test.go index bf302d2d..cc9d33b2 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -13,6 +13,7 @@ import ( v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -63,6 +64,10 @@ func (s *IntegrationCLITestSuite) SetupTest() { Mounts: []string{ fmt.Sprintf("%s/integration_test/etc:/etc/headscale", currentPath), }, + ExposedPorts: []string{"8080/tcp"}, + PortBindings: map[docker.Port][]docker.PortBinding{ + "8080/tcp": {{HostPort: "8080"}}, + }, Networks: []*dockertest.Network{&s.network}, Cmd: []string{"headscale", "serve"}, } @@ -87,7 +92,9 @@ func (s *IntegrationCLITestSuite) SetupTest() { fmt.Println("Created headscale container for CLI tests") fmt.Println("Waiting for headscale to be ready for CLI tests") - hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8080/tcp")) + hostEndpoint := fmt.Sprintf("%s:%s", + s.headscale.GetIPInNetwork(&s.network), + s.headscale.GetPort("8080/tcp")) if err := s.pool.Retry(func() error { url := fmt.Sprintf("http://%s/health", hostEndpoint) diff --git a/integration_general_test.go b/integration_general_test.go index d24c4d95..4087c9db 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -189,6 +189,10 @@ func (s *IntegrationTestSuite) tailscaleContainer( Cmd: []string{ "tailscaled", "--tun=tsdev", }, + ExposedPorts: []string{"8080/tcp"}, + PortBindings: map[docker.Port][]docker.PortBinding{ + "8080/tcp": {{HostPort: "8080"}}, + }, } err := s.pool.RemoveContainerByName(hostname) diff --git a/integration_oidc_test.go b/integration_oidc_test.go index dd3c99dd..27c1e7bc 100644 --- a/integration_oidc_test.go +++ b/integration_oidc_test.go @@ -109,10 +109,10 @@ func (s *IntegrationOIDCTestSuite) SetupSuite() { Name: oidcMockHostname, Cmd: []string{"headscale", "mockoidc"}, ExposedPorts: []string{"10000/tcp"}, - Networks: []*dockertest.Network{&s.network}, PortBindings: map[docker.Port][]docker.PortBinding{ "10000/tcp": {{HostPort: "10000"}}, }, + Networks: []*dockertest.Network{&s.network}, Env: []string{ fmt.Sprintf("MOCKOIDC_ADDR=%s", oidcMockHostname), "MOCKOIDC_PORT=10000", From d900f48d38ae145b009bd683a0f4d71fc0a6efb1 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 7 Oct 2022 14:39:49 +0200 Subject: [PATCH 19/55] expose right porsts Signed-off-by: Kristoffer Dalby --- integration_general_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/integration_general_test.go b/integration_general_test.go index 4087c9db..500247df 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -189,10 +189,6 @@ func (s *IntegrationTestSuite) tailscaleContainer( Cmd: []string{ "tailscaled", "--tun=tsdev", }, - ExposedPorts: []string{"8080/tcp"}, - PortBindings: map[docker.Port][]docker.PortBinding{ - "8080/tcp": {{HostPort: "8080"}}, - }, } err := s.pool.RemoveContainerByName(hostname) @@ -255,6 +251,10 @@ func (s *IntegrationTestSuite) SetupSuite() { Mounts: []string{ fmt.Sprintf("%s/integration_test/etc:/etc/headscale", currentPath), }, + ExposedPorts: []string{"8080/tcp"}, + PortBindings: map[docker.Port][]docker.PortBinding{ + "8080/tcp": {{HostPort: "8080"}}, + }, Networks: []*dockertest.Network{&s.network}, Cmd: []string{"headscale", "serve"}, } From 8ee35c9c226cfe6ed8ae8b46bc6be3a96810a223 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 7 Oct 2022 22:10:33 +0200 Subject: [PATCH 20/55] Stuff Signed-off-by: Kristoffer Dalby --- integration_cli_test.go | 12 ++++++------ integration_common_test.go | 1 + integration_embedded_derp_test.go | 3 ++- integration_general_test.go | 8 ++++---- integration_oidc_test.go | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/integration_cli_test.go b/integration_cli_test.go index cc9d33b2..0f5d69ad 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -43,11 +43,11 @@ func (s *IntegrationCLITestSuite) SetupTest() { 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 { - s.FailNow(fmt.Sprintf("Could not create network: %s", err), "") + network, err := GetFirstOrCreateNetwork(&s.pool, headscaleNetwork) + if err != nil { + s.FailNow(fmt.Sprintf("Failed to create or get network: %s", err), "") } + s.network = network headscaleBuildOptions := &dockertest.BuildOptions{ Dockerfile: "Dockerfile", @@ -64,12 +64,12 @@ func (s *IntegrationCLITestSuite) SetupTest() { Mounts: []string{ fmt.Sprintf("%s/integration_test/etc:/etc/headscale", currentPath), }, + Cmd: []string{"headscale", "serve"}, + Networks: []*dockertest.Network{&s.network}, ExposedPorts: []string{"8080/tcp"}, PortBindings: map[docker.Port][]docker.PortBinding{ "8080/tcp": {{HostPort: "8080"}}, }, - Networks: []*dockertest.Network{&s.network}, - Cmd: []string{"headscale", "serve"}, } err = s.pool.RemoveContainerByName(headscaleHostname) diff --git a/integration_common_test.go b/integration_common_test.go index 1d69972b..f3c39232 100644 --- a/integration_common_test.go +++ b/integration_common_test.go @@ -19,6 +19,7 @@ import ( ) const ( + headscaleNetwork = "headscale-test" headscaleHostname = "headscale" DOCKER_EXECUTE_TIMEOUT = 10 * time.Second ) diff --git a/integration_embedded_derp_test.go b/integration_embedded_derp_test.go index 421e01d0..c83f6106 100644 --- a/integration_embedded_derp_test.go +++ b/integration_embedded_derp_test.go @@ -95,7 +95,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { s.FailNow(fmt.Sprintf("Could not connect to docker: %s", err), "") } - network, err := GetFirstOrCreateNetwork(&s.pool, "headscale-test") + network, err := GetFirstOrCreateNetwork(&s.pool, headscaleNetwork) if err != nil { s.FailNow(fmt.Sprintf("Failed to create or get network: %s", err), "") } @@ -120,6 +120,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { } headscaleOptions := &dockertest.RunOptions{ + Name: headscaleDerpHostname, Mounts: []string{ fmt.Sprintf( diff --git a/integration_general_test.go b/integration_general_test.go index 500247df..5b5abf07 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -230,11 +230,11 @@ func (s *IntegrationTestSuite) SetupSuite() { 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 { - s.FailNow(fmt.Sprintf("Could not create network: %s", err), "") + network, err := GetFirstOrCreateNetwork(&s.pool, headscaleNetwork) + if err != nil { + s.FailNow(fmt.Sprintf("Failed to create or get network: %s", err), "") } + s.network = network headscaleBuildOptions := &dockertest.BuildOptions{ Dockerfile: "Dockerfile", diff --git a/integration_oidc_test.go b/integration_oidc_test.go index 27c1e7bc..ba0b00f6 100644 --- a/integration_oidc_test.go +++ b/integration_oidc_test.go @@ -96,7 +96,7 @@ func (s *IntegrationOIDCTestSuite) SetupSuite() { s.FailNow(fmt.Sprintf("Could not connect to docker: %s", err), "") } - network, err := GetFirstOrCreateNetwork(&s.pool, "headscale-test") + network, err := GetFirstOrCreateNetwork(&s.pool, headscaleNetwork) if err != nil { s.FailNow(fmt.Sprintf("Failed to create or get network: %s", err), "") } From 073308f1a330af550801f85292614a08da252c15 Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Tue, 11 Oct 2022 22:55:54 +0800 Subject: [PATCH 21/55] Fix the proposed noise private_key_path As indicated by the comment, the default /var/lib/headscale path is not writable in the container. However the sample setting is not following that like `private_key_path` --- docs/running-headscale-container.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/running-headscale-container.md b/docs/running-headscale-container.md index f3626e9f..afbc1c56 100644 --- a/docs/running-headscale-container.md +++ b/docs/running-headscale-container.md @@ -55,7 +55,7 @@ metrics_listen_addr: 0.0.0.0:9090 private_key_path: /etc/headscale/private.key # The default /var/lib/headscale path is not writable in the container noise: - private_key_path: /var/lib/headscale/noise_private.key + private_key_path: /etc/headscale/noise_private.key # The default /var/lib/headscale path is not writable in the container db_path: /etc/headscale/db.sqlite ``` From 21dd2123494a3b123908d32c73f592f3a8730118 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Thu, 13 Oct 2022 05:50:41 +0200 Subject: [PATCH 22/55] Split integration tests into seperate jobs Signed-off-by: Kristoffer Dalby --- .github/workflows/test-integration-cli.yml | 40 +++++++++++++++++++ ...egration.yml => test-integration-derp.yml} | 27 ------------- .../workflows/test-integration-general.yml | 40 +++++++++++++++++++ .github/workflows/test-integration-oidc.yml | 40 +++++++++++++++++++ 4 files changed, 120 insertions(+), 27 deletions(-) create mode 100644 .github/workflows/test-integration-cli.yml rename .github/workflows/{test-integration.yml => test-integration-derp.yml} (51%) create mode 100644 .github/workflows/test-integration-general.yml create mode 100644 .github/workflows/test-integration-oidc.yml diff --git a/.github/workflows/test-integration-cli.yml b/.github/workflows/test-integration-cli.yml new file mode 100644 index 00000000..46f48fd2 --- /dev/null +++ b/.github/workflows/test-integration-cli.yml @@ -0,0 +1,40 @@ +name: CI + +on: [pull_request] + +jobs: + integration-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: Set Swap Space + uses: pierotofy/set-swap-space@master + with: + swap-size-gb: 10 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v14.1 + with: + files: | + *.nix + go.* + **/*.go + integration_test/ + config-example.yaml + + - uses: cachix/install-nix-action@v16 + if: steps.changed-files.outputs.any_changed == 'true' + + - name: Run CLI integration tests + if: steps.changed-files.outputs.any_changed == 'true' + uses: nick-fields/retry@v2 + with: + timeout_minutes: 240 + max_attempts: 5 + retry_on: error + command: nix develop --command -- make test_integration_cli diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration-derp.yml similarity index 51% rename from .github/workflows/test-integration.yml rename to .github/workflows/test-integration-derp.yml index f2adfa19..7fd391bb 100644 --- a/.github/workflows/test-integration.yml +++ b/.github/workflows/test-integration-derp.yml @@ -30,15 +30,6 @@ jobs: - uses: cachix/install-nix-action@v16 if: steps.changed-files.outputs.any_changed == 'true' - - name: Run CLI integration tests - if: steps.changed-files.outputs.any_changed == 'true' - uses: nick-fields/retry@v2 - with: - timeout_minutes: 240 - max_attempts: 5 - retry_on: error - command: nix develop --command -- make test_integration_cli - - name: Run Embedded DERP server integration tests if: steps.changed-files.outputs.any_changed == 'true' uses: nick-fields/retry@v2 @@ -47,21 +38,3 @@ jobs: max_attempts: 5 retry_on: error command: nix develop --command -- make test_integration_derp - - - name: Run OIDC integration tests - if: steps.changed-files.outputs.any_changed == 'true' - uses: nick-fields/retry@v2 - with: - timeout_minutes: 240 - max_attempts: 5 - retry_on: error - command: nix develop --command -- make test_integration_oidc - - - name: Run general integration tests - if: steps.changed-files.outputs.any_changed == 'true' - uses: nick-fields/retry@v2 - with: - timeout_minutes: 240 - max_attempts: 5 - retry_on: error - command: nix develop --command -- make test_integration_general diff --git a/.github/workflows/test-integration-general.yml b/.github/workflows/test-integration-general.yml new file mode 100644 index 00000000..278548dc --- /dev/null +++ b/.github/workflows/test-integration-general.yml @@ -0,0 +1,40 @@ +name: CI + +on: [pull_request] + +jobs: + integration-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: Set Swap Space + uses: pierotofy/set-swap-space@master + with: + swap-size-gb: 10 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v14.1 + with: + files: | + *.nix + go.* + **/*.go + integration_test/ + config-example.yaml + + - uses: cachix/install-nix-action@v16 + if: steps.changed-files.outputs.any_changed == 'true' + + - name: Run general integration tests + if: steps.changed-files.outputs.any_changed == 'true' + uses: nick-fields/retry@v2 + with: + timeout_minutes: 240 + max_attempts: 5 + retry_on: error + command: nix develop --command -- make test_integration_general diff --git a/.github/workflows/test-integration-oidc.yml b/.github/workflows/test-integration-oidc.yml new file mode 100644 index 00000000..0f2005c5 --- /dev/null +++ b/.github/workflows/test-integration-oidc.yml @@ -0,0 +1,40 @@ +name: CI + +on: [pull_request] + +jobs: + integration-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: Set Swap Space + uses: pierotofy/set-swap-space@master + with: + swap-size-gb: 10 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v14.1 + with: + files: | + *.nix + go.* + **/*.go + integration_test/ + config-example.yaml + + - uses: cachix/install-nix-action@v16 + if: steps.changed-files.outputs.any_changed == 'true' + + - name: Run OIDC integration tests + if: steps.changed-files.outputs.any_changed == 'true' + uses: nick-fields/retry@v2 + with: + timeout_minutes: 240 + max_attempts: 5 + retry_on: error + command: nix develop --command -- make test_integration_oidc From 9f58eebfe16c1b45c352d93b601b913ddaf79384 Mon Sep 17 00:00:00 2001 From: Pontus N Date: Thu, 13 Oct 2022 15:17:18 +0200 Subject: [PATCH 23/55] Fix zero arguments error --- cmd/headscale/cli/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/headscale/cli/root.go b/cmd/headscale/cli/root.go index bd526203..52a3f1b8 100644 --- a/cmd/headscale/cli/root.go +++ b/cmd/headscale/cli/root.go @@ -15,7 +15,7 @@ import ( var cfgFile string = "" func init() { - if len(os.Args) > 1 && os.Args[1] == "version" || os.Args[1] == "mockoidc" { + if len(os.Args) > 1 && (os.Args[1] == "version" || os.Args[1] == "mockoidc") { return } From ff217ccce8c940ed082d0b416c573e4e96c2d473 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 14 Oct 2022 09:12:13 +0200 Subject: [PATCH 24/55] Add back head and unstable, ts 1.32.0 Signed-off-by: Kristoffer Dalby --- integration_common_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/integration_common_test.go b/integration_common_test.go index f3c39232..9fe435d6 100644 --- a/integration_common_test.go +++ b/integration_common_test.go @@ -31,8 +31,9 @@ var ( IpPrefix6 = netip.MustParsePrefix("fd7a:115c:a1e0::/48") tailscaleVersions = []string{ - // "head", - // "unstable", + "head", + "unstable", + "1.32.0", "1.30.2", "1.28.0", "1.26.2", From 365946166697eaf1746c08f65bf3d01c0bb1819b Mon Sep 17 00:00:00 2001 From: kevinlin Date: Sun, 9 Oct 2022 18:13:32 +0800 Subject: [PATCH 25/55] Update reverse-proxy document for istio/envoy --- docs/reverse-proxy.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/reverse-proxy.md b/docs/reverse-proxy.md index 74bbff71..4ab7ac00 100644 --- a/docs/reverse-proxy.md +++ b/docs/reverse-proxy.md @@ -59,3 +59,34 @@ server { } } ``` + +## istio/envoy +If you using [Istio](https://istio.io/) ingressgateway or [Envoy](https://www.envoyproxy.io/) as reverse proxy, there are some tips for you. + +### Envoy +You need add a new upgrade_type named `tailscale-control-protocol`. [see detail](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#extensions-filters-network-http-connection-manager-v3-httpconnectionmanager-upgradeconfig) + +### Istio +Same as envoy, we can use `EnvoyFilter` to add upgrade_type. +```yaml +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: headscale-behind-istio-ingress + namespace: istio-system +spec: + configPatches: + - applyTo: NETWORK_FILTER + match: + listener: + filterChain: + filter: + name: envoy.filters.network.http_connection_manager + patch: + operation: MERGE + value: + typed_config: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + upgrade_configs: + - upgrade_type: tailscale-control-protocol +``` \ No newline at end of file From 06e12f7020caa2b8a2e1c43ca28f38e7915b4055 Mon Sep 17 00:00:00 2001 From: kevinlin Date: Sun, 9 Oct 2022 18:17:31 +0800 Subject: [PATCH 26/55] Update: tips about warnning log --- docs/reverse-proxy.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/reverse-proxy.md b/docs/reverse-proxy.md index 4ab7ac00..2bfbcfb2 100644 --- a/docs/reverse-proxy.md +++ b/docs/reverse-proxy.md @@ -61,7 +61,10 @@ server { ``` ## istio/envoy -If you using [Istio](https://istio.io/) ingressgateway or [Envoy](https://www.envoyproxy.io/) as reverse proxy, there are some tips for you. +If you using [Istio](https://istio.io/) ingressgateway or [Envoy](https://www.envoyproxy.io/) as reverse proxy, there are some tips for you. If not set, you may see some debug log in proxy as below: +```log +Sending local reply with details upgrade_failed +``` ### Envoy You need add a new upgrade_type named `tailscale-control-protocol`. [see detail](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#extensions-filters-network-http-connection-manager-v3-httpconnectionmanager-upgradeconfig) From 79864e01650bc0a6aa7f9ff0c76793febb16ff32 Mon Sep 17 00:00:00 2001 From: kevinlin Date: Sat, 15 Oct 2022 00:06:15 +0800 Subject: [PATCH 27/55] Fmt md with prettier --- docs/reverse-proxy.md | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/docs/reverse-proxy.md b/docs/reverse-proxy.md index 2bfbcfb2..1c7e5804 100644 --- a/docs/reverse-proxy.md +++ b/docs/reverse-proxy.md @@ -61,16 +61,21 @@ server { ``` ## istio/envoy -If you using [Istio](https://istio.io/) ingressgateway or [Envoy](https://www.envoyproxy.io/) as reverse proxy, there are some tips for you. If not set, you may see some debug log in proxy as below: + +If you using [Istio](https://istio.io/) ingressgateway or [Envoy](https://www.envoyproxy.io/) as reverse proxy, there are some tips for you. If not set, you may see some debug log in proxy as below: + ```log Sending local reply with details upgrade_failed ``` ### Envoy + You need add a new upgrade_type named `tailscale-control-protocol`. [see detail](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#extensions-filters-network-http-connection-manager-v3-httpconnectionmanager-upgradeconfig) ### Istio + Same as envoy, we can use `EnvoyFilter` to add upgrade_type. + ```yaml apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter @@ -79,17 +84,17 @@ metadata: namespace: istio-system spec: configPatches: - - applyTo: NETWORK_FILTER - match: - listener: - filterChain: - filter: - name: envoy.filters.network.http_connection_manager - patch: - operation: MERGE - value: - typed_config: - '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - upgrade_configs: - - upgrade_type: tailscale-control-protocol -``` \ No newline at end of file + - applyTo: NETWORK_FILTER + match: + listener: + filterChain: + filter: + name: envoy.filters.network.http_connection_manager + patch: + operation: MERGE + value: + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + upgrade_configs: + - upgrade_type: tailscale-control-protocol +``` From 32c21a05f881698ac625f531785ba076745b4002 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 14:41:20 +0200 Subject: [PATCH 28/55] cache go mod in docker, speed up local Signed-off-by: Kristoffer Dalby --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index eeac2805..12c42360 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ test_integration_cli: docker network create headscale-test || true docker run -t --rm \ --network headscale-test \ + -v ~/.cache/hs-integration-go:/go \ -v $$PWD:$$PWD -w $$PWD \ -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ go test -failfast -tags integration_cli,integration -timeout 30m -count=1 ./... @@ -40,6 +41,7 @@ test_integration_derp: docker network create headscale-test || true docker run -t --rm \ --network headscale-test \ + -v ~/.cache/hs-integration-go:/go \ -v $$PWD:$$PWD -w $$PWD \ -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ go test -failfast -tags integration_derp,integration -timeout 30m -count=1 ./... @@ -49,6 +51,7 @@ test_integration_general: docker network create headscale-test || true docker run -t --rm \ --network headscale-test \ + -v ~/.cache/hs-integration-go:/go \ -v $$PWD:$$PWD -w $$PWD \ -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ go test -failfast -tags integration_general,integration -timeout 30m -count=1 ./... @@ -58,6 +61,7 @@ test_integration_oidc: docker network create headscale-test || true docker run -t --rm \ --network headscale-test \ + -v ~/.cache/hs-integration-go:/go \ -v $$PWD:$$PWD -w $$PWD \ -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ go test -failfast -tags integration_oidc,integration -timeout 30m -count=1 ./... From c6f82c36463e5e66e9ced6190ad7875bc924b6de Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 14:41:48 +0200 Subject: [PATCH 29/55] Switch from hacking buildtags to selecting tests Signed-off-by: Kristoffer Dalby --- Makefile | 8 ++++---- integration_cli_test.go | 4 +--- integration_common_test.go | 2 -- integration_embedded_derp_test.go | 4 +--- integration_general_test.go | 4 +--- integration_oidc_test.go | 4 +--- 6 files changed, 8 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 12c42360..90ee5107 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ test_integration_cli: -v ~/.cache/hs-integration-go:/go \ -v $$PWD:$$PWD -w $$PWD \ -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ - go test -failfast -tags integration_cli,integration -timeout 30m -count=1 ./... + go test -failfast -timeout 30m -count=1 -run IntegrationCLI ./... test_integration_derp: docker network rm $$(docker network ls --filter name=headscale --quiet) || true @@ -44,7 +44,7 @@ test_integration_derp: -v ~/.cache/hs-integration-go:/go \ -v $$PWD:$$PWD -w $$PWD \ -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ - go test -failfast -tags integration_derp,integration -timeout 30m -count=1 ./... + go test -failfast -timeout 30m -count=1 -run IntegrationDERP ./... test_integration_general: docker network rm $$(docker network ls --filter name=headscale --quiet) || true @@ -54,7 +54,7 @@ test_integration_general: -v ~/.cache/hs-integration-go:/go \ -v $$PWD:$$PWD -w $$PWD \ -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ - go test -failfast -tags integration_general,integration -timeout 30m -count=1 ./... + go test -failfast -timeout 30m -count=1 -run IntegrationGeneral ./... test_integration_oidc: docker network rm $$(docker network ls --filter name=headscale --quiet) || true @@ -64,7 +64,7 @@ test_integration_oidc: -v ~/.cache/hs-integration-go:/go \ -v $$PWD:$$PWD -w $$PWD \ -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ - go test -failfast -tags integration_oidc,integration -timeout 30m -count=1 ./... + go test -failfast -timeout 30m -count=1 -run IntegrationOIDC ./... coverprofile_func: go tool cover -func=coverage.out diff --git a/integration_cli_test.go b/integration_cli_test.go index 0f5d69ad..dc854034 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -1,5 +1,3 @@ -//go:build integration_cli - package headscale import ( @@ -28,7 +26,7 @@ type IntegrationCLITestSuite struct { env []string } -func TestCLIIntegrationTestSuite(t *testing.T) { +func TestIntegrationCLITestSuite(t *testing.T) { s := new(IntegrationCLITestSuite) suite.Run(t, s) diff --git a/integration_common_test.go b/integration_common_test.go index 9fe435d6..4b931840 100644 --- a/integration_common_test.go +++ b/integration_common_test.go @@ -1,5 +1,3 @@ -//go:build integration - package headscale import ( diff --git a/integration_embedded_derp_test.go b/integration_embedded_derp_test.go index c83f6106..343a04ad 100644 --- a/integration_embedded_derp_test.go +++ b/integration_embedded_derp_test.go @@ -1,5 +1,3 @@ -//go:build integration_derp - package headscale import ( @@ -46,7 +44,7 @@ type IntegrationDERPTestSuite struct { joinWaitGroup sync.WaitGroup } -func TestDERPIntegrationTestSuite(t *testing.T) { +func TestIntegrationDERPTestSuite(t *testing.T) { saveLogs, err := GetEnvBool("HEADSCALE_INTEGRATION_SAVE_LOG") if err != nil { saveLogs = false diff --git a/integration_general_test.go b/integration_general_test.go index 5b5abf07..8f318d32 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -1,5 +1,3 @@ -//go:build integration_general - package headscale import ( @@ -41,7 +39,7 @@ type IntegrationTestSuite struct { joinWaitGroup sync.WaitGroup } -func TestIntegrationTestSuite(t *testing.T) { +func TestIntegrationGeneralTestSuite(t *testing.T) { saveLogs, err := GetEnvBool("HEADSCALE_INTEGRATION_SAVE_LOG") if err != nil { saveLogs = false diff --git a/integration_oidc_test.go b/integration_oidc_test.go index ba0b00f6..8e5f7910 100644 --- a/integration_oidc_test.go +++ b/integration_oidc_test.go @@ -1,5 +1,3 @@ -//go:build integration_oidc - package headscale import ( @@ -45,7 +43,7 @@ type IntegrationOIDCTestSuite struct { joinWaitGroup sync.WaitGroup } -func TestOIDCIntegrationTestSuite(t *testing.T) { +func TestIntegrationOIDCTestSuite(t *testing.T) { saveLogs, err := GetEnvBool("HEADSCALE_INTEGRATION_SAVE_LOG") if err != nil { saveLogs = false From dfadb965b7014618848afe706d7916c3b3519495 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 14:45:18 +0200 Subject: [PATCH 30/55] Use short test to signal that we dont run integration Signed-off-by: Kristoffer Dalby --- Makefile | 2 +- integration_cli_test.go | 4 ++++ integration_embedded_derp_test.go | 4 ++++ integration_general_test.go | 4 ++++ integration_oidc_test.go | 4 ++++ 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 90ee5107..c5a2d88c 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ build: dev: lint test build test: - @go test -coverprofile=coverage.out ./... + @go test -short -coverprofile=coverage.out ./... test_integration: test_integration_cli test_integration_derp test_integration_oidc test_integration_general diff --git a/integration_cli_test.go b/integration_cli_test.go index dc854034..06771483 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -27,6 +27,10 @@ type IntegrationCLITestSuite struct { } func TestIntegrationCLITestSuite(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration tests due to short flag") + } + s := new(IntegrationCLITestSuite) suite.Run(t, s) diff --git a/integration_embedded_derp_test.go b/integration_embedded_derp_test.go index 343a04ad..0b7a8d27 100644 --- a/integration_embedded_derp_test.go +++ b/integration_embedded_derp_test.go @@ -45,6 +45,10 @@ type IntegrationDERPTestSuite struct { } func TestIntegrationDERPTestSuite(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration tests due to short flag") + } + saveLogs, err := GetEnvBool("HEADSCALE_INTEGRATION_SAVE_LOG") if err != nil { saveLogs = false diff --git a/integration_general_test.go b/integration_general_test.go index 8f318d32..ad92a2b2 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -40,6 +40,10 @@ type IntegrationTestSuite struct { } func TestIntegrationGeneralTestSuite(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration tests due to short flag") + } + saveLogs, err := GetEnvBool("HEADSCALE_INTEGRATION_SAVE_LOG") if err != nil { saveLogs = false diff --git a/integration_oidc_test.go b/integration_oidc_test.go index 8e5f7910..2f4d7ddf 100644 --- a/integration_oidc_test.go +++ b/integration_oidc_test.go @@ -44,6 +44,10 @@ type IntegrationOIDCTestSuite struct { } func TestIntegrationOIDCTestSuite(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration tests due to short flag") + } + saveLogs, err := GetEnvBool("HEADSCALE_INTEGRATION_SAVE_LOG") if err != nil { saveLogs = false From 4df47de3f29cc11a397bf3f1e4da8176c0b57439 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 14:57:22 +0200 Subject: [PATCH 31/55] add nolint to integrationtests, they are going away :tm: Signed-off-by: Kristoffer Dalby --- integration_cli_test.go | 1 + integration_common_test.go | 2 +- integration_embedded_derp_test.go | 5 ++--- integration_general_test.go | 3 ++- integration_oidc_test.go | 3 ++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/integration_cli_test.go b/integration_cli_test.go index 06771483..ee6a9e1f 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -1,3 +1,4 @@ +//nolint package headscale import ( diff --git a/integration_common_test.go b/integration_common_test.go index 4b931840..a1658863 100644 --- a/integration_common_test.go +++ b/integration_common_test.go @@ -1,3 +1,4 @@ +//nolint package headscale import ( @@ -326,7 +327,6 @@ func GetEnvBool(key string) (bool, error) { func GetFirstOrCreateNetwork(pool *dockertest.Pool, name string) (dockertest.Network, error) { networks, err := pool.NetworksByName(name) if err != nil || len(networks) == 0 { - if _, err := pool.CreateNetwork(name); err == nil { // Create does not give us an updated version of the resource, so we need to // get it again. diff --git a/integration_embedded_derp_test.go b/integration_embedded_derp_test.go index 0b7a8d27..5bd6deed 100644 --- a/integration_embedded_derp_test.go +++ b/integration_embedded_derp_test.go @@ -1,3 +1,4 @@ +//nolint package headscale import ( @@ -15,13 +16,12 @@ import ( "testing" "time" + "github.com/ccding/go-stun/stun" v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" - - "github.com/ccding/go-stun/stun" ) const ( @@ -122,7 +122,6 @@ func (s *IntegrationDERPTestSuite) SetupSuite() { } headscaleOptions := &dockertest.RunOptions{ - Name: headscaleDerpHostname, Mounts: []string{ fmt.Sprintf( diff --git a/integration_general_test.go b/integration_general_test.go index ad92a2b2..52bfddd4 100644 --- a/integration_general_test.go +++ b/integration_general_test.go @@ -1,3 +1,4 @@ +//nolint package headscale import ( @@ -506,7 +507,7 @@ func getIPsfromIPNstate(status ipnstate.Status) []netip.Addr { return ips } -// TODO: Adopt test for cross communication between namespaces +// TODO: Adopt test for cross communication between namespaces. func (s *IntegrationTestSuite) TestPingAllPeersByAddress() { for _, scales := range s.namespaces { ips, err := getIPs(scales.tailscales) diff --git a/integration_oidc_test.go b/integration_oidc_test.go index 2f4d7ddf..8ca46db7 100644 --- a/integration_oidc_test.go +++ b/integration_oidc_test.go @@ -1,3 +1,4 @@ +//nolint package headscale import ( @@ -199,7 +200,7 @@ oidc: log.Println(config) configPath := path.Join(currentPath, "integration_test/etc_oidc/config.yaml") - err = os.WriteFile(configPath, []byte(config), 0644) + err = os.WriteFile(configPath, []byte(config), 0o644) if err != nil { s.FailNow(fmt.Sprintf("Could not write config: %s", err), "") } From 2f36a11a8eee8bfe723d323aee6b887435bfd138 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 15:08:48 +0200 Subject: [PATCH 32/55] use short flag for nix build test Signed-off-by: Kristoffer Dalby --- flake.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flake.nix b/flake.nix index f7d0c669..6775e9cb 100644 --- a/flake.nix +++ b/flake.nix @@ -26,6 +26,9 @@ version = headscaleVersion; src = pkgs.lib.cleanSource self; + # Only run unit tests when testing a build + checkFlags = ["-short"]; + # 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-DosFCSiQ5FURbIrt4NcPGkExc84t2MGMqe9XLxNHdIM="; From fa8b02a83f856a06858b5c1d160a6abbb7df9e17 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Thu, 13 Oct 2022 16:00:08 +0200 Subject: [PATCH 33/55] tsic: Tailscale in Container abstraction Signed-off-by: Kristoffer Dalby --- integration/tsic/tsic.go | 217 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 integration/tsic/tsic.go diff --git a/integration/tsic/tsic.go b/integration/tsic/tsic.go new file mode 100644 index 00000000..40a0e693 --- /dev/null +++ b/integration/tsic/tsic.go @@ -0,0 +1,217 @@ +package tsic + +import ( + "errors" + "fmt" + "log" + "net/netip" + "strings" + + "github.com/juanfont/headscale" + "github.com/juanfont/headscale/integration/dockertestutil" + "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" +) + +const tsicHashLength = 6 +const dockerContextPath = "../." + +var errTailscalePingFailed = errors.New("ping failed") + +type TailscaleInContainer struct { + version string + Hostname string + + pool *dockertest.Pool + container *dockertest.Resource + network *dockertest.Network +} + +func New( + pool *dockertest.Pool, + version string, + network *dockertest.Network) (*TailscaleInContainer, error) { + hash, err := headscale.GenerateRandomStringDNSSafe(tsicHashLength) + if err != nil { + return nil, err + } + + hostname := fmt.Sprintf("ts-%s-%s", version, hash) + + // TODO(kradalby): figure out why we need to "refresh" the network here. + // network, err = dockertestutil.GetFirstOrCreateNetwork(pool, network.Network.Name) + // if err != nil { + // return nil, err + // } + + tailscaleOptions := &dockertest.RunOptions{ + Name: hostname, + Networks: []*dockertest.Network{network}, + Cmd: []string{ + "tailscaled", "--tun=tsdev", + }, + } + + // dockertest isnt very good at handling containers that has already + // been created, this is an attempt to make sure this container isnt + // present. + err = pool.RemoveContainerByName(hostname) + if err != nil { + return nil, err + } + + container, err := pool.BuildAndRunWithBuildOptions( + createTailscaleBuildOptions(version), + tailscaleOptions, + dockertestutil.DockerRestartPolicy, + dockertestutil.DockerAllowLocalIPv6, + dockertestutil.DockerAllowNetworkAdministration, + ) + if err != nil { + return nil, fmt.Errorf("could not start tailscale container: %w", err) + } + log.Printf("Created %s container\n", hostname) + + return &TailscaleInContainer{ + version: version, + Hostname: hostname, + + pool: pool, + container: container, + network: network, + }, nil +} + +func (t *TailscaleInContainer) Shutdown() error { + return t.pool.Purge(t.container) +} + +func (t *TailscaleInContainer) Up( + loginServer, authKey string, +) error { + command := []string{ + "tailscale", + "up", + "-login-server", + loginServer, + "--authkey", + authKey, + "--hostname", + t.Hostname, + } + + log.Println("Join command:", command) + log.Printf("Running join command for %s\n", t.Hostname) + _, _, err := dockertestutil.ExecuteCommand( + t.container, + command, + []string{}, + ) + if err != nil { + return err + } + log.Printf("%s joined\n", t.Hostname) + + return nil +} + +func (t *TailscaleInContainer) IPs() ([]netip.Addr, error) { + ips := make([]netip.Addr, 0) + + command := []string{ + "tailscale", + "ip", + } + + result, _, err := dockertestutil.ExecuteCommand( + t.container, + command, + []string{}, + ) + if err != nil { + return []netip.Addr{}, err + } + + for _, address := range strings.Split(result, "\n") { + address = strings.TrimSuffix(address, "\n") + if len(address) < 1 { + continue + } + ip, err := netip.ParseAddr(address) + if err != nil { + return nil, err + } + ips = append(ips, ip) + } + + return ips, nil +} + +func (t *TailscaleInContainer) Ping(ip netip.Addr) error { + command := []string{ + "tailscale", "ping", + "--timeout=1s", + "--c=10", + "--until-direct=true", + ip.String(), + } + + result, _, err := dockertestutil.ExecuteCommand( + t.container, + command, + []string{}, + ) + if err != nil { + return err + } + + if !strings.Contains(result, "pong") { + return errTailscalePingFailed + } + + return nil +} + +func createTailscaleBuildOptions(version string) *dockertest.BuildOptions { + var tailscaleBuildOptions *dockertest.BuildOptions + switch version { + case "head": + tailscaleBuildOptions = &dockertest.BuildOptions{ + Dockerfile: "Dockerfile.tailscale-HEAD", + ContextDir: dockerContextPath, + BuildArgs: []docker.BuildArg{}, + } + case "unstable": + tailscaleBuildOptions = &dockertest.BuildOptions{ + Dockerfile: "Dockerfile.tailscale", + ContextDir: dockerContextPath, + BuildArgs: []docker.BuildArg{ + { + Name: "TAILSCALE_VERSION", + Value: "*", // Installs the latest version https://askubuntu.com/a/824926 + }, + { + Name: "TAILSCALE_CHANNEL", + Value: "unstable", + }, + }, + } + default: + tailscaleBuildOptions = &dockertest.BuildOptions{ + Dockerfile: "Dockerfile.tailscale", + ContextDir: dockerContextPath, + BuildArgs: []docker.BuildArg{ + { + Name: "TAILSCALE_VERSION", + Value: version, + }, + { + Name: "TAILSCALE_CHANNEL", + Value: "stable", + }, + }, + } + } + + return tailscaleBuildOptions +} From 308b9e78a1613e68ae8ee01f3b7da1e39de4a28e Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Thu, 13 Oct 2022 16:00:22 +0200 Subject: [PATCH 34/55] Defince control server interface Signed-off-by: Kristoffer Dalby --- integration/control.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 integration/control.go diff --git a/integration/control.go b/integration/control.go new file mode 100644 index 00000000..bcda4a56 --- /dev/null +++ b/integration/control.go @@ -0,0 +1,13 @@ +package integration + +import v1 "github.com/juanfont/headscale/gen/go/headscale/v1" + +type ControlServer interface { + Shutdown() error + GetHealthEndpoint() string + GetEndpoint() string + WaitForReady() error + CreateNamespace(namespace string) error + CreateAuthKey(namespace string) (*v1.PreAuthKey, error) + ListNodes(namespace string) ([]*v1.Machine, error) +} From b331e3f7367ca7208be6541641421a9325a05a85 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Thu, 13 Oct 2022 16:01:23 +0200 Subject: [PATCH 35/55] hsic: ControlServer implementation of headscale in docker Signed-off-by: Kristoffer Dalby --- integration/hsic/hsic.go | 223 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 integration/hsic/hsic.go diff --git a/integration/hsic/hsic.go b/integration/hsic/hsic.go new file mode 100644 index 00000000..78b1ef3b --- /dev/null +++ b/integration/hsic/hsic.go @@ -0,0 +1,223 @@ +package hsic + +import ( + "encoding/json" + "errors" + "fmt" + "log" + "net/http" + "os" + "path" + + "github.com/juanfont/headscale" + v1 "github.com/juanfont/headscale/gen/go/headscale/v1" + "github.com/juanfont/headscale/integration/dockertestutil" + "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" +) + +const hsicHashLength = 6 +const dockerContextPath = "../." + +var errHeadscaleStatusCodeNotOk = errors.New("headscale status code not ok") + +type HeadscaleInContainer struct { + hostname string + port int + + pool *dockertest.Pool + container *dockertest.Resource + network *dockertest.Network +} + +func New( + pool *dockertest.Pool, + port int, + network *dockertest.Network) (*HeadscaleInContainer, error) { + hash, err := headscale.GenerateRandomStringDNSSafe(hsicHashLength) + if err != nil { + return nil, err + } + + headscaleBuildOptions := &dockertest.BuildOptions{ + Dockerfile: "Dockerfile", + ContextDir: dockerContextPath, + } + + hostname := fmt.Sprintf("hs-%s", hash) + portProto := fmt.Sprintf("%d/tcp", port) + dockerPort := docker.Port(portProto) + + currentPath, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("could not determine current path: %w", err) + } + + integrationConfigPath := path.Join(currentPath, "..", "integration_test", "etc") + + runOptions := &dockertest.RunOptions{ + Name: hostname, + // TODO(kradalby): Do something clever here, can we ditch the config repo? + // Always generate the config from code? + Mounts: []string{ + fmt.Sprintf("%s:/etc/headscale", integrationConfigPath), + }, + ExposedPorts: []string{portProto}, + // TODO(kradalby): WHY do we need to bind these now that we run fully in docker? + PortBindings: map[docker.Port][]docker.PortBinding{ + dockerPort: {{HostPort: fmt.Sprintf("%d", port)}}, + }, + Networks: []*dockertest.Network{network}, + Cmd: []string{"headscale", "serve"}, + } + + // dockertest isnt very good at handling containers that has already + // been created, this is an attempt to make sure this container isnt + // present. + err = pool.RemoveContainerByName(hostname) + if err != nil { + return nil, err + } + + container, err := pool.BuildAndRunWithBuildOptions( + headscaleBuildOptions, + runOptions, + dockertestutil.DockerRestartPolicy, + dockertestutil.DockerAllowLocalIPv6, + dockertestutil.DockerAllowNetworkAdministration, + ) + if err != nil { + return nil, fmt.Errorf("could not start headscale container: %w", err) + } + log.Printf("Created %s container\n", hostname) + + return &HeadscaleInContainer{ + hostname: hostname, + port: port, + + pool: pool, + container: container, + network: network, + }, nil +} + +func (t *HeadscaleInContainer) Shutdown() error { + return t.pool.Purge(t.container) +} + +func (t *HeadscaleInContainer) GetIP() string { + return t.container.GetIPInNetwork(t.network) +} + +func (t *HeadscaleInContainer) GetPort() string { + portProto := fmt.Sprintf("%d/tcp", t.port) + + return t.container.GetPort(portProto) +} + +func (t *HeadscaleInContainer) GetHealthEndpoint() string { + hostEndpoint := fmt.Sprintf("%s:%s", + t.GetIP(), + t.GetPort()) + + return fmt.Sprintf("http://%s/health", hostEndpoint) +} + +func (t *HeadscaleInContainer) GetEndpoint() string { + hostEndpoint := fmt.Sprintf("%s:%s", + t.GetIP(), + t.GetPort()) + + return fmt.Sprintf("http://%s", hostEndpoint) +} + +func (t *HeadscaleInContainer) WaitForReady() error { + url := t.GetHealthEndpoint() + + return t.pool.Retry(func() error { + resp, err := http.Get(url) + if err != nil { + return fmt.Errorf("headscale is not ready: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return errHeadscaleStatusCodeNotOk + } + + return nil + }) +} + +func (t *HeadscaleInContainer) CreateNamespace( + namespace string, +) error { + command := []string{"headscale", "namespaces", "create", namespace} + + _, _, err := dockertestutil.ExecuteCommand( + t.container, + command, + []string{}, + ) + if err != nil { + return err + } + + return nil +} + +func (t *HeadscaleInContainer) CreateAuthKey( + namespace string, +) (*v1.PreAuthKey, error) { + command := []string{ + "headscale", + "--namespace", + namespace, + "preauthkeys", + "create", + "--reusable", + "--expiration", + "24h", + "--output", + "json", + } + + result, _, err := dockertestutil.ExecuteCommand( + t.container, + command, + []string{}, + ) + if err != nil { + return nil, fmt.Errorf("failed to execute create auth key command: %w", err) + } + + var preAuthKey v1.PreAuthKey + err = json.Unmarshal([]byte(result), &preAuthKey) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal auth key: %w", err) + } + + return &preAuthKey, nil +} + +func (t *HeadscaleInContainer) ListNodes( + namespace string, +) ([]*v1.Machine, error) { + command := []string{"headscale", "--namespace", namespace, "nodes", "list", "--output", "json"} + + result, _, err := dockertestutil.ExecuteCommand( + t.container, + command, + []string{}, + ) + if err != nil { + return nil, fmt.Errorf("failed to execute list node command: %w", err) + } + + var nodes []*v1.Machine + err = json.Unmarshal([]byte(result), &nodes) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal nodes: %w", err) + } + + return nodes, nil +} From f68ba7504f542bbe6fb6c1bbd6e3a86d6529ea86 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Thu, 13 Oct 2022 16:03:09 +0200 Subject: [PATCH 36/55] Move some helper functions into dockertestutil package Signed-off-by: Kristoffer Dalby --- integration/dockertestutil/config.go | 28 ++++++++ integration/dockertestutil/execute.go | 94 +++++++++++++++++++++++++++ integration/dockertestutil/network.go | 21 ++++++ 3 files changed, 143 insertions(+) create mode 100644 integration/dockertestutil/config.go create mode 100644 integration/dockertestutil/execute.go create mode 100644 integration/dockertestutil/network.go diff --git a/integration/dockertestutil/config.go b/integration/dockertestutil/config.go new file mode 100644 index 00000000..2a5ac144 --- /dev/null +++ b/integration/dockertestutil/config.go @@ -0,0 +1,28 @@ +package dockertestutil + +import "github.com/ory/dockertest/v3/docker" + +func DockerRestartPolicy(config *docker.HostConfig) { + // set AutoRemove to true so that stopped container goes away by itself on error *immediately*. + // when set to false, containers remain until the end of the integration test. + config.AutoRemove = false + config.RestartPolicy = docker.RestartPolicy{ + Name: "no", + } +} + +func DockerAllowLocalIPv6(config *docker.HostConfig) { + if config.Sysctls == nil { + config.Sysctls = make(map[string]string, 1) + } + config.Sysctls["net.ipv6.conf.all.disable_ipv6"] = "0" +} + +func DockerAllowNetworkAdministration(config *docker.HostConfig) { + config.CapAdd = append(config.CapAdd, "NET_ADMIN") + config.Mounts = append(config.Mounts, docker.HostMount{ + Type: "bind", + Source: "/dev/net/tun", + Target: "/dev/net/tun", + }) +} diff --git a/integration/dockertestutil/execute.go b/integration/dockertestutil/execute.go new file mode 100644 index 00000000..71afa698 --- /dev/null +++ b/integration/dockertestutil/execute.go @@ -0,0 +1,94 @@ +package dockertestutil + +import ( + "bytes" + "errors" + "fmt" + "time" + + "github.com/ory/dockertest/v3" +) + +const dockerExecuteTimeout = time.Second * 10 + +var ( + ErrDockertestCommandFailed = errors.New("dockertest command failed") + ErrDockertestCommandTimeout = errors.New("dockertest command timed out") +) + +type ExecuteCommandConfig struct { + timeout time.Duration +} + +type ExecuteCommandOption func(*ExecuteCommandConfig) error + +func ExecuteCommandTimeout(timeout time.Duration) ExecuteCommandOption { + return ExecuteCommandOption(func(conf *ExecuteCommandConfig) error { + conf.timeout = timeout + + return nil + }) +} + +func ExecuteCommand( + resource *dockertest.Resource, + cmd []string, + env []string, + options ...ExecuteCommandOption, +) (string, string, error) { + var stdout bytes.Buffer + var stderr bytes.Buffer + + execConfig := ExecuteCommandConfig{ + timeout: dockerExecuteTimeout, + } + + for _, opt := range options { + if err := opt(&execConfig); err != nil { + return "", "", fmt.Errorf("execute-command/options: %w", err) + } + } + + type result struct { + exitCode int + err error + } + + resultChan := make(chan result, 1) + + // Run your long running function in it's own goroutine and pass back it's + // response into our channel. + go func() { + exitCode, err := resource.Exec( + cmd, + dockertest.ExecOptions{ + Env: append(env, "HEADSCALE_LOG_LEVEL=disabled"), + StdOut: &stdout, + StdErr: &stderr, + }, + ) + resultChan <- result{exitCode, err} + }() + + // Listen on our channel AND a timeout channel - which ever happens first. + select { + case res := <-resultChan: + if res.err != nil { + return stdout.String(), stderr.String(), res.err + } + + if res.exitCode != 0 { + // Uncomment for debugging + // log.Println("Command: ", cmd) + // log.Println("stdout: ", stdout.String()) + // log.Println("stderr: ", stderr.String()) + + return stdout.String(), stderr.String(), ErrDockertestCommandFailed + } + + return stdout.String(), stderr.String(), nil + case <-time.After(execConfig.timeout): + + return stdout.String(), stderr.String(), ErrDockertestCommandTimeout + } +} diff --git a/integration/dockertestutil/network.go b/integration/dockertestutil/network.go new file mode 100644 index 00000000..b4ff87cf --- /dev/null +++ b/integration/dockertestutil/network.go @@ -0,0 +1,21 @@ +package dockertestutil + +import "github.com/ory/dockertest/v3" + +func GetFirstOrCreateNetwork(pool *dockertest.Pool, name string) (*dockertest.Network, error) { + networks, err := pool.NetworksByName(name) + if err != nil || len(networks) == 0 { + if _, err := pool.CreateNetwork(name); err == nil { + // Create does not give us an updated version of the resource, so we need to + // get it again. + networks, err := pool.NetworksByName(name) + if err != nil { + return nil, err + } + + return &networks[0], nil + } + } + + return &networks[0], nil +} From a9c3b14f79e4dc733f2fe2a69931908d74e7ce12 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Thu, 13 Oct 2022 16:03:38 +0200 Subject: [PATCH 37/55] Define a "scenario", which is a controlserver with nodes Signed-off-by: Kristoffer Dalby --- integration/scenario.go | 206 +++++++++++++++++++++++++++++++++++ integration/scenario_test.go | 149 +++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 integration/scenario.go create mode 100644 integration/scenario_test.go diff --git a/integration/scenario.go b/integration/scenario.go new file mode 100644 index 00000000..d3cbf247 --- /dev/null +++ b/integration/scenario.go @@ -0,0 +1,206 @@ +package integration + +import ( + "errors" + "fmt" + "log" + "os" + "sync" + + "github.com/juanfont/headscale" + v1 "github.com/juanfont/headscale/gen/go/headscale/v1" + "github.com/juanfont/headscale/integration/dockertestutil" + "github.com/juanfont/headscale/integration/hsic" + "github.com/juanfont/headscale/integration/tsic" + "github.com/ory/dockertest/v3" +) + +const scenarioHashLength = 6 + +var errNoHeadscaleAvailable = errors.New("no headscale available") +var errNoNamespaceAvailable = errors.New("no namespace available") + +type Namespace struct { + Clients map[string]*tsic.TailscaleInContainer + + createWaitGroup sync.WaitGroup + joinWaitGroup sync.WaitGroup +} + +// TODO(kradalby): make control server configurable, test test correctness with +// Tailscale SaaS. +type Scenario struct { + // TODO(kradalby): support multiple headcales for later, currently only + // use one. + controlServers map[string]ControlServer + + namespaces map[string]*Namespace + + pool *dockertest.Pool + network *dockertest.Network +} + +func NewScenario() (*Scenario, error) { + hash, err := headscale.GenerateRandomStringDNSSafe(scenarioHashLength) + if err != nil { + return nil, err + } + + pool, err := dockertest.NewPool("") + if err != nil { + return nil, fmt.Errorf("could not connect to docker: %w", err) + } + + networkName := fmt.Sprintf("hs-%s", hash) + if overrideNetworkName := os.Getenv("HEADSCALE_TEST_NETWORK_NAME"); overrideNetworkName != "" { + networkName = overrideNetworkName + } + + network, err := dockertestutil.GetFirstOrCreateNetwork(pool, networkName) + if err != nil { + return nil, fmt.Errorf("failed to create or get network: %w", err) + } + + return &Scenario{ + controlServers: make(map[string]ControlServer), + namespaces: make(map[string]*Namespace), + + pool: pool, + network: network, + }, nil +} + +func (s *Scenario) Shutdown() error { + for _, control := range s.controlServers { + err := control.Shutdown() + if err != nil { + return fmt.Errorf("failed to tear down control: %w", err) + } + } + + for namespaceName, namespace := range s.namespaces { + for _, client := range namespace.Clients { + log.Printf("removing client %s in namespace %s", client.Hostname, namespaceName) + err := client.Shutdown() + if err != nil { + return fmt.Errorf("failed to tear down client: %w", err) + } + } + } + + // TODO(kradalby): This breaks the "we need to create a network before we start" + // part, since we now run the tests in a container... + // if err := s.pool.RemoveNetwork(s.network); err != nil { + // return fmt.Errorf("failed to remove network: %w", err) + // } + + // TODO(kradalby): This seem redundant to the previous call + // if err := s.network.Close(); err != nil { + // return fmt.Errorf("failed to tear down network: %w", err) + // } + + return nil +} + +/// Headscale related stuff +// Note: These functions assume that there is a _single_ headscale instance for now + +// TODO(kradalby): make port and headscale configurable, multiple instances support? +func (s *Scenario) StartHeadscale() error { + headscale, err := hsic.New(s.pool, 8080, s.network) + if err != nil { + return fmt.Errorf("failed to create headscale container: %w", err) + } + + s.controlServers["headscale"] = headscale + + return nil +} + +func (s *Scenario) Headscale() *hsic.HeadscaleInContainer { + return s.controlServers["headscale"].(*hsic.HeadscaleInContainer) +} + +func (s *Scenario) CreatePreAuthKey(namespace string) (*v1.PreAuthKey, error) { + if headscale, ok := s.controlServers["headscale"]; ok { + key, err := headscale.CreateAuthKey(namespace) + if err != nil { + return nil, fmt.Errorf("failed to create namespace: %w", err) + } + + return key, nil + } + + return nil, fmt.Errorf("failed to create namespace: %w", errNoHeadscaleAvailable) +} + +func (s *Scenario) CreateNamespace(namespace string) error { + if headscale, ok := s.controlServers["headscale"]; ok { + err := headscale.CreateNamespace(namespace) + if err != nil { + return fmt.Errorf("failed to create namespace: %w", err) + } + + s.namespaces[namespace] = &Namespace{ + Clients: make(map[string]*tsic.TailscaleInContainer), + } + + return nil + } + + return fmt.Errorf("failed to create namespace: %w", errNoHeadscaleAvailable) +} + +/// Client related stuff + +func (s *Scenario) CreateTailscaleNodesInNamespace( + namespace string, + version string, + count int, +) error { + if ns, ok := s.namespaces[namespace]; ok { + for i := 0; i < count; i++ { + ns.createWaitGroup.Add(1) + + go func() { + defer ns.createWaitGroup.Done() + + // TODO(kradalby): error handle this + ts, err := tsic.New(s.pool, version, s.network) + if err != nil { + // return fmt.Errorf("failed to add tailscale node: %w", err) + fmt.Printf("failed to add tailscale node: %s", err) + } + + ns.Clients[ts.Hostname] = ts + }() + } + ns.createWaitGroup.Wait() + + return nil + } + + return fmt.Errorf("failed to add tailscale node: %w", errNoNamespaceAvailable) +} + +func (s *Scenario) RunTailscaleUp( + namespace, loginServer, authKey string, +) error { + if ns, ok := s.namespaces[namespace]; ok { + for _, client := range ns.Clients { + ns.joinWaitGroup.Add(1) + + go func() { + defer ns.joinWaitGroup.Done() + + // TODO(kradalby): error handle this + _ = client.Up(loginServer, authKey) + }() + } + ns.joinWaitGroup.Wait() + + return nil + } + + return fmt.Errorf("failed to up tailscale node: %w", errNoNamespaceAvailable) +} diff --git a/integration/scenario_test.go b/integration/scenario_test.go new file mode 100644 index 00000000..cb4aa859 --- /dev/null +++ b/integration/scenario_test.go @@ -0,0 +1,149 @@ +package integration + +import ( + "testing" + + "github.com/juanfont/headscale/integration/tsic" +) + +func TestHeadscale(t *testing.T) { + var err error + + scenario, err := NewScenario() + if err != nil { + t.Errorf("failed to create scenario: %s", err) + } + + t.Run("start-headscale", func(t *testing.T) { + err = scenario.StartHeadscale() + if err != nil { + t.Errorf("failed to create start headcale: %s", err) + } + + err = scenario.Headscale().WaitForReady() + if err != nil { + t.Errorf("headscale failed to become ready: %s", err) + } + + }) + + t.Run("create-namespace", func(t *testing.T) { + err := scenario.CreateNamespace("test-space") + if err != nil { + t.Errorf("failed to create namespace: %s", err) + } + + if _, ok := scenario.namespaces["test-space"]; !ok { + t.Errorf("namespace is not in scenario") + } + }) + + t.Run("create-auth-key", func(t *testing.T) { + _, err := scenario.CreatePreAuthKey("test-space") + if err != nil { + t.Errorf("failed to create preauthkey: %s", err) + } + }) + + err = scenario.Shutdown() + if err != nil { + t.Errorf("failed to tear down scenario: %s", err) + } +} + +func TestCreateTailscale(t *testing.T) { + var scenario *Scenario + var err error + + namespace := "only-create-containers" + + scenario, err = NewScenario() + if err != nil { + t.Errorf("failed to create scenario: %s", err) + } + + scenario.namespaces[namespace] = &Namespace{ + Clients: make(map[string]*tsic.TailscaleInContainer), + } + + t.Run("create-tailscale", func(t *testing.T) { + err := scenario.CreateTailscaleNodesInNamespace(namespace, "1.32.0", 3) + if err != nil { + t.Errorf("failed to add tailscale nodes: %s", err) + } + + if clients := len(scenario.namespaces[namespace].Clients); clients != 3 { + t.Errorf("wrong number of tailscale clients: %d != %d", clients, 3) + } + }) + + err = scenario.Shutdown() + if err != nil { + t.Errorf("failed to tear down scenario: %s", err) + } +} + +func TestTailscaleNodesJoiningHeadcale(t *testing.T) { + var err error + + namespace := "join-node-test" + + scenario, err := NewScenario() + if err != nil { + t.Errorf("failed to create scenario: %s", err) + } + + t.Run("start-headscale", func(t *testing.T) { + err = scenario.StartHeadscale() + if err != nil { + t.Errorf("failed to create start headcale: %s", err) + } + + headscale := scenario.Headscale() + err = headscale.WaitForReady() + if err != nil { + t.Errorf("headscale failed to become ready: %s", err) + } + + }) + + t.Run("create-namespace", func(t *testing.T) { + err := scenario.CreateNamespace(namespace) + if err != nil { + t.Errorf("failed to create namespace: %s", err) + } + + if _, ok := scenario.namespaces[namespace]; !ok { + t.Errorf("namespace is not in scenario") + } + }) + + t.Run("create-tailscale", func(t *testing.T) { + err := scenario.CreateTailscaleNodesInNamespace(namespace, "1.32.0", 2) + if err != nil { + t.Errorf("failed to add tailscale nodes: %s", err) + } + + if clients := len(scenario.namespaces[namespace].Clients); clients != 2 { + t.Errorf("wrong number of tailscale clients: %d != %d", clients, 2) + } + }) + + t.Run("join-headscale", func(t *testing.T) { + key, err := scenario.CreatePreAuthKey(namespace) + if err != nil { + t.Errorf("failed to create preauthkey: %s", err) + } + + err = scenario.RunTailscaleUp(namespace, scenario.Headscale().GetEndpoint(), key.GetKey()) + if err != nil { + t.Errorf("failed to login: %s", err) + } + + }) + + err = scenario.Shutdown() + if err != nil { + t.Errorf("failed to tear down scenario: %s", err) + } +} From eda432148687f467c4d425235aa8f75c5d8c83c8 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 14 Oct 2022 10:37:13 +0200 Subject: [PATCH 38/55] Skip integration tests on short or lack of docker Signed-off-by: Kristoffer Dalby --- integration/dockertestutil/config.go | 14 +++++++++++++- integration/scenario_test.go | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/integration/dockertestutil/config.go b/integration/dockertestutil/config.go index 2a5ac144..4dc3ee33 100644 --- a/integration/dockertestutil/config.go +++ b/integration/dockertestutil/config.go @@ -1,6 +1,18 @@ package dockertestutil -import "github.com/ory/dockertest/v3/docker" +import ( + "os" + + "github.com/ory/dockertest/v3/docker" +) + +func IsRunningInContainer() bool { + if _, err := os.Stat("/.dockerenv"); err != nil { + return false + } + + return true +} func DockerRestartPolicy(config *docker.HostConfig) { // set AutoRemove to true so that stopped container goes away by itself on error *immediately*. diff --git a/integration/scenario_test.go b/integration/scenario_test.go index cb4aa859..8811b2f8 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -3,10 +3,24 @@ package integration import ( "testing" + "github.com/juanfont/headscale/integration/dockertestutil" "github.com/juanfont/headscale/integration/tsic" ) +func IntegrationSkip(t *testing.T) { + t.Helper() + + if !dockertestutil.IsRunningInContainer() { + t.Skip("not running in docker, skipping") + } + + if testing.Short() { + t.Skip("skipping integration tests due to short flag") + } +} + func TestHeadscale(t *testing.T) { + IntegrationSkip(t) var err error scenario, err := NewScenario() @@ -52,6 +66,8 @@ func TestHeadscale(t *testing.T) { } func TestCreateTailscale(t *testing.T) { + IntegrationSkip(t) + var scenario *Scenario var err error @@ -84,6 +100,8 @@ func TestCreateTailscale(t *testing.T) { } func TestTailscaleNodesJoiningHeadcale(t *testing.T) { + IntegrationSkip(t) + var err error namespace := "join-node-test" From f109b54e7953a37198ddcb8b9ea1ea297ba3265c Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 14 Oct 2022 10:38:27 +0200 Subject: [PATCH 39/55] Join test suite container to network, allowing seperate networks Signed-off-by: Kristoffer Dalby --- integration/dockertestutil/network.go | 43 ++++++++++++++++++++++++++- integration/scenario.go | 16 ++++++---- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/integration/dockertestutil/network.go b/integration/dockertestutil/network.go index b4ff87cf..15c99082 100644 --- a/integration/dockertestutil/network.go +++ b/integration/dockertestutil/network.go @@ -1,6 +1,13 @@ package dockertestutil -import "github.com/ory/dockertest/v3" +import ( + "errors" + + "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" +) + +var ErrContainerNotFound = errors.New("container not found") func GetFirstOrCreateNetwork(pool *dockertest.Pool, name string) (*dockertest.Network, error) { networks, err := pool.NetworksByName(name) @@ -19,3 +26,37 @@ func GetFirstOrCreateNetwork(pool *dockertest.Pool, name string) (*dockertest.Ne return &networks[0], nil } + +func AddContainerToNetwork( + pool *dockertest.Pool, + network *dockertest.Network, + testContainer string, +) error { + containers, err := pool.Client.ListContainers(docker.ListContainersOptions{ + All: true, + Filters: map[string][]string{ + "name": {testContainer}, + }, + }) + if err != nil { + return err + } + + err = pool.Client.ConnectNetwork(network.Network.ID, docker.NetworkConnectionOptions{ + Container: containers[0].ID, + }) + if err != nil { + return err + } + + // TODO(kradalby): This doesnt work reliably, but calling the exact same functions + // seem to work fine... + // if container, ok := pool.ContainerByName("/" + testContainer); ok { + // err := container.ConnectToNetwork(network) + // if err != nil { + // return err + // } + // } + + return nil +} diff --git a/integration/scenario.go b/integration/scenario.go index d3cbf247..b1b0719b 100644 --- a/integration/scenario.go +++ b/integration/scenario.go @@ -61,6 +61,14 @@ func NewScenario() (*Scenario, error) { return nil, fmt.Errorf("failed to create or get network: %w", err) } + // We run the test suite in a docker container that calls a couple of endpoints for + // readiness checks, this ensures that we can run the tests with individual networks + // and have the client reach the different containers + err = dockertestutil.AddContainerToNetwork(pool, network, "headscale-test-suite") + if err != nil { + return nil, fmt.Errorf("failed to add test suite container to network: %w", err) + } + return &Scenario{ controlServers: make(map[string]ControlServer), namespaces: make(map[string]*Namespace), @@ -88,11 +96,9 @@ func (s *Scenario) Shutdown() error { } } - // TODO(kradalby): This breaks the "we need to create a network before we start" - // part, since we now run the tests in a container... - // if err := s.pool.RemoveNetwork(s.network); err != nil { - // return fmt.Errorf("failed to remove network: %w", err) - // } + if err := s.pool.RemoveNetwork(s.network); err != nil { + return fmt.Errorf("failed to remove network: %w", err) + } // TODO(kradalby): This seem redundant to the previous call // if err := s.network.Close(); err != nil { From 25e39d9ff9b0da2b6a2d96633c234a067db16eb9 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 14 Oct 2022 12:17:59 +0200 Subject: [PATCH 40/55] Add get ips command to scenario Signed-off-by: Kristoffer Dalby --- integration/scenario.go | 18 ++++++++++++++++++ integration/tsic/tsic.go | 16 +++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/integration/scenario.go b/integration/scenario.go index b1b0719b..2f00daf8 100644 --- a/integration/scenario.go +++ b/integration/scenario.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "log" + "net/netip" "os" "sync" @@ -210,3 +211,20 @@ func (s *Scenario) RunTailscaleUp( return fmt.Errorf("failed to up tailscale node: %w", errNoNamespaceAvailable) } + +func (s *Scenario) GetIPs(namespace string) ([]netip.Addr, error) { + var ips []netip.Addr + if ns, ok := s.namespaces[namespace]; ok { + for _, client := range ns.Clients { + clientIps, err := client.IPs() + if err != nil { + return ips, fmt.Errorf("failed to get ips: %w", err) + } + ips = append(ips, clientIps...) + } + + return ips, nil + } + + return ips, fmt.Errorf("failed to get ips: %w", errNoNamespaceAvailable) +} diff --git a/integration/tsic/tsic.go b/integration/tsic/tsic.go index 40a0e693..4bbba8e2 100644 --- a/integration/tsic/tsic.go +++ b/integration/tsic/tsic.go @@ -17,6 +17,7 @@ const tsicHashLength = 6 const dockerContextPath = "../." var errTailscalePingFailed = errors.New("ping failed") +var errTailscaleNotLoggedIn = errors.New("tailscale not logged in") type TailscaleInContainer struct { version string @@ -102,14 +103,17 @@ func (t *TailscaleInContainer) Up( log.Println("Join command:", command) log.Printf("Running join command for %s\n", t.Hostname) - _, _, err := dockertestutil.ExecuteCommand( + stdout, stderr, err := dockertestutil.ExecuteCommand( t.container, command, []string{}, ) if err != nil { + log.Printf("tailscale join stderr: %s\n", stderr) + return err } + log.Printf("tailscale join stdout: %s\n", stdout) log.Printf("%s joined\n", t.Hostname) return nil @@ -123,12 +127,18 @@ func (t *TailscaleInContainer) IPs() ([]netip.Addr, error) { "ip", } - result, _, err := dockertestutil.ExecuteCommand( + result, stderr, err := dockertestutil.ExecuteCommand( t.container, command, []string{}, ) if err != nil { + log.Printf("failed commands stderr: %s\n", stderr) + + if strings.Contains(stderr, "NeedsLogin") { + return []netip.Addr{}, errTailscaleNotLoggedIn + } + return []netip.Addr{}, err } @@ -165,7 +175,7 @@ func (t *TailscaleInContainer) Ping(ip netip.Addr) error { return err } - if !strings.Contains(result, "pong") { + if !strings.Contains(result, "pong") || !strings.Contains(result, "is local") { return errTailscalePingFailed } From b0a4ee4dfeefa87a245b7a4fc95e60d2a67270ad Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 14 Oct 2022 12:18:28 +0200 Subject: [PATCH 41/55] test login with one node Signed-off-by: Kristoffer Dalby --- integration/scenario_test.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 8811b2f8..c13784b9 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -21,6 +21,7 @@ func IntegrationSkip(t *testing.T) { func TestHeadscale(t *testing.T) { IntegrationSkip(t) + var err error scenario, err := NewScenario() @@ -106,6 +107,8 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) { namespace := "join-node-test" + count := 1 + scenario, err := NewScenario() if err != nil { t.Errorf("failed to create scenario: %s", err) @@ -137,13 +140,13 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) { }) t.Run("create-tailscale", func(t *testing.T) { - err := scenario.CreateTailscaleNodesInNamespace(namespace, "1.32.0", 2) + err := scenario.CreateTailscaleNodesInNamespace(namespace, "1.30.2", count) if err != nil { t.Errorf("failed to add tailscale nodes: %s", err) } - if clients := len(scenario.namespaces[namespace].Clients); clients != 2 { - t.Errorf("wrong number of tailscale clients: %d != %d", clients, 2) + if clients := len(scenario.namespaces[namespace].Clients); clients != count { + t.Errorf("wrong number of tailscale clients: %d != %d", clients, count) } }) @@ -157,7 +160,17 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) { if err != nil { t.Errorf("failed to login: %s", err) } + }) + t.Run("get-ips", func(t *testing.T) { + ips, err := scenario.GetIPs(namespace) + if err != nil { + t.Errorf("failed to get tailscale ips: %s", err) + } + + if len(ips) != count*2 { + t.Errorf("got the wrong amount of tailscale ips, %d != %d", len(ips), count*2) + } }) err = scenario.Shutdown() From 13aa845c69db8a8fff44f17df2bf5d7a81d3dab3 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 14 Oct 2022 12:23:35 +0200 Subject: [PATCH 42/55] Add comment about scenario test Signed-off-by: Kristoffer Dalby --- integration/scenario_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index c13784b9..9e97bc31 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -7,6 +7,9 @@ import ( "github.com/juanfont/headscale/integration/tsic" ) +// This file is intendet to "test the test framework", by proxy it will also test +// some Headcsale/Tailscale stuff, but mostly in very simple ways. + func IntegrationSkip(t *testing.T) { t.Helper() From aef77a113ccca4734ef371cfd0996cbd61ef85c9 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 14 Oct 2022 12:38:34 +0200 Subject: [PATCH 43/55] use variable for namespace Signed-off-by: Kristoffer Dalby --- integration/scenario_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 9e97bc31..ff6f3e85 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -27,6 +27,8 @@ func TestHeadscale(t *testing.T) { var err error + namespace := "test-space" + scenario, err := NewScenario() if err != nil { t.Errorf("failed to create scenario: %s", err) @@ -46,18 +48,18 @@ func TestHeadscale(t *testing.T) { }) t.Run("create-namespace", func(t *testing.T) { - err := scenario.CreateNamespace("test-space") + err := scenario.CreateNamespace(namespace) if err != nil { t.Errorf("failed to create namespace: %s", err) } - if _, ok := scenario.namespaces["test-space"]; !ok { + if _, ok := scenario.namespaces[namespace]; !ok { t.Errorf("namespace is not in scenario") } }) t.Run("create-auth-key", func(t *testing.T) { - _, err := scenario.CreatePreAuthKey("test-space") + _, err := scenario.CreatePreAuthKey(namespace) if err != nil { t.Errorf("failed to create preauthkey: %s", err) } From 84f9f604b0fc083745ba1314f662de09c4493a0b Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 11:57:21 +0200 Subject: [PATCH 44/55] go mod tidy Signed-off-by: Kristoffer Dalby --- go.mod | 2 +- go.sum | 126 +-------------------------------------------------------- 2 files changed, 3 insertions(+), 125 deletions(-) diff --git a/go.mod b/go.mod index 24463c34..53f1fd91 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.19 require ( github.com/AlecAivazis/survey/v2 v2.3.5 github.com/ccding/go-stun/stun v0.0.0-20200514191101-4dc67bcdb029 + github.com/cenkalti/backoff/v4 v4.1.3 github.com/coreos/go-oidc/v3 v3.3.0 github.com/deckarep/golang-set/v2 v2.1.0 github.com/efekarakus/termcolor v1.0.1 @@ -54,7 +55,6 @@ require ( github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/containerd/console v1.0.3 // indirect github.com/containerd/continuity v0.3.0 // indirect diff --git a/go.sum b/go.sum index 0567a055..180e7c37 100644 --- a/go.sum +++ b/go.sum @@ -71,8 +71,6 @@ contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EU dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= -filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= -filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/mkcert v1.4.3 h1:axpnmtrZMM8u5Hf4N3UXxboGemMOV+Tn+e+pkHM6E3o= github.com/AlecAivazis/survey/v2 v2.3.5 h1:A8cYupsAZkjaUmhtTYv3sSqc7LO5mp1XDfqe5E/9wRQ= github.com/AlecAivazis/survey/v2 v2.3.5/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= @@ -80,8 +78,6 @@ github.com/Antonboom/errname v0.1.5/go.mod h1:DugbBstvPFQbv/5uLcRRzfrNqKE9tVdVCq github.com/Antonboom/nilnil v0.1.0/go.mod h1:PhHLvRPSghY5Y7mX4TW+BHZQYo1A8flE5H20D3IPZBo= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= @@ -154,7 +150,6 @@ github.com/ccding/go-stun/stun v0.0.0-20200514191101-4dc67bcdb029/go.mod h1:Rpr5 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 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -168,8 +163,6 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn 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/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4= -github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -189,8 +182,6 @@ github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvA 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.2.0 h1:2eR2MGR7thBXSQ2YbODlF0fcmgtliLCfr9iX6RW11fc= -github.com/coreos/go-oidc/v3 v3.2.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo= github.com/coreos/go-oidc/v3 v3.3.0 h1:Y1LV3mP+QT3MEycATZpAiwfyN+uxZLqVbAHJUuOJEe4= github.com/coreos/go-oidc/v3 v3.3.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -224,18 +215,12 @@ github.com/denis-tingajkin/go-header v0.4.2/go.mod h1:eLRHAVXzE5atsKAnNRDB90WHCF github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/docker/cli v20.10.16+incompatible h1:aLQ8XowgKpR3/IysPj8qZQJBVQ+Qws61icFuZl6iKYs= github.com/docker/cli v20.10.16+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M= -github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v20.10.16+incompatible h1:2Db6ZR/+FUR3hqPMwnogOPHFn405crbpxvWzKovETOQ= github.com/docker/docker v20.10.16+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE= -github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/efekarakus/termcolor v1.0.1 h1:YAKFO3bnLrqZGTWyNLcYoSIAQFKVOmbqmDnwsU/znzg= @@ -273,10 +258,10 @@ github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASx 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.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/glebarez/go-sqlite v1.17.3 h1:Rji9ROVSTTfjuWD6j5B+8DtkNvPILoUC3xRhkQzGxvk= github.com/glebarez/go-sqlite v1.17.3/go.mod h1:Hg+PQuhUy98XCxWEJEaWob8x7lhJzhNYF1nZbUiRGIY= -github.com/glebarez/go-sqlite v1.18.1 h1:w0xtxKWktqYsUsXg//SQK+l1IcpKb3rGOQHmMptvL2U= -github.com/glebarez/go-sqlite v1.18.1/go.mod h1:ydXIGq2M4OzF4YyNhH129SPp7jWoVvgkEgb6pldmS0s= github.com/glebarez/sqlite v1.4.6 h1:D5uxD2f6UJ82cHnVtO2TZ9pqsLyto3fpDKHIk2OsR8A= github.com/glebarez/sqlite v1.4.6/go.mod h1:WYEtEFjhADPaPJqL/PGlbQQGINBA3eUAfDNbKFJf/zA= github.com/go-critic/go-critic v0.6.1/go.mod h1:SdNCfU0yF3UBjtaZGw6586/WocupMOJuiqgom5DsQxM= @@ -453,8 +438,6 @@ github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= -github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI= -github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254/go.mod h1:M9mZEtGIsR1oDaZagNPNG9iq9n2HrhZ17dsXk73V3Lw= @@ -484,10 +467,7 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.2 h1:BqHID5W5qnMkug0Z8UmL8tN0gAy4jQ+B4WFt8cCgluU= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.2/go.mod h1:ZbS3MZTZq/apAfAEHGoB5HbsQQstoqP92SjAqtQ9zeg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= @@ -511,8 +491,6 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.4.0 h1:aAQzgqIrRKRa7w75CKpbBxYsmUoPjzVm1W59ca1L0J4= github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= -github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -539,13 +517,8 @@ github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -558,8 +531,6 @@ github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8 github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8= github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -568,7 +539,6 @@ github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5W github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= @@ -578,8 +548,6 @@ github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwX github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y= github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= @@ -588,21 +556,16 @@ github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrU github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs= github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y= github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= @@ -610,8 +573,6 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -625,8 +586,6 @@ github.com/josharian/txtarfs v0.0.0-20210218200122-0702f000015a/go.mod h1:izVPOv github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jsimonetti/rtnetlink v1.1.2-0.20220408201609-d380b505068b h1:Yws7RV6kZr2O7PPdT+RkbSmmOponA8i/1DuGHe8BRsM= github.com/jsimonetti/rtnetlink v1.1.2-0.20220408201609-d380b505068b/go.mod h1:TzDCVOZKUa79z6iXbbXqhtAflVgUKaFkZ21M5tK5tzY= -github.com/jsimonetti/rtnetlink v1.2.2 h1:Ok9vYMcpxfHyF/iRqNTYJPDLxVaVItvPamAhtzttDBY= -github.com/jsimonetti/rtnetlink v1.2.2/go.mod h1:T3BJ2qI9ZJFkUYWLrzECdcXhCvaGRfnMFmoYF0X8w2A= 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= @@ -713,8 +672,6 @@ github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -725,8 +682,6 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -735,7 +690,6 @@ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4 github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -749,8 +703,6 @@ github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfp github.com/mgechev/revive v1.1.2/go.mod h1:bnXsMr+ZTH09V5rssEI+jHAZ4z+ZdyhgO/zsy3EhK+0= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= -github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= @@ -777,8 +729,6 @@ github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx 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/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= -github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= 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= @@ -822,8 +772,6 @@ 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.1.2 h1:2VSZwLx5k/BfsBxMMipG/LYUnmqOD/BPkIVgQUcTlLw= github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= -github.com/opencontainers/runc v1.1.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD+5dg= -github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -845,8 +793,6 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= -github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/philip-bui/grpc-zerolog v1.0.1 h1:EMacvLRUd2O1K0eWod27ZP5CY1iTNkhBDLSN+Q4JEvA= @@ -900,8 +846,6 @@ github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5b github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= github.com/pterm/pterm v0.12.45 h1:5HATKLTDjl9D74b0x7yiHzFI7OADlSXK3yHrJNhRwZE= github.com/pterm/pterm v0.12.45/go.mod h1:hJgLlBafm45w/Hr0dKXxY//POD7CgowhePaG1sdPNBg= -github.com/puzpuzpuz/xsync v1.4.2 h1:3SmMNFuNaSHy1xsGGR8edy3Rzv0Ix3dOirPWtAnXvKk= -github.com/puzpuzpuz/xsync v1.4.2/go.mod h1:K98BYhX3k1dQ2M63t1YNVDanbwUPmBCAhNmVrrxfiGg= github.com/puzpuzpuz/xsync v1.4.3 h1:nS/Iqc4EnpJ8jm/MzJ+e3MUaP2Ys2mqXeEfoxoU0HaM= github.com/puzpuzpuz/xsync v1.4.3/go.mod h1:K98BYhX3k1dQ2M63t1YNVDanbwUPmBCAhNmVrrxfiGg= github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= @@ -916,8 +860,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6O github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.3.4 h1:3Z3Eu6FGHZWSfNKJTOUiPatWwfc7DzJRU04jFUqJODw= -github.com/rivo/uniseg v0.3.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -925,16 +867,11 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1-0.20211023094830-115ce09fd6b4 h1:Ha8xCaq6ln1a+R91Km45Oq6lPXj2Mla6CRJYcuV2h1w= github.com/rogpeppe/go-internal v1.8.1-0.20211023094830-115ce09fd6b4/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= -github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -949,7 +886,6 @@ 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.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/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= @@ -969,8 +905,6 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sivchari/tenv v1.4.7/go.mod h1:5nF+bITvkebQVanjU6IuMbvIot/7ReNsUV7I5NbprB0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -982,8 +916,6 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= -github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -1026,8 +958,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tailscale/hujson v0.0.0-20220630195928-54599719472f h1:n4r/sJ92cBSBHK8n9lR1XLFr0OiTVeGfN5TR+9LaN7E= @@ -1068,8 +998,6 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= @@ -1119,16 +1047,10 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE= go4.org/mem v0.0.0-20210711025021-927187094b94 h1:OAAkygi2Js191AJP1Ds42MhJRgeofeKGjuoUqNp1QC4= go4.org/mem v0.0.0-20210711025021-927187094b94/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= -go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= -go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= -go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf h1:IdwJUzqoIo5lkr2EOyKoe5qipUaEjbOKKY5+fzPBZ3A= -go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf/go.mod h1:+QXzaoURFd0rGDIjDNpyIkv+F9R7EmeKorvlKRnhqgA= go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d h1:ggxwEf5eu0l8v+87VhX1czFh8zJul3hK16Gmruxn7hw= go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 h1:FyBZqvoA/jbNzuAWLQE2kG820zMAkcilx6BMjGbL/E4= golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1152,8 +1074,6 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1226,7 +1146,6 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -1257,7 +1176,6 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= @@ -1282,8 +1200,6 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7 h1:dtndE8FcEta75/4kHF3AbpuWzV6f1LjnLrM4pe2SZrw= -golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8= golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1299,8 +1215,6 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc= golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1406,20 +1320,14 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1428,8 +1336,6 @@ golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc= -golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1440,8 +1346,6 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y= -golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1449,8 +1353,6 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M= golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ= -golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1571,8 +1473,6 @@ golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNq golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= golang.zx2c4.com/wireguard/windows v0.4.10 h1:HmjzJnb+G4NCdX+sfjsQlsxGPuYaThxRbZUZFLyR0/s= golang.zx2c4.com/wireguard/windows v0.4.10/go.mod h1:v7w/8FC48tTBm1IzScDVPEEb0/GjLta+T0ybpP9UWRg= -golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= -golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1709,8 +1609,6 @@ google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220808204814-fd01256a5276 h1:7PEE9xCtufpGJzrqweakEEnTh7YFELmnKm/ee+5jmfQ= -google.golang.org/genproto v0.0.0-20220808204814-fd01256a5276/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= google.golang.org/genproto v0.0.0-20220902135211-223410557253 h1:vXJMM8Shg7TGaYxZsQ++A/FOSlbDmDtWhS/o+3w/hj4= google.golang.org/genproto v0.0.0-20220902135211-223410557253/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -1748,8 +1646,6 @@ google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11 google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -1786,10 +1682,7 @@ gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -1807,14 +1700,10 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.3.8 h1:8bEphSAB69t3odsCR4NDzt581iZEWQuRM27Cg6KgfPY= -gorm.io/driver/postgres v1.3.8/go.mod h1:qB98Aj6AhRO/oyu/jmZsi/YM9g6UzVCjMxO/6frFvcA= gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg= gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U= -gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE= gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= @@ -1836,7 +1725,6 @@ modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpN modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= @@ -1845,24 +1733,14 @@ modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= modernc.org/libc v1.16.8 h1:Ux98PaOMvolgoFX/YwusFOHBnanXdGRmWgI8ciI2z4o= modernc.org/libc v1.16.8/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.17.3 h1:MbsE18Y/xJMTxGGjq2Il6aZZf1YFUu6mnRZgQm/VUWQ= -modernc.org/libc v1.17.3/go.mod h1:9y68dPDczc/zwZupQ2yLX/HTAC4YY/u3grUCeD5fC9I= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU= modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.1 h1:dkRh86wgmq/bJu2cAS2oqBCz/KsMZU7TUM4CibQ7eBs= -modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.17.3 h1:iE+coC5g17LtByDYDWKpR6m2Z9022YrSh3bumwOnIrI= modernc.org/sqlite v1.17.3/go.mod h1:10hPVYar9C0kfXuTWGz8s0XtB8uAGymUy51ZzStYe3k= -modernc.org/sqlite v1.18.1 h1:ko32eKt3jf7eqIkCgPAeHMBXw3riNSLhl2f3loEF7o8= -modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= From c90d0dd843e47cbbe5584725ff8c2b2387dd0b90 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 11:58:15 +0200 Subject: [PATCH 45/55] remove the need to bind host port Signed-off-by: Kristoffer Dalby --- integration/hsic/hsic.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/integration/hsic/hsic.go b/integration/hsic/hsic.go index 78b1ef3b..2b1eedc8 100644 --- a/integration/hsic/hsic.go +++ b/integration/hsic/hsic.go @@ -13,7 +13,6 @@ import ( v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/juanfont/headscale/integration/dockertestutil" "github.com/ory/dockertest/v3" - "github.com/ory/dockertest/v3/docker" ) const hsicHashLength = 6 @@ -46,7 +45,6 @@ func New( hostname := fmt.Sprintf("hs-%s", hash) portProto := fmt.Sprintf("%d/tcp", port) - dockerPort := docker.Port(portProto) currentPath, err := os.Getwd() if err != nil { @@ -64,9 +62,6 @@ func New( }, ExposedPorts: []string{portProto}, // TODO(kradalby): WHY do we need to bind these now that we run fully in docker? - PortBindings: map[docker.Port][]docker.PortBinding{ - dockerPort: {{HostPort: fmt.Sprintf("%d", port)}}, - }, Networks: []*dockertest.Network{network}, Cmd: []string{"headscale", "serve"}, } @@ -116,17 +111,17 @@ func (t *HeadscaleInContainer) GetPort() string { } func (t *HeadscaleInContainer) GetHealthEndpoint() string { - hostEndpoint := fmt.Sprintf("%s:%s", + hostEndpoint := fmt.Sprintf("%s:%d", t.GetIP(), - t.GetPort()) + t.port) return fmt.Sprintf("http://%s/health", hostEndpoint) } func (t *HeadscaleInContainer) GetEndpoint() string { - hostEndpoint := fmt.Sprintf("%s:%s", + hostEndpoint := fmt.Sprintf("%s:%d", t.GetIP(), - t.GetPort()) + t.port) return fmt.Sprintf("http://%s", hostEndpoint) } @@ -134,6 +129,8 @@ func (t *HeadscaleInContainer) GetEndpoint() string { func (t *HeadscaleInContainer) WaitForReady() error { url := t.GetHealthEndpoint() + log.Printf("waiting for headscale to be ready at %s", url) + return t.pool.Retry(func() error { resp, err := http.Get(url) if err != nil { From 3951f3986875ec040543606f720bf811fa40242f Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 11:58:49 +0200 Subject: [PATCH 46/55] Add wait for peers and status to tsic Signed-off-by: Kristoffer Dalby --- integration/tsic/tsic.go | 88 +++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 11 deletions(-) diff --git a/integration/tsic/tsic.go b/integration/tsic/tsic.go index 4bbba8e2..2dfd852c 100644 --- a/integration/tsic/tsic.go +++ b/integration/tsic/tsic.go @@ -1,16 +1,19 @@ package tsic import ( + "encoding/json" "errors" "fmt" "log" "net/netip" "strings" + "github.com/cenkalti/backoff/v4" "github.com/juanfont/headscale" "github.com/juanfont/headscale/integration/dockertestutil" "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" + "tailscale.com/ipn/ipnstate" ) const tsicHashLength = 6 @@ -87,6 +90,10 @@ func (t *TailscaleInContainer) Shutdown() error { return t.pool.Purge(t.container) } +func (t *TailscaleInContainer) Version() string { + return t.version +} + func (t *TailscaleInContainer) Up( loginServer, authKey string, ) error { @@ -113,12 +120,17 @@ func (t *TailscaleInContainer) Up( return err } - log.Printf("tailscale join stdout: %s\n", stdout) + + if stdout != "" { + log.Printf("tailscale join stdout: %s\n", stdout) + } + log.Printf("%s joined\n", t.Hostname) return nil } +// TODO(kradalby): Make cached/lazy func (t *TailscaleInContainer) IPs() ([]netip.Addr, error) { ips := make([]netip.Addr, 0) @@ -157,13 +169,11 @@ func (t *TailscaleInContainer) IPs() ([]netip.Addr, error) { return ips, nil } -func (t *TailscaleInContainer) Ping(ip netip.Addr) error { +func (t *TailscaleInContainer) Status() (*ipnstate.Status, error) { command := []string{ - "tailscale", "ping", - "--timeout=1s", - "--c=10", - "--until-direct=true", - ip.String(), + "tailscale", + "status", + "--json", } result, _, err := dockertestutil.ExecuteCommand( @@ -172,14 +182,70 @@ func (t *TailscaleInContainer) Ping(ip netip.Addr) error { []string{}, ) if err != nil { - return err + return nil, fmt.Errorf("failed to execute tailscale status command: %w", err) } - if !strings.Contains(result, "pong") || !strings.Contains(result, "is local") { - return errTailscalePingFailed + var status ipnstate.Status + err = json.Unmarshal([]byte(result), &status) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal tailscale status: %w", err) } - return nil + return &status, err +} + +func (t *TailscaleInContainer) WaitForPeers(expected int) error { + return t.pool.Retry(func() error { + status, err := t.Status() + if err != nil { + return fmt.Errorf("failed to fetch tailscale status: %w", err) + } + + if peers := status.Peers(); len(peers) != expected { + return fmt.Errorf( + "tailscale client does not have the expected clients: %d out of %d", + len(peers), + expected, + ) + } + + return nil + }) +} + +// TODO(kradalby): Make multiping, go routine magic +func (t *TailscaleInContainer) Ping(ip netip.Addr) error { + return t.pool.Retry(func() error { + command := []string{ + "tailscale", "ping", + "--timeout=1s", + "--c=10", + "--until-direct=true", + ip.String(), + } + + result, _, err := dockertestutil.ExecuteCommand( + t.container, + command, + []string{}, + ) + if err != nil { + log.Printf( + "failed to run ping command from %s to %s, err: %s", + t.Hostname, + ip.String(), + err, + ) + return err + } + + if !strings.Contains(result, "pong") && !strings.Contains(result, "is local") { + return backoff.Permanent(errTailscalePingFailed) + } + + return nil + }) + } func createTailscaleBuildOptions(version string) *dockertest.BuildOptions { From 0db608a7b7e2cf979d2529dbfe624b10d93a75c6 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 11:59:28 +0200 Subject: [PATCH 47/55] Add tailscale versions, waiters and helpers for scenario Signed-off-by: Kristoffer Dalby --- integration/scenario.go | 118 +++++++++++++++++++++++++++++++++-- integration/scenario_test.go | 9 ++- 2 files changed, 118 insertions(+), 9 deletions(-) diff --git a/integration/scenario.go b/integration/scenario.go index 2f00daf8..3d664b5f 100644 --- a/integration/scenario.go +++ b/integration/scenario.go @@ -7,6 +7,7 @@ import ( "net/netip" "os" "sync" + "time" "github.com/juanfont/headscale" v1 "github.com/juanfont/headscale/gen/go/headscale/v1" @@ -20,12 +21,32 @@ const scenarioHashLength = 6 var errNoHeadscaleAvailable = errors.New("no headscale available") var errNoNamespaceAvailable = errors.New("no namespace available") +var TailscaleVersions = []string{ + "head", + "unstable", + "1.32.0", + "1.30.2", + "1.28.0", + "1.26.2", + "1.24.2", + "1.22.2", + "1.20.4", + "1.18.2", + "1.16.2", + + // These versions seem to fail when fetching from apt. + // "1.14.6", + // "1.12.4", + // "1.10.2", + // "1.8.7", +} type Namespace struct { Clients map[string]*tsic.TailscaleInContainer createWaitGroup sync.WaitGroup joinWaitGroup sync.WaitGroup + syncWaitGroup sync.WaitGroup } // TODO(kradalby): make control server configurable, test test correctness with @@ -52,6 +73,8 @@ func NewScenario() (*Scenario, error) { return nil, fmt.Errorf("could not connect to docker: %w", err) } + pool.MaxWait = 60 * time.Second + networkName := fmt.Sprintf("hs-%s", hash) if overrideNetworkName := os.Getenv("HEADSCALE_TEST_NETWORK_NAME"); overrideNetworkName != "" { networkName = overrideNetworkName @@ -162,11 +185,16 @@ func (s *Scenario) CreateNamespace(namespace string) error { func (s *Scenario) CreateTailscaleNodesInNamespace( namespace string, - version string, + requestedVersion string, count int, ) error { if ns, ok := s.namespaces[namespace]; ok { for i := 0; i < count; i++ { + version := requestedVersion + if requestedVersion == "all" { + version = TailscaleVersions[i%len(TailscaleVersions)] + } + ns.createWaitGroup.Add(1) go func() { @@ -197,12 +225,12 @@ func (s *Scenario) RunTailscaleUp( for _, client := range ns.Clients { ns.joinWaitGroup.Add(1) - go func() { + go func(c *tsic.TailscaleInContainer) { defer ns.joinWaitGroup.Done() // TODO(kradalby): error handle this - _ = client.Up(loginServer, authKey) - }() + _ = c.Up(loginServer, authKey) + }(client) } ns.joinWaitGroup.Wait() @@ -212,6 +240,75 @@ func (s *Scenario) RunTailscaleUp( return fmt.Errorf("failed to up tailscale node: %w", errNoNamespaceAvailable) } +func (s *Scenario) CountTailscale() int { + count := 0 + + for _, ns := range s.namespaces { + count += len(ns.Clients) + } + + return count +} + +func (s *Scenario) WaitForTailscaleSync() error { + tsCount := s.CountTailscale() + + for _, ns := range s.namespaces { + for _, client := range ns.Clients { + ns.syncWaitGroup.Add(1) + + go func(c *tsic.TailscaleInContainer) { + defer ns.syncWaitGroup.Done() + + // TODO(kradalby): error handle this + _ = c.WaitForPeers(tsCount) + }(client) + } + ns.syncWaitGroup.Wait() + } + + return nil +} + +// CreateHeadscaleEnv is a conventient method returning a set up Headcale +// test environment with nodes of all versions, joined to the server with X +// namespaces +func (s *Scenario) CreateHeadscaleEnv(namespaces map[string]int) error { + err := s.StartHeadscale() + if err != nil { + return err + } + + err = s.Headscale().WaitForReady() + if err != nil { + return err + } + + for namespaceName, clientCount := range namespaces { + err = s.CreateNamespace(namespaceName) + if err != nil { + return err + } + + err = s.CreateTailscaleNodesInNamespace(namespaceName, "all", clientCount) + if err != nil { + return err + } + + key, err := s.CreatePreAuthKey(namespaceName) + if err != nil { + return err + } + + err = s.RunTailscaleUp(namespaceName, s.Headscale().GetEndpoint(), key.GetKey()) + if err != nil { + return err + } + } + + return nil +} + func (s *Scenario) GetIPs(namespace string) ([]netip.Addr, error) { var ips []netip.Addr if ns, ok := s.namespaces[namespace]; ok { @@ -228,3 +325,16 @@ func (s *Scenario) GetIPs(namespace string) ([]netip.Addr, error) { return ips, fmt.Errorf("failed to get ips: %w", errNoNamespaceAvailable) } + +func (s *Scenario) GetClients(namespace string) ([]*tsic.TailscaleInContainer, error) { + var clients []*tsic.TailscaleInContainer + if ns, ok := s.namespaces[namespace]; ok { + for _, client := range ns.Clients { + clients = append(clients, client) + } + + return clients, nil + } + + return clients, fmt.Errorf("failed to get clients: %w", errNoNamespaceAvailable) +} diff --git a/integration/scenario_test.go b/integration/scenario_test.go index ff6f3e85..e94e1d93 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -74,12 +74,9 @@ func TestHeadscale(t *testing.T) { func TestCreateTailscale(t *testing.T) { IntegrationSkip(t) - var scenario *Scenario - var err error - namespace := "only-create-containers" - scenario, err = NewScenario() + scenario, err := NewScenario() if err != nil { t.Errorf("failed to create scenario: %s", err) } @@ -89,7 +86,7 @@ func TestCreateTailscale(t *testing.T) { } t.Run("create-tailscale", func(t *testing.T) { - err := scenario.CreateTailscaleNodesInNamespace(namespace, "1.32.0", 3) + err := scenario.CreateTailscaleNodesInNamespace(namespace, "all", 3) if err != nil { t.Errorf("failed to add tailscale nodes: %s", err) } @@ -97,6 +94,8 @@ func TestCreateTailscale(t *testing.T) { if clients := len(scenario.namespaces[namespace].Clients); clients != 3 { t.Errorf("wrong number of tailscale clients: %d != %d", clients, 3) } + + // TODO(kradalby): Test "all" version logic }) err = scenario.Shutdown() From 39bc6f7e01f9e008f349d408d5fbeef4f62ba390 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 11:59:43 +0200 Subject: [PATCH 48/55] Port PingAll test to new test suite Signed-off-by: Kristoffer Dalby --- integration/general_test.go | 78 +++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 integration/general_test.go diff --git a/integration/general_test.go b/integration/general_test.go new file mode 100644 index 00000000..0b8db521 --- /dev/null +++ b/integration/general_test.go @@ -0,0 +1,78 @@ +package integration + +import ( + "net/netip" + "testing" + + "github.com/juanfont/headscale/integration/tsic" +) + +func TestPingAll(t *testing.T) { + IntegrationSkip(t) + + scenario, err := NewScenario() + if err != nil { + t.Errorf("failed to create scenario: %s", err) + } + + spec := map[string]int{ + "namespace1": len(TailscaleVersions), + "namespace2": len(TailscaleVersions), + } + + err = scenario.CreateHeadscaleEnv(spec) + if err != nil { + t.Errorf("failed to create headscale environment: %s", err) + } + + var allIps []netip.Addr + var allClients []*tsic.TailscaleInContainer + + for namespace, count := range spec { + ips, err := scenario.GetIPs(namespace) + if err != nil { + t.Errorf("failed to get tailscale ips: %s", err) + } + + if len(ips) != count*2 { + t.Errorf( + "got the wrong amount of tailscale ips, %d != %d", + len(ips), + count*2, + ) + } + + clients, err := scenario.GetClients(namespace) + if err != nil { + t.Errorf("failed to get tailscale clients: %s", err) + } + + allIps = append(allIps, ips...) + allClients = append(allClients, clients...) + } + + scenario.WaitForTailscaleSync() + if err != nil { + t.Errorf("failed wait for tailscale clients to be in sync: %s", err) + } + + success := 0 + + for _, client := range allClients { + for _, ip := range allIps { + err := client.Ping(ip) + if err != nil { + t.Errorf("failed to ping %s from %s: %s", ip, client.Hostname, err) + } else { + success++ + } + } + } + + t.Logf("%d successful pings out of %d", success, len(allClients)*len(allIps)) + + err = scenario.Shutdown() + if err != nil { + t.Errorf("failed to tear down scenario: %s", err) + } +} From 2bf50bc20587fe685a8ca7cd5096dcfdd044772e Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 12:03:51 +0200 Subject: [PATCH 49/55] Add new integration tests to ci Signed-off-by: Kristoffer Dalby --- .../workflows/test-integration-v2-general.yml | 40 +++++++++++++++++++ Makefile | 10 +++++ 2 files changed, 50 insertions(+) create mode 100644 .github/workflows/test-integration-v2-general.yml diff --git a/.github/workflows/test-integration-v2-general.yml b/.github/workflows/test-integration-v2-general.yml new file mode 100644 index 00000000..b76cc466 --- /dev/null +++ b/.github/workflows/test-integration-v2-general.yml @@ -0,0 +1,40 @@ +name: CI + +on: [pull_request] + +jobs: + integration-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: Set Swap Space + uses: pierotofy/set-swap-space@master + with: + swap-size-gb: 10 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v14.1 + with: + files: | + *.nix + go.* + **/*.go + integration_test/ + config-example.yaml + + - uses: cachix/install-nix-action@v16 + if: steps.changed-files.outputs.any_changed == 'true' + + - name: Run general integration tests + if: steps.changed-files.outputs.any_changed == 'true' + uses: nick-fields/retry@v2 + with: + timeout_minutes: 240 + max_attempts: 5 + retry_on: error + command: nix develop --command -- make test_integration_v2_general diff --git a/Makefile b/Makefile index c5a2d88c..de890d20 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,16 @@ test_integration_oidc: -v /var/run/docker.sock:/var/run/docker.sock golang:1 \ go test -failfast -timeout 30m -count=1 -run IntegrationOIDC ./... +test_integration_v2_general: + docker run \ + -it --rm \ + -v ~/.cache/hs-integration-go:/go \ + --name headscale-test-suite \ + -v $$PWD:$$PWD -w $$PWD \ + -v /var/run/docker.sock:/var/run/docker.sock \ + golang:1 \ + go test ./... -timeout 15m -v + coverprofile_func: go tool cover -func=coverage.out From 4cb7d63e8b7082b95837351bf4d10cf070551da2 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 12:05:17 +0200 Subject: [PATCH 50/55] Set better names for different integration tests Signed-off-by: Kristoffer Dalby --- .github/workflows/test-integration-cli.yml | 2 +- .github/workflows/test-integration-derp.yml | 2 +- .github/workflows/test-integration-general.yml | 2 +- .github/workflows/test-integration-oidc.yml | 2 +- .github/workflows/test-integration-v2-general.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-integration-cli.yml b/.github/workflows/test-integration-cli.yml index 46f48fd2..de288fd9 100644 --- a/.github/workflows/test-integration-cli.yml +++ b/.github/workflows/test-integration-cli.yml @@ -3,7 +3,7 @@ name: CI on: [pull_request] jobs: - integration-test: + integration-test-cli: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/test-integration-derp.yml b/.github/workflows/test-integration-derp.yml index 7fd391bb..88b7cf47 100644 --- a/.github/workflows/test-integration-derp.yml +++ b/.github/workflows/test-integration-derp.yml @@ -3,7 +3,7 @@ name: CI on: [pull_request] jobs: - integration-test: + integration-test-derp: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/test-integration-general.yml b/.github/workflows/test-integration-general.yml index 278548dc..01b31d96 100644 --- a/.github/workflows/test-integration-general.yml +++ b/.github/workflows/test-integration-general.yml @@ -3,7 +3,7 @@ name: CI on: [pull_request] jobs: - integration-test: + integration-test-general: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/test-integration-oidc.yml b/.github/workflows/test-integration-oidc.yml index 0f2005c5..e8afc1bf 100644 --- a/.github/workflows/test-integration-oidc.yml +++ b/.github/workflows/test-integration-oidc.yml @@ -3,7 +3,7 @@ name: CI on: [pull_request] jobs: - integration-test: + integration-test-oidc: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/test-integration-v2-general.yml b/.github/workflows/test-integration-v2-general.yml index b76cc466..fdd98d07 100644 --- a/.github/workflows/test-integration-v2-general.yml +++ b/.github/workflows/test-integration-v2-general.yml @@ -3,7 +3,7 @@ name: CI on: [pull_request] jobs: - integration-test: + integration-test-v2-general: runs-on: ubuntu-latest steps: From 36ad0003a9e10ece2ecc903f6d43cd8ad4e54afd Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 12:09:10 +0200 Subject: [PATCH 51/55] golangci-lint --fix Signed-off-by: Kristoffer Dalby --- integration/hsic/hsic.go | 9 +++++--- integration/scenario.go | 44 +++++++++++++++++++----------------- integration/scenario_test.go | 2 -- integration/tsic/tsic.go | 20 +++++++++------- 4 files changed, 41 insertions(+), 34 deletions(-) diff --git a/integration/hsic/hsic.go b/integration/hsic/hsic.go index 2b1eedc8..afe9b62c 100644 --- a/integration/hsic/hsic.go +++ b/integration/hsic/hsic.go @@ -15,8 +15,10 @@ import ( "github.com/ory/dockertest/v3" ) -const hsicHashLength = 6 -const dockerContextPath = "../." +const ( + hsicHashLength = 6 + dockerContextPath = "../." +) var errHeadscaleStatusCodeNotOk = errors.New("headscale status code not ok") @@ -32,7 +34,8 @@ type HeadscaleInContainer struct { func New( pool *dockertest.Pool, port int, - network *dockertest.Network) (*HeadscaleInContainer, error) { + network *dockertest.Network, +) (*HeadscaleInContainer, error) { hash, err := headscale.GenerateRandomStringDNSSafe(hsicHashLength) if err != nil { return nil, err diff --git a/integration/scenario.go b/integration/scenario.go index 3d664b5f..36c8a430 100644 --- a/integration/scenario.go +++ b/integration/scenario.go @@ -19,27 +19,29 @@ import ( const scenarioHashLength = 6 -var errNoHeadscaleAvailable = errors.New("no headscale available") -var errNoNamespaceAvailable = errors.New("no namespace available") -var TailscaleVersions = []string{ - "head", - "unstable", - "1.32.0", - "1.30.2", - "1.28.0", - "1.26.2", - "1.24.2", - "1.22.2", - "1.20.4", - "1.18.2", - "1.16.2", +var ( + errNoHeadscaleAvailable = errors.New("no headscale available") + errNoNamespaceAvailable = errors.New("no namespace available") + TailscaleVersions = []string{ + "head", + "unstable", + "1.32.0", + "1.30.2", + "1.28.0", + "1.26.2", + "1.24.2", + "1.22.2", + "1.20.4", + "1.18.2", + "1.16.2", - // These versions seem to fail when fetching from apt. - // "1.14.6", - // "1.12.4", - // "1.10.2", - // "1.8.7", -} + // These versions seem to fail when fetching from apt. + // "1.14.6", + // "1.12.4", + // "1.10.2", + // "1.8.7", + } +) type Namespace struct { Clients map[string]*tsic.TailscaleInContainer @@ -272,7 +274,7 @@ func (s *Scenario) WaitForTailscaleSync() error { // CreateHeadscaleEnv is a conventient method returning a set up Headcale // test environment with nodes of all versions, joined to the server with X -// namespaces +// namespaces. func (s *Scenario) CreateHeadscaleEnv(namespaces map[string]int) error { err := s.StartHeadscale() if err != nil { diff --git a/integration/scenario_test.go b/integration/scenario_test.go index e94e1d93..c1a51f30 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -44,7 +44,6 @@ func TestHeadscale(t *testing.T) { if err != nil { t.Errorf("headscale failed to become ready: %s", err) } - }) t.Run("create-namespace", func(t *testing.T) { @@ -129,7 +128,6 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) { if err != nil { t.Errorf("headscale failed to become ready: %s", err) } - }) t.Run("create-namespace", func(t *testing.T) { diff --git a/integration/tsic/tsic.go b/integration/tsic/tsic.go index 2dfd852c..ef89b229 100644 --- a/integration/tsic/tsic.go +++ b/integration/tsic/tsic.go @@ -16,11 +16,15 @@ import ( "tailscale.com/ipn/ipnstate" ) -const tsicHashLength = 6 -const dockerContextPath = "../." +const ( + tsicHashLength = 6 + dockerContextPath = "../." +) -var errTailscalePingFailed = errors.New("ping failed") -var errTailscaleNotLoggedIn = errors.New("tailscale not logged in") +var ( + errTailscalePingFailed = errors.New("ping failed") + errTailscaleNotLoggedIn = errors.New("tailscale not logged in") +) type TailscaleInContainer struct { version string @@ -34,7 +38,8 @@ type TailscaleInContainer struct { func New( pool *dockertest.Pool, version string, - network *dockertest.Network) (*TailscaleInContainer, error) { + network *dockertest.Network, +) (*TailscaleInContainer, error) { hash, err := headscale.GenerateRandomStringDNSSafe(tsicHashLength) if err != nil { return nil, err @@ -130,7 +135,7 @@ func (t *TailscaleInContainer) Up( return nil } -// TODO(kradalby): Make cached/lazy +// TODO(kradalby): Make cached/lazy. func (t *TailscaleInContainer) IPs() ([]netip.Addr, error) { ips := make([]netip.Addr, 0) @@ -213,7 +218,7 @@ func (t *TailscaleInContainer) WaitForPeers(expected int) error { }) } -// TODO(kradalby): Make multiping, go routine magic +// TODO(kradalby): Make multiping, go routine magic. func (t *TailscaleInContainer) Ping(ip netip.Addr) error { return t.pool.Retry(func() error { command := []string{ @@ -245,7 +250,6 @@ func (t *TailscaleInContainer) Ping(ip netip.Addr) error { return nil }) - } func createTailscaleBuildOptions(version string) *dockertest.BuildOptions { From 8502a0acda2c429073f8593a0f20e8daf6d46bd9 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 12:09:57 +0200 Subject: [PATCH 52/55] dont request tty Signed-off-by: Kristoffer Dalby --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index de890d20..72925347 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,7 @@ test_integration_oidc: test_integration_v2_general: docker run \ - -it --rm \ + -t --rm \ -v ~/.cache/hs-integration-go:/go \ --name headscale-test-suite \ -v $$PWD:$$PWD -w $$PWD \ From 12ee9bc02dccbbfe1c8088546441f0ca98b9afe1 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 12:19:43 +0200 Subject: [PATCH 53/55] Fix golangcilint Signed-off-by: Kristoffer Dalby --- integration/general_test.go | 2 +- integration/hsic/hsic.go | 2 +- integration/scenario.go | 49 ++++++++++++++++++++----------------- integration/tsic/tsic.go | 12 ++++----- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/integration/general_test.go b/integration/general_test.go index 0b8db521..2e7689ac 100644 --- a/integration/general_test.go +++ b/integration/general_test.go @@ -51,7 +51,7 @@ func TestPingAll(t *testing.T) { allClients = append(allClients, clients...) } - scenario.WaitForTailscaleSync() + err = scenario.WaitForTailscaleSync() if err != nil { t.Errorf("failed wait for tailscale clients to be in sync: %s", err) } diff --git a/integration/hsic/hsic.go b/integration/hsic/hsic.go index afe9b62c..1790a0a2 100644 --- a/integration/hsic/hsic.go +++ b/integration/hsic/hsic.go @@ -135,7 +135,7 @@ func (t *HeadscaleInContainer) WaitForReady() error { log.Printf("waiting for headscale to be ready at %s", url) return t.pool.Retry(func() error { - resp, err := http.Get(url) + resp, err := http.Get(url) //nolint if err != nil { return fmt.Errorf("headscale is not ready: %w", err) } diff --git a/integration/scenario.go b/integration/scenario.go index 36c8a430..0b8d2022 100644 --- a/integration/scenario.go +++ b/integration/scenario.go @@ -18,6 +18,8 @@ import ( ) const scenarioHashLength = 6 +const maxWait = 60 * time.Second +const headscalePort = 8080 var ( errNoHeadscaleAvailable = errors.New("no headscale available") @@ -75,7 +77,7 @@ func NewScenario() (*Scenario, error) { return nil, fmt.Errorf("could not connect to docker: %w", err) } - pool.MaxWait = 60 * time.Second + pool.MaxWait = maxWait networkName := fmt.Sprintf("hs-%s", hash) if overrideNetworkName := os.Getenv("HEADSCALE_TEST_NETWORK_NAME"); overrideNetworkName != "" { @@ -139,7 +141,7 @@ func (s *Scenario) Shutdown() error { // TODO(kradalby): make port and headscale configurable, multiple instances support? func (s *Scenario) StartHeadscale() error { - headscale, err := hsic.New(s.pool, 8080, s.network) + headscale, err := hsic.New(s.pool, headscalePort, s.network) if err != nil { return fmt.Errorf("failed to create headscale container: %w", err) } @@ -150,6 +152,7 @@ func (s *Scenario) StartHeadscale() error { } func (s *Scenario) Headscale() *hsic.HeadscaleInContainer { + //nolint return s.controlServers["headscale"].(*hsic.HeadscaleInContainer) } @@ -186,33 +189,33 @@ func (s *Scenario) CreateNamespace(namespace string) error { /// Client related stuff func (s *Scenario) CreateTailscaleNodesInNamespace( - namespace string, + namespaceStr string, requestedVersion string, count int, ) error { - if ns, ok := s.namespaces[namespace]; ok { + if namespace, ok := s.namespaces[namespaceStr]; ok { for i := 0; i < count; i++ { version := requestedVersion if requestedVersion == "all" { version = TailscaleVersions[i%len(TailscaleVersions)] } - ns.createWaitGroup.Add(1) + namespace.createWaitGroup.Add(1) go func() { - defer ns.createWaitGroup.Done() + defer namespace.createWaitGroup.Done() // TODO(kradalby): error handle this - ts, err := tsic.New(s.pool, version, s.network) + tsClient, err := tsic.New(s.pool, version, s.network) if err != nil { // return fmt.Errorf("failed to add tailscale node: %w", err) - fmt.Printf("failed to add tailscale node: %s", err) + log.Printf("failed to add tailscale node: %s", err) } - ns.Clients[ts.Hostname] = ts + namespace.Clients[tsClient.Hostname] = tsClient }() } - ns.createWaitGroup.Wait() + namespace.createWaitGroup.Wait() return nil } @@ -221,20 +224,20 @@ func (s *Scenario) CreateTailscaleNodesInNamespace( } func (s *Scenario) RunTailscaleUp( - namespace, loginServer, authKey string, + namespaceStr, loginServer, authKey string, ) error { - if ns, ok := s.namespaces[namespace]; ok { - for _, client := range ns.Clients { - ns.joinWaitGroup.Add(1) + if namespace, ok := s.namespaces[namespaceStr]; ok { + for _, client := range namespace.Clients { + namespace.joinWaitGroup.Add(1) go func(c *tsic.TailscaleInContainer) { - defer ns.joinWaitGroup.Done() + defer namespace.joinWaitGroup.Done() // TODO(kradalby): error handle this _ = c.Up(loginServer, authKey) }(client) } - ns.joinWaitGroup.Wait() + namespace.joinWaitGroup.Wait() return nil } @@ -245,8 +248,8 @@ func (s *Scenario) RunTailscaleUp( func (s *Scenario) CountTailscale() int { count := 0 - for _, ns := range s.namespaces { - count += len(ns.Clients) + for _, namespace := range s.namespaces { + count += len(namespace.Clients) } return count @@ -255,18 +258,18 @@ func (s *Scenario) CountTailscale() int { func (s *Scenario) WaitForTailscaleSync() error { tsCount := s.CountTailscale() - for _, ns := range s.namespaces { - for _, client := range ns.Clients { - ns.syncWaitGroup.Add(1) + for _, namespace := range s.namespaces { + for _, client := range namespace.Clients { + namespace.syncWaitGroup.Add(1) go func(c *tsic.TailscaleInContainer) { - defer ns.syncWaitGroup.Done() + defer namespace.syncWaitGroup.Done() // TODO(kradalby): error handle this _ = c.WaitForPeers(tsCount) }(client) } - ns.syncWaitGroup.Wait() + namespace.syncWaitGroup.Wait() } return nil diff --git a/integration/tsic/tsic.go b/integration/tsic/tsic.go index ef89b229..f3188135 100644 --- a/integration/tsic/tsic.go +++ b/integration/tsic/tsic.go @@ -22,8 +22,9 @@ const ( ) var ( - errTailscalePingFailed = errors.New("ping failed") - errTailscaleNotLoggedIn = errors.New("tailscale not logged in") + errTailscalePingFailed = errors.New("ping failed") + errTailscaleNotLoggedIn = errors.New("tailscale not logged in") + errTailscaleWrongPeerCount = errors.New("wrong peer count") ) type TailscaleInContainer struct { @@ -207,11 +208,7 @@ func (t *TailscaleInContainer) WaitForPeers(expected int) error { } if peers := status.Peers(); len(peers) != expected { - return fmt.Errorf( - "tailscale client does not have the expected clients: %d out of %d", - len(peers), - expected, - ) + return errTailscaleWrongPeerCount } return nil @@ -241,6 +238,7 @@ func (t *TailscaleInContainer) Ping(ip netip.Addr) error { ip.String(), err, ) + return err } From 6d8c18d4de57247895449e364f693b406660625a Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 12:21:38 +0200 Subject: [PATCH 54/55] Fix golangcilint Signed-off-by: Kristoffer Dalby --- integration/scenario.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/integration/scenario.go b/integration/scenario.go index 0b8d2022..ebe3aff2 100644 --- a/integration/scenario.go +++ b/integration/scenario.go @@ -17,9 +17,11 @@ import ( "github.com/ory/dockertest/v3" ) -const scenarioHashLength = 6 -const maxWait = 60 * time.Second -const headscalePort = 8080 +const ( + scenarioHashLength = 6 + maxWait = 60 * time.Second + headscalePort = 8080 +) var ( errNoHeadscaleAvailable = errors.New("no headscale available") From b2bca2ac815ddf1002d8078f364dab82d733249a Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 18 Oct 2022 16:00:24 +0200 Subject: [PATCH 55/55] Only run integration tests from dir in new tests Signed-off-by: Kristoffer Dalby --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 72925347..431e1076 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ test_integration_v2_general: -t --rm \ -v ~/.cache/hs-integration-go:/go \ --name headscale-test-suite \ - -v $$PWD:$$PWD -w $$PWD \ + -v $$PWD:$$PWD -w $$PWD/integration \ -v /var/run/docker.sock:/var/run/docker.sock \ golang:1 \ go test ./... -timeout 15m -v