diff --git a/acls.go b/acls.go index cb02e04..0e01514 100644 --- a/acls.go +++ b/acls.go @@ -108,7 +108,9 @@ func (h *Headscale) generateACLPolicySrcIP(u string) ([]string, error) { return h.expandAlias(u) } -func (h *Headscale) generateACLPolicyDestPorts(d string) ([]tailcfg.NetPortRange, error) { +func (h *Headscale) generateACLPolicyDestPorts( + d string, +) ([]tailcfg.NetPortRange, error) { tokens := strings.Split(d, ":") if len(tokens) < 2 || len(tokens) > 3 { return nil, errorInvalidPortFormat diff --git a/acls_test.go b/acls_test.go index da7f3ec..c178805 100644 --- a/acls_test.go +++ b/acls_test.go @@ -22,7 +22,11 @@ func (s *Suite) TestInvalidPolicyHuson(c *check.C) { func (s *Suite) TestParseHosts(c *check.C) { var hs Hosts - err := hs.UnmarshalJSON([]byte(`{"example-host-1": "100.100.100.100","example-host-2": "100.100.101.100/24"}`)) + err := hs.UnmarshalJSON( + []byte( + `{"example-host-1": "100.100.100.100","example-host-2": "100.100.101.100/24"}`, + ), + ) c.Assert(hs, check.NotNil) c.Assert(err, check.IsNil) } diff --git a/api.go b/api.go index 490ce25..25851d8 100644 --- a/api.go +++ b/api.go @@ -95,7 +95,8 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) { Str("handler", "Registration"). Err(err). Msg("Could not create row") - machineRegistrations.WithLabelValues("unknown", "web", "error", m.Namespace.Name).Inc() + machineRegistrations.WithLabelValues("unknown", "web", "error", m.Namespace.Name). + Inc() return } m = &newMachine @@ -156,11 +157,13 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) { Str("handler", "Registration"). Err(err). Msg("Cannot encode message") - machineRegistrations.WithLabelValues("update", "web", "error", m.Namespace.Name).Inc() + machineRegistrations.WithLabelValues("update", "web", "error", m.Namespace.Name). + Inc() c.String(http.StatusInternalServerError, "") return } - machineRegistrations.WithLabelValues("update", "web", "success", m.Namespace.Name).Inc() + machineRegistrations.WithLabelValues("update", "web", "success", m.Namespace.Name). + Inc() c.Data(200, "application/json; charset=utf-8", respBody) return } @@ -195,11 +198,13 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) { Str("handler", "Registration"). Err(err). Msg("Cannot encode message") - machineRegistrations.WithLabelValues("new", "web", "error", m.Namespace.Name).Inc() + machineRegistrations.WithLabelValues("new", "web", "error", m.Namespace.Name). + Inc() c.String(http.StatusInternalServerError, "") return } - machineRegistrations.WithLabelValues("new", "web", "success", m.Namespace.Name).Inc() + machineRegistrations.WithLabelValues("new", "web", "success", m.Namespace.Name). + Inc() c.Data(200, "application/json; charset=utf-8", respBody) return } @@ -234,7 +239,11 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) { Str("machine", m.Name). Msg("The node is sending us a new NodeKey, sending auth url") if h.cfg.OIDC.Issuer != "" { - resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s", strings.TrimSuffix(h.cfg.ServerURL, "/"), mKey.HexString()) + resp.AuthURL = fmt.Sprintf( + "%s/oidc/register/%s", + strings.TrimSuffix(h.cfg.ServerURL, "/"), + mKey.HexString(), + ) } else { resp.AuthURL = fmt.Sprintf("%s/register?key=%s", strings.TrimSuffix(h.cfg.ServerURL, "/"), mKey.HexString()) @@ -257,7 +266,11 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) { c.Data(200, "application/json; charset=utf-8", respBody) } -func (h *Headscale) getMapResponse(mKey wgkey.Key, req tailcfg.MapRequest, m *Machine) ([]byte, error) { +func (h *Headscale) getMapResponse( + mKey wgkey.Key, + req tailcfg.MapRequest, + m *Machine, +) ([]byte, error) { log.Trace(). Str("func", "getMapResponse"). Str("machine", req.Hostinfo.Hostname). @@ -291,7 +304,12 @@ func (h *Headscale) getMapResponse(mKey wgkey.Key, req tailcfg.MapRequest, m *Ma return nil, err } - dnsConfig, err := getMapResponseDNSConfig(h.cfg.DNSConfig, h.cfg.BaseDomain, *m, peers) + dnsConfig, err := getMapResponseDNSConfig( + h.cfg.DNSConfig, + h.cfg.BaseDomain, + *m, + peers, + ) if err != nil { log.Error(). Str("func", "getMapResponse"). @@ -340,7 +358,11 @@ func (h *Headscale) getMapResponse(mKey wgkey.Key, req tailcfg.MapRequest, m *Ma return data, nil } -func (h *Headscale) getMapKeepAliveResponse(mKey wgkey.Key, req tailcfg.MapRequest, m *Machine) ([]byte, error) { +func (h *Headscale) getMapKeepAliveResponse( + mKey wgkey.Key, + req tailcfg.MapRequest, + m *Machine, +) ([]byte, error) { resp := tailcfg.MapResponse{ KeepAlive: true, } @@ -394,7 +416,8 @@ func (h *Headscale) handleAuthKey( Err(err). Msg("Cannot encode message") c.String(http.StatusInternalServerError, "") - machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name).Inc() + machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name). + Inc() return } c.Data(401, "application/json; charset=utf-8", respBody) @@ -402,7 +425,8 @@ func (h *Headscale) handleAuthKey( Str("func", "handleAuthKey"). Str("machine", m.Name). Msg("Failed authentication via AuthKey") - machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name).Inc() + machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name). + Inc() return } @@ -416,7 +440,8 @@ func (h *Headscale) handleAuthKey( Str("func", "handleAuthKey"). Str("machine", m.Name). Msg("Failed to find an available IP") - machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name).Inc() + machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name). + Inc() return } log.Info(). @@ -445,11 +470,13 @@ func (h *Headscale) handleAuthKey( Str("machine", m.Name). Err(err). Msg("Cannot encode message") - machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name).Inc() + machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name). + Inc() c.String(http.StatusInternalServerError, "Extremely sad!") return } - machineRegistrations.WithLabelValues("new", "authkey", "success", m.Namespace.Name).Inc() + machineRegistrations.WithLabelValues("new", "authkey", "success", m.Namespace.Name). + Inc() c.Data(200, "application/json; charset=utf-8", respBody) log.Info(). Str("func", "handleAuthKey"). diff --git a/app.go b/app.go index c226062..94181ac 100644 --- a/app.go +++ b/app.go @@ -152,8 +152,14 @@ func NewHeadscale(cfg Config) (*Headscale, error) { var dbString string switch cfg.DBtype { case "postgres": - dbString = fmt.Sprintf("host=%s port=%d dbname=%s user=%s password=%s sslmode=disable", cfg.DBhost, - cfg.DBport, cfg.DBname, cfg.DBuser, cfg.DBpass) + dbString = fmt.Sprintf( + "host=%s port=%d dbname=%s user=%s password=%s sslmode=disable", + cfg.DBhost, + cfg.DBport, + cfg.DBname, + cfg.DBuser, + cfg.DBpass, + ) case "sqlite3": dbString = cfg.DBpath default: @@ -182,7 +188,10 @@ func NewHeadscale(cfg Config) (*Headscale, error) { } if h.cfg.DNSConfig != nil && h.cfg.DNSConfig.Proxied { // if MagicDNS - magicDNSDomains, err := generateMagicDNSRootDomains(h.cfg.IPPrefix, h.cfg.BaseDomain) + magicDNSDomains, err := generateMagicDNSRootDomains( + h.cfg.IPPrefix, + h.cfg.BaseDomain, + ) if err != nil { return nil, err } @@ -224,7 +233,10 @@ func (h *Headscale) expireEphemeralNodesWorker() { for _, ns := range namespaces { machines, err := h.ListMachinesInNamespace(ns.Name) if err != nil { - log.Error().Err(err).Str("namespace", ns.Name).Msg("Error listing machines in namespace") + log.Error(). + Err(err). + Str("namespace", ns.Name). + Msg("Error listing machines in namespace") return } @@ -232,7 +244,9 @@ func (h *Headscale) expireEphemeralNodesWorker() { for _, m := range machines { if m.AuthKey != nil && m.LastSeen != nil && m.AuthKey.Ephemeral && time.Now().After(m.LastSeen.Add(h.cfg.EphemeralNodeInactivityTimeout)) { - log.Info().Str("machine", m.Name).Msg("Ephemeral client removed from database") + log.Info(). + Str("machine", m.Name). + Msg("Ephemeral client removed from database") err = h.db.Unscoped().Delete(m).Error if err != nil { @@ -274,18 +288,33 @@ func (h *Headscale) grpcAuthenticationInterceptor(ctx context.Context, // the server p, _ := peer.FromContext(ctx) - log.Trace().Caller().Str("client_address", p.Addr.String()).Msg("Client is trying to authenticate") + log.Trace(). + Caller(). + Str("client_address", p.Addr.String()). + Msg("Client is trying to authenticate") md, ok := metadata.FromIncomingContext(ctx) if !ok { - log.Error().Caller().Str("client_address", p.Addr.String()).Msg("Retrieving metadata is failed") - return ctx, status.Errorf(codes.InvalidArgument, "Retrieving metadata is failed") + log.Error(). + Caller(). + Str("client_address", p.Addr.String()). + Msg("Retrieving metadata is failed") + return ctx, status.Errorf( + codes.InvalidArgument, + "Retrieving metadata is failed", + ) } authHeader, ok := md["authorization"] if !ok { - log.Error().Caller().Str("client_address", p.Addr.String()).Msg("Authorization token is not supplied") - return ctx, status.Errorf(codes.Unauthenticated, "Authorization token is not supplied") + log.Error(). + Caller(). + Str("client_address", p.Addr.String()). + Msg("Authorization token is not supplied") + return ctx, status.Errorf( + codes.Unauthenticated, + "Authorization token is not supplied", + ) } token := authHeader[0] @@ -295,7 +324,10 @@ func (h *Headscale) grpcAuthenticationInterceptor(ctx context.Context, Caller(). Str("client_address", p.Addr.String()). Msg(`missing "Bearer " prefix in "Authorization" header`) - return ctx, status.Error(codes.Unauthenticated, `missing "Bearer " prefix in "Authorization" header`) + return ctx, status.Error( + codes.Unauthenticated, + `missing "Bearer " prefix in "Authorization" header`, + ) } // TODO(kradalby): Implement API key backend: @@ -307,7 +339,10 @@ func (h *Headscale) grpcAuthenticationInterceptor(ctx context.Context, // Currently all other than localhost traffic is unauthorized, this is intentional to allow // us to make use of gRPC for our CLI, but not having to implement any of the remote capabilities // and API key auth - return ctx, status.Error(codes.Unauthenticated, "Authentication is not implemented yet") + return ctx, status.Error( + codes.Unauthenticated, + "Authentication is not implemented yet", + ) //if strings.TrimPrefix(token, AUTH_PREFIX) != a.Token { // log.Error().Caller().Str("client_address", p.Addr.String()).Msg("invalid token") @@ -405,7 +440,10 @@ func (h *Headscale) Serve() error { // Match gRPC requests here grpcListener := m.MatchWithWriters( cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc"), - cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc+proto"), + cmux.HTTP2MatchHeaderFieldSendSettings( + "content-type", + "application/grpc+proto", + ), ) // Otherwise match regular http requests. httpListener := m.Match(cmux.Any()) @@ -436,7 +474,10 @@ func (h *Headscale) Serve() error { p := ginprometheus.NewPrometheus("gin") p.Use(r) - r.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"healthy": "ok"}) }) + r.GET( + "/health", + func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"healthy": "ok"}) }, + ) r.GET("/key", h.KeyHandler) r.GET("/register", h.RegisterWebAPI) r.POST("/machine/:id/map", h.PollNetMapHandler) @@ -537,7 +578,8 @@ func (h *Headscale) Serve() error { g.Go(func() error { return m.Serve() }) - log.Info().Msgf("listening and serving (multiplexed HTTP and gRPC) on: %s", h.cfg.Addr) + log.Info(). + Msgf("listening and serving (multiplexed HTTP and gRPC) on: %s", h.cfg.Addr) return g.Wait() } @@ -545,7 +587,8 @@ func (h *Headscale) Serve() error { func (h *Headscale) getTLSSettings() (*tls.Config, error) { if h.cfg.TLSLetsEncryptHostname != "" { if !strings.HasPrefix(h.cfg.ServerURL, "https://") { - log.Warn().Msg("Listening with TLS but ServerURL does not start with https://") + log.Warn(). + Msg("Listening with TLS but ServerURL does not start with https://") } m := autocert.Manager{ diff --git a/app_test.go b/app_test.go index 5e53f1c..ec23282 100644 --- a/app_test.go +++ b/app_test.go @@ -17,8 +17,10 @@ var _ = check.Suite(&Suite{}) type Suite struct{} -var tmpDir string -var h Headscale +var ( + tmpDir string + h Headscale +) func (s *Suite) SetUpTest(c *check.C) { s.ResetDB(c) diff --git a/apple_mobileconfig.go b/apple_mobileconfig.go index f3956e3..6ddd5be 100644 --- a/apple_mobileconfig.go +++ b/apple_mobileconfig.go @@ -73,7 +73,11 @@ func (h *Headscale) AppleMobileConfig(c *gin.Context) { Str("handler", "AppleMobileConfig"). Err(err). Msg("Could not render Apple index template") - c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Could not render Apple index template")) + c.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Could not render Apple index template"), + ) return } @@ -89,7 +93,11 @@ func (h *Headscale) ApplePlatformConfig(c *gin.Context) { Str("handler", "ApplePlatformConfig"). Err(err). Msg("Failed not create UUID") - c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Failed to create UUID")) + c.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Failed to create UUID"), + ) return } @@ -99,7 +107,11 @@ func (h *Headscale) ApplePlatformConfig(c *gin.Context) { Str("handler", "ApplePlatformConfig"). Err(err). Msg("Failed not create UUID") - c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Failed to create UUID")) + c.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Failed to create UUID"), + ) return } @@ -117,7 +129,11 @@ func (h *Headscale) ApplePlatformConfig(c *gin.Context) { Str("handler", "ApplePlatformConfig"). Err(err). Msg("Could not render Apple macOS template") - c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Could not render Apple macOS template")) + c.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Could not render Apple macOS template"), + ) return } case "ios": @@ -126,11 +142,19 @@ func (h *Headscale) ApplePlatformConfig(c *gin.Context) { Str("handler", "ApplePlatformConfig"). Err(err). Msg("Could not render Apple iOS template") - c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Could not render Apple iOS template")) + c.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Could not render Apple iOS template"), + ) return } default: - c.Data(http.StatusOK, "text/html; charset=utf-8", []byte("Invalid platform, only ios and macos is supported")) + c.Data( + http.StatusOK, + "text/html; charset=utf-8", + []byte("Invalid platform, only ios and macos is supported"), + ) return } @@ -146,11 +170,19 @@ func (h *Headscale) ApplePlatformConfig(c *gin.Context) { Str("handler", "ApplePlatformConfig"). Err(err). Msg("Could not render Apple platform template") - c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Could not render Apple platform template")) + c.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Could not render Apple platform template"), + ) return } - c.Data(http.StatusOK, "application/x-apple-aspen-config; charset=utf-8", content.Bytes()) + c.Data( + http.StatusOK, + "application/x-apple-aspen-config; charset=utf-8", + content.Bytes(), + ) } type AppleMobileConfig struct { @@ -164,7 +196,8 @@ type AppleMobilePlatformConfig struct { Url string } -var commonTemplate = template.Must(template.New("mobileconfig").Parse(` +var commonTemplate = template.Must( + template.New("mobileconfig").Parse(` @@ -187,7 +220,8 @@ var commonTemplate = template.Must(template.New("mobileconfig").Parse(` -`)) +`), +) var iosTemplate = template.Must(template.New("iosTemplate").Parse(` diff --git a/cli_test.go b/cli_test.go index 291b5df..6c0b2bb 100644 --- a/cli_test.go +++ b/cli_test.go @@ -28,7 +28,10 @@ func (s *Suite) TestRegisterMachine(c *check.C) { _, err = h.GetMachine("test", "testmachine") c.Assert(err, check.IsNil) - m2, err := h.RegisterMachine("8ce002a935f8c394e55e78fbbb410576575ff8ec5cfa2e627e4b807f1be15b0e", n.Name) + m2, err := h.RegisterMachine( + "8ce002a935f8c394e55e78fbbb410576575ff8ec5cfa2e627e4b807f1be15b0e", + n.Name, + ) c.Assert(err, check.IsNil) c.Assert(m2.Registered, check.Equals, true) diff --git a/cmd/headscale/cli/debug.go b/cmd/headscale/cli/debug.go index e140156..f106efa 100644 --- a/cmd/headscale/cli/debug.go +++ b/cmd/headscale/cli/debug.go @@ -27,7 +27,8 @@ func init() { if err != nil { log.Fatal().Err(err).Msg("") } - createNodeCmd.Flags().StringSliceP("route", "r", []string{}, "List (or repeated flags) of routes to advertise") + createNodeCmd.Flags(). + StringSliceP("route", "r", []string{}, "List (or repeated flags) of routes to advertise") debugCmd.AddCommand(createNodeCmd) } @@ -56,19 +57,31 @@ var createNodeCmd = &cobra.Command{ name, err := cmd.Flags().GetString("name") if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting node from flag: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Error getting node from flag: %s", err), + output, + ) return } machineKey, err := cmd.Flags().GetString("key") if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting key from flag: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Error getting key from flag: %s", err), + output, + ) return } routes, err := cmd.Flags().GetStringSlice("route") if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting routes from flag: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Error getting routes from flag: %s", err), + output, + ) return } @@ -81,7 +94,11 @@ var createNodeCmd = &cobra.Command{ response, err := client.DebugCreateMachine(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot create machine: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf("Cannot create machine: %s", status.Convert(err).Message()), + output, + ) return } diff --git a/cmd/headscale/cli/namespaces.go b/cmd/headscale/cli/namespaces.go index 752638a..3a11178 100644 --- a/cmd/headscale/cli/namespaces.go +++ b/cmd/headscale/cli/namespaces.go @@ -48,7 +48,14 @@ var createNamespaceCmd = &cobra.Command{ log.Trace().Interface("request", request).Msg("Sending CreateNamespace request") response, err := client.CreateNamespace(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot create namespace: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf( + "Cannot create namespace: %s", + status.Convert(err).Message(), + ), + output, + ) return } @@ -78,7 +85,14 @@ var destroyNamespaceCmd = &cobra.Command{ response, err := client.DeleteNamespace(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot destroy namespace: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf( + "Cannot destroy namespace: %s", + status.Convert(err).Message(), + ), + output, + ) return } @@ -100,7 +114,11 @@ var listNamespacesCmd = &cobra.Command{ response, err := client.ListNamespaces(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot get namespaces: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf("Cannot get namespaces: %s", status.Convert(err).Message()), + output, + ) return } @@ -122,7 +140,11 @@ var listNamespacesCmd = &cobra.Command{ } err = pterm.DefaultTable.WithHasHeader().WithData(d).Render() if err != nil { - ErrorOutput(err, fmt.Sprintf("Failed to render pterm table: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Failed to render pterm table: %s", err), + output, + ) return } }, @@ -151,7 +173,14 @@ var renameNamespaceCmd = &cobra.Command{ response, err := client.RenameNamespace(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot rename namespace: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf( + "Cannot rename namespace: %s", + status.Convert(err).Message(), + ), + output, + ) return } diff --git a/cmd/headscale/cli/nodes.go b/cmd/headscale/cli/nodes.go index 9b3f424..934ac49 100644 --- a/cmd/headscale/cli/nodes.go +++ b/cmd/headscale/cli/nodes.go @@ -86,7 +86,11 @@ var registerNodeCmd = &cobra.Command{ machineKey, err := cmd.Flags().GetString("key") if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting machine key from flag: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Error getting machine key from flag: %s", err), + output, + ) return } @@ -97,7 +101,14 @@ var registerNodeCmd = &cobra.Command{ response, err := client.RegisterMachine(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot register machine: %s\n", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf( + "Cannot register machine: %s\n", + status.Convert(err).Message(), + ), + output, + ) return } @@ -126,7 +137,11 @@ var listNodesCmd = &cobra.Command{ response, err := client.ListMachines(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot get nodes: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf("Cannot get nodes: %s", status.Convert(err).Message()), + output, + ) return } @@ -143,7 +158,11 @@ var listNodesCmd = &cobra.Command{ err = pterm.DefaultTable.WithHasHeader().WithData(d).Render() if err != nil { - ErrorOutput(err, fmt.Sprintf("Failed to render pterm table: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Failed to render pterm table: %s", err), + output, + ) return } }, @@ -157,7 +176,11 @@ var deleteNodeCmd = &cobra.Command{ id, err := cmd.Flags().GetInt("identifier") if err != nil { - ErrorOutput(err, fmt.Sprintf("Error converting ID to integer: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Error converting ID to integer: %s", err), + output, + ) return } @@ -171,7 +194,14 @@ var deleteNodeCmd = &cobra.Command{ getResponse, err := client.GetMachine(ctx, getRequest) if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting node node: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf( + "Error getting node node: %s", + status.Convert(err).Message(), + ), + output, + ) return } @@ -183,7 +213,10 @@ var deleteNodeCmd = &cobra.Command{ force, _ := cmd.Flags().GetBool("force") if !force { prompt := &survey.Confirm{ - Message: fmt.Sprintf("Do you want to remove the node %s?", getResponse.GetMachine().Name), + Message: fmt.Sprintf( + "Do you want to remove the node %s?", + getResponse.GetMachine().Name, + ), } err = survey.AskOne(prompt, &confirm) if err != nil { @@ -198,10 +231,21 @@ var deleteNodeCmd = &cobra.Command{ return } if err != nil { - ErrorOutput(err, fmt.Sprintf("Error deleting node: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf( + "Error deleting node: %s", + status.Convert(err).Message(), + ), + output, + ) return } - SuccessOutput(map[string]string{"Result": "Node deleted"}, "Node deleted", output) + SuccessOutput( + map[string]string{"Result": "Node deleted"}, + "Node deleted", + output, + ) } else { SuccessOutput(map[string]string{"Result": "Node not deleted"}, "Node not deleted", output) } @@ -235,7 +279,11 @@ func sharingWorker( machineResponse, err := client.GetMachine(ctx, machineRequest) if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting node node: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf("Error getting node node: %s", status.Convert(err).Message()), + output, + ) return "", nil, nil, err } @@ -245,7 +293,11 @@ func sharingWorker( namespaceResponse, err := client.GetNamespace(ctx, namespaceRequest) if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting node node: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf("Error getting node node: %s", status.Convert(err).Message()), + output, + ) return "", nil, nil, err } @@ -258,7 +310,11 @@ var shareMachineCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { output, machine, namespace, err := sharingWorker(cmd, args) if err != nil { - ErrorOutput(err, fmt.Sprintf("Failed to fetch namespace or machine: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Failed to fetch namespace or machine: %s", err), + output, + ) return } @@ -273,7 +329,11 @@ var shareMachineCmd = &cobra.Command{ response, err := client.ShareMachine(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Error sharing node: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf("Error sharing node: %s", status.Convert(err).Message()), + output, + ) return } @@ -287,7 +347,11 @@ var unshareMachineCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { output, machine, namespace, err := sharingWorker(cmd, args) if err != nil { - ErrorOutput(err, fmt.Sprintf("Failed to fetch namespace or machine: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Failed to fetch namespace or machine: %s", err), + output, + ) return } @@ -302,7 +366,11 @@ var unshareMachineCmd = &cobra.Command{ response, err := client.UnshareMachine(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Error unsharing node: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf("Error unsharing node: %s", status.Convert(err).Message()), + output, + ) return } @@ -310,8 +378,22 @@ var unshareMachineCmd = &cobra.Command{ }, } -func nodesToPtables(currentNamespace string, machines []*v1.Machine) (pterm.TableData, error) { - d := pterm.TableData{{"ID", "Name", "NodeKey", "Namespace", "IP address", "Ephemeral", "Last seen", "Online"}} +func nodesToPtables( + currentNamespace string, + machines []*v1.Machine, +) (pterm.TableData, error) { + d := pterm.TableData{ + { + "ID", + "Name", + "NodeKey", + "Namespace", + "IP address", + "Ephemeral", + "Last seen", + "Online", + }, + } for _, machine := range machines { var ephemeral bool @@ -331,7 +413,9 @@ func nodesToPtables(currentNamespace string, machines []*v1.Machine) (pterm.Tabl nodeKey := tailcfg.NodeKey(nKey) var online string - if lastSeen.After(time.Now().Add(-5 * time.Minute)) { // TODO: Find a better way to reliably show if online + if lastSeen.After( + time.Now().Add(-5 * time.Minute), + ) { // TODO: Find a better way to reliably show if online online = pterm.LightGreen("true") } else { online = pterm.LightRed("false") diff --git a/cmd/headscale/cli/preauthkeys.go b/cmd/headscale/cli/preauthkeys.go index a07e961..f5b3b87 100644 --- a/cmd/headscale/cli/preauthkeys.go +++ b/cmd/headscale/cli/preauthkeys.go @@ -22,8 +22,10 @@ func init() { preauthkeysCmd.AddCommand(listPreAuthKeys) preauthkeysCmd.AddCommand(createPreAuthKeyCmd) preauthkeysCmd.AddCommand(expirePreAuthKeyCmd) - createPreAuthKeyCmd.PersistentFlags().Bool("reusable", false, "Make the preauthkey reusable") - createPreAuthKeyCmd.PersistentFlags().Bool("ephemeral", false, "Preauthkey for ephemeral nodes") + createPreAuthKeyCmd.PersistentFlags(). + Bool("reusable", false, "Make the preauthkey reusable") + createPreAuthKeyCmd.PersistentFlags(). + Bool("ephemeral", false, "Preauthkey for ephemeral nodes") createPreAuthKeyCmd.Flags(). DurationP("expiration", "e", 24*time.Hour, "Human-readable expiration of the key (30m, 24h, 365d...)") } @@ -55,7 +57,11 @@ var listPreAuthKeys = &cobra.Command{ response, err := client.ListPreAuthKeys(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting the list of keys: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Error getting the list of keys: %s", err), + output, + ) return } @@ -64,7 +70,9 @@ var listPreAuthKeys = &cobra.Command{ return } - d := pterm.TableData{{"ID", "Key", "Reusable", "Ephemeral", "Used", "Expiration", "Created"}} + d := pterm.TableData{ + {"ID", "Key", "Reusable", "Ephemeral", "Used", "Expiration", "Created"}, + } for _, k := range response.PreAuthKeys { expiration := "-" if k.GetExpiration() != nil { @@ -91,7 +99,11 @@ var listPreAuthKeys = &cobra.Command{ } err = pterm.DefaultTable.WithHasHeader().WithData(d).Render() if err != nil { - ErrorOutput(err, fmt.Sprintf("Failed to render pterm table: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Failed to render pterm table: %s", err), + output, + ) return } }, @@ -139,7 +151,11 @@ var createPreAuthKeyCmd = &cobra.Command{ response, err := client.CreatePreAuthKey(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot create Pre Auth Key: %s\n", err), output) + ErrorOutput( + err, + fmt.Sprintf("Cannot create Pre Auth Key: %s\n", err), + output, + ) return } @@ -175,7 +191,11 @@ var expirePreAuthKeyCmd = &cobra.Command{ response, err := client.ExpirePreAuthKey(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot expire Pre Auth Key: %s\n", err), output) + ErrorOutput( + err, + fmt.Sprintf("Cannot expire Pre Auth Key: %s\n", err), + output, + ) return } diff --git a/cmd/headscale/cli/root.go b/cmd/headscale/cli/root.go index e5115f3..99b1514 100644 --- a/cmd/headscale/cli/root.go +++ b/cmd/headscale/cli/root.go @@ -10,7 +10,8 @@ import ( func init() { rootCmd.PersistentFlags(). StringP("output", "o", "", "Output format. Empty for human-readable, 'json', 'json-line' or 'yaml'") - rootCmd.PersistentFlags().Bool("force", false, "Disable prompts and forces the execution") + rootCmd.PersistentFlags(). + Bool("force", false, "Disable prompts and forces the execution") } var rootCmd = &cobra.Command{ diff --git a/cmd/headscale/cli/routes.go b/cmd/headscale/cli/routes.go index 9f2e4e2..e6c80fb 100644 --- a/cmd/headscale/cli/routes.go +++ b/cmd/headscale/cli/routes.go @@ -21,7 +21,8 @@ func init() { } routesCmd.AddCommand(listRoutesCmd) - enableRouteCmd.Flags().StringSliceP("route", "r", []string{}, "List (or repeated flags) of routes to enable") + enableRouteCmd.Flags(). + StringSliceP("route", "r", []string{}, "List (or repeated flags) of routes to enable") enableRouteCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") err = enableRouteCmd.MarkFlagRequired("identifier") if err != nil { @@ -46,7 +47,11 @@ var listRoutesCmd = &cobra.Command{ machineId, err := cmd.Flags().GetUint64("identifier") if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting machine id from flag: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Error getting machine id from flag: %s", err), + output, + ) return } @@ -60,7 +65,11 @@ var listRoutesCmd = &cobra.Command{ response, err := client.GetMachineRoute(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot get nodes: %s", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf("Cannot get nodes: %s", status.Convert(err).Message()), + output, + ) return } @@ -77,7 +86,11 @@ var listRoutesCmd = &cobra.Command{ err = pterm.DefaultTable.WithHasHeader().WithData(d).Render() if err != nil { - ErrorOutput(err, fmt.Sprintf("Failed to render pterm table: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Failed to render pterm table: %s", err), + output, + ) return } }, @@ -95,13 +108,21 @@ omit the route you do not want to enable. output, _ := cmd.Flags().GetString("output") machineId, err := cmd.Flags().GetUint64("identifier") if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting machine id from flag: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Error getting machine id from flag: %s", err), + output, + ) return } routes, err := cmd.Flags().GetStringSlice("route") if err != nil { - ErrorOutput(err, fmt.Sprintf("Error getting routes from flag: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Error getting routes from flag: %s", err), + output, + ) return } @@ -116,7 +137,14 @@ omit the route you do not want to enable. response, err := client.EnableMachineRoutes(ctx, request) if err != nil { - ErrorOutput(err, fmt.Sprintf("Cannot register machine: %s\n", status.Convert(err).Message()), output) + ErrorOutput( + err, + fmt.Sprintf( + "Cannot register machine: %s\n", + status.Convert(err).Message(), + ), + output, + ) return } @@ -133,7 +161,11 @@ omit the route you do not want to enable. err = pterm.DefaultTable.WithHasHeader().WithData(d).Render() if err != nil { - ErrorOutput(err, fmt.Sprintf("Failed to render pterm table: %s", err), output) + ErrorOutput( + err, + fmt.Sprintf("Failed to render pterm table: %s", err), + output, + ) return } }, diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go index 30f1a78..16b236a 100644 --- a/cmd/headscale/cli/utils.go +++ b/cmd/headscale/cli/utils.go @@ -149,9 +149,14 @@ func GetDNSConfig() (*tailcfg.DNSConfig, string) { if viper.IsSet("dns_config.restricted_nameservers") { if len(dnsConfig.Nameservers) > 0 { dnsConfig.Routes = make(map[string][]dnstype.Resolver) - restrictedDNS := viper.GetStringMapStringSlice("dns_config.restricted_nameservers") + restrictedDNS := viper.GetStringMapStringSlice( + "dns_config.restricted_nameservers", + ) for domain, restrictedNameservers := range restrictedDNS { - restrictedResolvers := make([]dnstype.Resolver, len(restrictedNameservers)) + restrictedResolvers := make( + []dnstype.Resolver, + len(restrictedNameservers), + ) for index, nameserverStr := range restrictedNameservers { nameserver, err := netaddr.ParseIP(nameserverStr) if err != nil { @@ -219,7 +224,9 @@ func getHeadscaleConfig() headscale.Config { "10h", ) // use 10h here because it is the length of a standard business day plus a small amount of leeway if viper.GetDuration("max_machine_registration_duration") >= time.Second { - maxMachineRegistrationDuration = viper.GetDuration("max_machine_registration_duration") + maxMachineRegistrationDuration = viper.GetDuration( + "max_machine_registration_duration", + ) } // defaultMachineRegistrationDuration is the default time assigned to a machine registration if one is not @@ -229,7 +236,9 @@ func getHeadscaleConfig() headscale.Config { "8h", ) // use 8h here because it's the length of a standard business day if viper.GetDuration("default_machine_registration_duration") >= time.Second { - defaultMachineRegistrationDuration = viper.GetDuration("default_machine_registration_duration") + defaultMachineRegistrationDuration = viper.GetDuration( + "default_machine_registration_duration", + ) } dnsConfig, baseDomain := GetDNSConfig() @@ -244,7 +253,9 @@ func getHeadscaleConfig() headscale.Config { DERP: derpConfig, - EphemeralNodeInactivityTimeout: viper.GetDuration("ephemeral_node_inactivity_timeout"), + EphemeralNodeInactivityTimeout: viper.GetDuration( + "ephemeral_node_inactivity_timeout", + ), DBtype: viper.GetString("db_type"), DBpath: absPath(viper.GetString("db_path")), @@ -254,9 +265,11 @@ func getHeadscaleConfig() headscale.Config { DBuser: viper.GetString("db_user"), DBpass: viper.GetString("db_pass"), - TLSLetsEncryptHostname: viper.GetString("tls_letsencrypt_hostname"), - TLSLetsEncryptListen: viper.GetString("tls_letsencrypt_listen"), - TLSLetsEncryptCacheDir: absPath(viper.GetString("tls_letsencrypt_cache_dir")), + TLSLetsEncryptHostname: viper.GetString("tls_letsencrypt_hostname"), + TLSLetsEncryptListen: viper.GetString("tls_letsencrypt_listen"), + TLSLetsEncryptCacheDir: absPath( + viper.GetString("tls_letsencrypt_cache_dir"), + ), TLSLetsEncryptChallengeType: viper.GetString("tls_letsencrypt_challenge_type"), TLSCertPath: absPath(viper.GetString("tls_cert_path")), @@ -431,7 +444,10 @@ type tokenAuth struct { } // Return value is mapped to request headers. -func (t tokenAuth) GetRequestMetadata(ctx context.Context, in ...string) (map[string]string, error) { +func (t tokenAuth) GetRequestMetadata( + ctx context.Context, + in ...string, +) (map[string]string, error) { return map[string]string{ "authorization": "Bearer " + t.token, }, nil diff --git a/cmd/headscale/headscale.go b/cmd/headscale/headscale.go index ed4644f..8f436b9 100644 --- a/cmd/headscale/headscale.go +++ b/cmd/headscale/headscale.go @@ -63,7 +63,8 @@ func main() { } if !viper.GetBool("disable_check_updates") && !machineOutput { - if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") && cli.Version != "dev" { + if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") && + cli.Version != "dev" { githubTag := &latest.GithubTag{ Owner: "juanfont", Repository: "headscale", diff --git a/cmd/headscale/headscale_test.go b/cmd/headscale/headscale_test.go index e3a5713..ceee3e4 100644 --- a/cmd/headscale/headscale_test.go +++ b/cmd/headscale/headscale_test.go @@ -40,7 +40,10 @@ func (*Suite) TestConfigLoading(c *check.C) { } // Symlink the example config file - err = os.Symlink(filepath.Clean(path+"/../../config-example.yaml"), filepath.Join(tmpDir, "config.yaml")) + err = os.Symlink( + filepath.Clean(path+"/../../config-example.yaml"), + filepath.Join(tmpDir, "config.yaml"), + ) if err != nil { c.Fatal(err) } @@ -74,7 +77,10 @@ func (*Suite) TestDNSConfigLoading(c *check.C) { } // Symlink the example config file - err = os.Symlink(filepath.Clean(path+"/../../config-example.yaml"), filepath.Join(tmpDir, "config.yaml")) + err = os.Symlink( + filepath.Clean(path+"/../../config-example.yaml"), + filepath.Join(tmpDir, "config.yaml"), + ) if err != nil { c.Fatal(err) } @@ -128,7 +134,11 @@ func (*Suite) TestTLSConfigValidation(c *check.C) { check.Matches, ".*Fatal config error: the only supported values for tls_letsencrypt_challenge_type are.*", ) - c.Assert(tmp, check.Matches, ".*Fatal config error: server_url must start with https:// or http://.*") + c.Assert( + tmp, + check.Matches, + ".*Fatal config error: server_url must start with https:// or http://.*", + ) fmt.Println(tmp) // Check configuration validation errors (2) diff --git a/db.go b/db.go index 42c5eee..60e2f6f 100644 --- a/db.go +++ b/db.go @@ -87,7 +87,10 @@ func (h *Headscale) openDB() (*gorm.DB, error) { // getValue returns the value for the given key in KV func (h *Headscale) getValue(key string) (string, error) { var row KV - if result := h.db.First(&row, "key = ?", key); errors.Is(result.Error, gorm.ErrRecordNotFound) { + if result := h.db.First(&row, "key = ?", key); errors.Is( + result.Error, + gorm.ErrRecordNotFound, + ) { return "", errors.New("not found") } return row.Value, nil diff --git a/dns.go b/dns.go index c7ca32a..e0e1abe 100644 --- a/dns.go +++ b/dns.go @@ -30,7 +30,10 @@ import ( // From the netmask we can find out the wildcard bits (the bits that are not set in the netmask). // This allows us to then calculate the subnets included in the subsequent class block and generate the entries. -func generateMagicDNSRootDomains(ipPrefix netaddr.IPPrefix, baseDomain string) ([]dnsname.FQDN, error) { +func generateMagicDNSRootDomains( + ipPrefix netaddr.IPPrefix, + baseDomain string, +) ([]dnsname.FQDN, error) { // TODO(juanfont): we are not handing out IPv6 addresses yet // and in fact this is Tailscale.com's range (note the fd7a:115c:a1e0: range in the fc00::/7 network) ipv6base := dnsname.FQDN("0.e.1.a.c.5.1.1.a.7.d.f.ip6.arpa.") @@ -69,12 +72,20 @@ func generateMagicDNSRootDomains(ipPrefix netaddr.IPPrefix, baseDomain string) ( return fqdns, nil } -func getMapResponseDNSConfig(dnsConfigOrig *tailcfg.DNSConfig, baseDomain string, m Machine, peers Machines) (*tailcfg.DNSConfig, error) { +func getMapResponseDNSConfig( + dnsConfigOrig *tailcfg.DNSConfig, + baseDomain string, + m Machine, + peers Machines, +) (*tailcfg.DNSConfig, error) { var dnsConfig *tailcfg.DNSConfig if dnsConfigOrig != nil && dnsConfigOrig.Proxied { // if MagicDNS is enabled // Only inject the Search Domain of the current namespace - shared nodes should use their full FQDN dnsConfig = dnsConfigOrig.Clone() - dnsConfig.Domains = append(dnsConfig.Domains, fmt.Sprintf("%s.%s", m.Namespace.Name, baseDomain)) + dnsConfig.Domains = append( + dnsConfig.Domains, + fmt.Sprintf("%s.%s", m.Namespace.Name, baseDomain), + ) namespaceSet := set.New(set.ThreadSafe) namespaceSet.Add(m.Namespace) diff --git a/grpcv1.go b/grpcv1.go index 998f0c0..4366446 100644 --- a/grpcv1.go +++ b/grpcv1.go @@ -155,7 +155,10 @@ func (api headscaleV1APIServer) RegisterMachine( ctx context.Context, request *v1.RegisterMachineRequest, ) (*v1.RegisterMachineResponse, error) { - log.Trace().Str("namespace", request.GetNamespace()).Str("machine_key", request.GetKey()).Msg("Registering machine") + log.Trace(). + Str("namespace", request.GetNamespace()). + Str("machine_key", request.GetKey()). + Msg("Registering machine") machine, err := api.h.RegisterMachine( request.GetKey(), request.GetNamespace(), @@ -208,7 +211,9 @@ func (api headscaleV1APIServer) ListMachines( return nil, err } - sharedMachines, err := api.h.ListSharedMachinesInNamespace(request.GetNamespace()) + sharedMachines, err := api.h.ListSharedMachinesInNamespace( + request.GetNamespace(), + ) if err != nil { return nil, err } @@ -338,7 +343,11 @@ func (api headscaleV1APIServer) DebugCreateMachine( return nil, err } - log.Trace().Caller().Interface("route-prefix", routes).Interface("route-str", request.GetRoutes()).Msg("") + log.Trace(). + Caller(). + Interface("route-prefix", routes). + Interface("route-str", request.GetRoutes()). + Msg("") hostinfo := tailcfg.Hostinfo{ RoutableIPs: routes, diff --git a/integration_cli_test.go b/integration_cli_test.go index e1b1672..335768c 100644 --- a/integration_cli_test.go +++ b/integration_cli_test.go @@ -109,7 +109,10 @@ func (s *IntegrationCLITestSuite) TearDownTest() { } } -func (s *IntegrationCLITestSuite) HandleStats(suiteName string, stats *suite.SuiteInformation) { +func (s *IntegrationCLITestSuite) HandleStats( + suiteName string, + stats *suite.SuiteInformation, +) { s.stats = stats } @@ -298,11 +301,26 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommand() { assert.True(s.T(), listedPreAuthKeys[3].Expiration.AsTime().After(time.Now())) assert.True(s.T(), listedPreAuthKeys[4].Expiration.AsTime().After(time.Now())) - assert.True(s.T(), listedPreAuthKeys[0].Expiration.AsTime().Before(time.Now().Add(time.Hour*26))) - assert.True(s.T(), listedPreAuthKeys[1].Expiration.AsTime().Before(time.Now().Add(time.Hour*26))) - assert.True(s.T(), listedPreAuthKeys[2].Expiration.AsTime().Before(time.Now().Add(time.Hour*26))) - assert.True(s.T(), listedPreAuthKeys[3].Expiration.AsTime().Before(time.Now().Add(time.Hour*26))) - assert.True(s.T(), listedPreAuthKeys[4].Expiration.AsTime().Before(time.Now().Add(time.Hour*26))) + assert.True( + s.T(), + listedPreAuthKeys[0].Expiration.AsTime().Before(time.Now().Add(time.Hour*26)), + ) + assert.True( + s.T(), + listedPreAuthKeys[1].Expiration.AsTime().Before(time.Now().Add(time.Hour*26)), + ) + assert.True( + s.T(), + listedPreAuthKeys[2].Expiration.AsTime().Before(time.Now().Add(time.Hour*26)), + ) + assert.True( + s.T(), + listedPreAuthKeys[3].Expiration.AsTime().Before(time.Now().Add(time.Hour*26)), + ) + assert.True( + s.T(), + listedPreAuthKeys[4].Expiration.AsTime().Before(time.Now().Add(time.Hour*26)), + ) // Expire three keys for i := 0; i < 3; i++ { @@ -341,11 +359,26 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommand() { err = json.Unmarshal([]byte(listAfterExpireResult), &listedAfterExpirePreAuthKeys) assert.Nil(s.T(), err) - assert.True(s.T(), listedAfterExpirePreAuthKeys[0].Expiration.AsTime().Before(time.Now())) - assert.True(s.T(), listedAfterExpirePreAuthKeys[1].Expiration.AsTime().Before(time.Now())) - assert.True(s.T(), listedAfterExpirePreAuthKeys[2].Expiration.AsTime().Before(time.Now())) - assert.True(s.T(), listedAfterExpirePreAuthKeys[3].Expiration.AsTime().After(time.Now())) - assert.True(s.T(), listedAfterExpirePreAuthKeys[4].Expiration.AsTime().After(time.Now())) + assert.True( + s.T(), + listedAfterExpirePreAuthKeys[0].Expiration.AsTime().Before(time.Now()), + ) + assert.True( + s.T(), + listedAfterExpirePreAuthKeys[1].Expiration.AsTime().Before(time.Now()), + ) + assert.True( + s.T(), + listedAfterExpirePreAuthKeys[2].Expiration.AsTime().Before(time.Now()), + ) + assert.True( + s.T(), + listedAfterExpirePreAuthKeys[3].Expiration.AsTime().After(time.Now()), + ) + assert.True( + s.T(), + listedAfterExpirePreAuthKeys[4].Expiration.AsTime().After(time.Now()), + ) } func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandWithoutExpiry() { @@ -689,7 +722,10 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { assert.Nil(s.T(), err) var listOnlySharedMachineNamespace []v1.Machine - err = json.Unmarshal([]byte(listOnlySharedMachineNamespaceResult), &listOnlySharedMachineNamespace) + err = json.Unmarshal( + []byte(listOnlySharedMachineNamespaceResult), + &listOnlySharedMachineNamespace, + ) assert.Nil(s.T(), err) assert.Len(s.T(), listOnlySharedMachineNamespace, 2) @@ -738,7 +774,10 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { assert.Nil(s.T(), err) var listOnlyMachineNamespaceAfterDelete []v1.Machine - err = json.Unmarshal([]byte(listOnlyMachineNamespaceAfterDeleteResult), &listOnlyMachineNamespaceAfterDelete) + err = json.Unmarshal( + []byte(listOnlyMachineNamespaceAfterDeleteResult), + &listOnlyMachineNamespaceAfterDelete, + ) assert.Nil(s.T(), err) assert.Len(s.T(), listOnlyMachineNamespaceAfterDelete, 4) @@ -789,7 +828,10 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { assert.Nil(s.T(), err) var listOnlyMachineNamespaceAfterShare []v1.Machine - err = json.Unmarshal([]byte(listOnlyMachineNamespaceAfterShareResult), &listOnlyMachineNamespaceAfterShare) + err = json.Unmarshal( + []byte(listOnlyMachineNamespaceAfterShareResult), + &listOnlyMachineNamespaceAfterShare, + ) assert.Nil(s.T(), err) assert.Len(s.T(), listOnlyMachineNamespaceAfterShare, 5) @@ -846,7 +888,10 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { assert.Nil(s.T(), err) var listOnlyMachineNamespaceAfterUnshare []v1.Machine - err = json.Unmarshal([]byte(listOnlyMachineNamespaceAfterUnshareResult), &listOnlyMachineNamespaceAfterUnshare) + err = json.Unmarshal( + []byte(listOnlyMachineNamespaceAfterUnshareResult), + &listOnlyMachineNamespaceAfterUnshare, + ) assert.Nil(s.T(), err) assert.Len(s.T(), listOnlyMachineNamespaceAfterUnshare, 4) @@ -1010,5 +1055,9 @@ func (s *IntegrationCLITestSuite) TestRouteCommand() { ) assert.Nil(s.T(), err) - assert.Contains(s.T(), string(failEnableNonAdvertisedRoute), "route (route-machine) is not available on node") + assert.Contains( + s.T(), + string(failEnableNonAdvertisedRoute), + "route (route-machine) is not available on node", + ) } diff --git a/integration_common_test.go b/integration_common_test.go index 71d4866..6540012 100644 --- a/integration_common_test.go +++ b/integration_common_test.go @@ -12,7 +12,11 @@ import ( "github.com/ory/dockertest/v3/docker" ) -func ExecuteCommand(resource *dockertest.Resource, cmd []string, env []string) (string, error) { +func ExecuteCommand( + resource *dockertest.Resource, + cmd []string, + env []string, +) (string, error) { var stdout bytes.Buffer var stderr bytes.Buffer diff --git a/integration_test.go b/integration_test.go index c4f6bb4..dc5a83c 100644 --- a/integration_test.go +++ b/integration_test.go @@ -89,7 +89,10 @@ func TestIntegrationTestSuite(t *testing.T) { } } -func (s *IntegrationTestSuite) saveLog(resource *dockertest.Resource, basePath string) error { +func (s *IntegrationTestSuite) saveLog( + resource *dockertest.Resource, + basePath string, +) error { err := os.MkdirAll(basePath, os.ModePerm) if err != nil { return err @@ -118,12 +121,20 @@ func (s *IntegrationTestSuite) saveLog(resource *dockertest.Resource, basePath s fmt.Printf("Saving logs for %s to %s\n", resource.Container.Name, basePath) - err = ioutil.WriteFile(path.Join(basePath, resource.Container.Name+".stdout.log"), []byte(stdout.String()), 0o644) + err = ioutil.WriteFile( + path.Join(basePath, resource.Container.Name+".stdout.log"), + []byte(stdout.String()), + 0o644, + ) if err != nil { return err } - err = ioutil.WriteFile(path.Join(basePath, resource.Container.Name+".stderr.log"), []byte(stdout.String()), 0o644) + err = ioutil.WriteFile( + path.Join(basePath, resource.Container.Name+".stderr.log"), + []byte(stdout.String()), + 0o644, + ) if err != nil { return err } @@ -144,14 +155,27 @@ func (s *IntegrationTestSuite) tailscaleContainer( }, }, } - hostname := fmt.Sprintf("%s-tailscale-%s-%s", namespace, strings.Replace(version, ".", "-", -1), identifier) + hostname := fmt.Sprintf( + "%s-tailscale-%s-%s", + namespace, + strings.Replace(version, ".", "-", -1), + identifier, + ) tailscaleOptions := &dockertest.RunOptions{ Name: hostname, Networks: []*dockertest.Network{&s.network}, - Cmd: []string{"tailscaled", "--tun=userspace-networking", "--socks5-server=localhost:1055"}, + Cmd: []string{ + "tailscaled", + "--tun=userspace-networking", + "--socks5-server=localhost:1055", + }, } - pts, err := s.pool.BuildAndRunWithBuildOptions(tailscaleBuildOptions, tailscaleOptions, DockerRestartPolicy) + pts, err := s.pool.BuildAndRunWithBuildOptions( + tailscaleBuildOptions, + tailscaleOptions, + DockerRestartPolicy, + ) if err != nil { log.Fatalf("Could not start resource: %s", err) } @@ -210,7 +234,11 @@ func (s *IntegrationTestSuite) SetupSuite() { for i := 0; i < scales.count; i++ { version := tailscaleVersions[i%len(tailscaleVersions)] - hostname, container := s.tailscaleContainer(namespace, fmt.Sprint(i), version) + hostname, container := s.tailscaleContainer( + namespace, + fmt.Sprint(i), + version, + ) scales.tailscales[hostname] = *container } } @@ -273,7 +301,10 @@ func (s *IntegrationTestSuite) SetupSuite() { headscaleEndpoint := "http://headscale:8080" - fmt.Printf("Joining tailscale containers to headscale at %s\n", headscaleEndpoint) + fmt.Printf( + "Joining tailscale containers to headscale at %s\n", + headscaleEndpoint, + ) for hostname, tailscale := range scales.tailscales { command := []string{ "tailscale", @@ -307,7 +338,10 @@ func (s *IntegrationTestSuite) SetupSuite() { func (s *IntegrationTestSuite) TearDownSuite() { } -func (s *IntegrationTestSuite) HandleStats(suiteName string, stats *suite.SuiteInformation) { +func (s *IntegrationTestSuite) HandleStats( + suiteName string, + stats *suite.SuiteInformation, +) { s.stats = stats } @@ -427,7 +461,13 @@ func (s *IntegrationTestSuite) TestPingAllPeers() { ip.String(), } - fmt.Printf("Pinging from %s (%s) to %s (%s)\n", hostname, ips[hostname], peername, ip) + fmt.Printf( + "Pinging from %s (%s) to %s (%s)\n", + hostname, + ips[hostname], + peername, + ip, + ) result, err := ExecuteCommand( &tailscale, command, @@ -449,7 +489,15 @@ func (s *IntegrationTestSuite) TestSharedNodes() { result, err := ExecuteCommand( &s.headscale, - []string{"headscale", "nodes", "list", "--output", "json", "--namespace", "shared"}, + []string{ + "headscale", + "nodes", + "list", + "--output", + "json", + "--namespace", + "shared", + }, []string{}, ) assert.Nil(s.T(), err) @@ -520,7 +568,13 @@ func (s *IntegrationTestSuite) TestSharedNodes() { ip.String(), } - fmt.Printf("Pinging from %s (%s) to %s (%s)\n", hostname, mainIps[hostname], peername, ip) + fmt.Printf( + "Pinging from %s (%s) to %s (%s)\n", + hostname, + mainIps[hostname], + peername, + ip, + ) result, err := ExecuteCommand( &tailscale, command, @@ -578,9 +632,19 @@ func (s *IntegrationTestSuite) TestTailDrop() { "PUT", "--upload-file", fmt.Sprintf("/tmp/file_from_%s", hostname), - fmt.Sprintf("%s/v0/put/file_from_%s", peerAPI, hostname), + fmt.Sprintf( + "%s/v0/put/file_from_%s", + peerAPI, + hostname, + ), } - fmt.Printf("Sending file from %s (%s) to %s (%s)\n", hostname, ips[hostname], peername, ip) + fmt.Printf( + "Sending file from %s (%s) to %s (%s)\n", + hostname, + ips[hostname], + peername, + ip, + ) _, err = ExecuteCommand( &tailscale, command, @@ -621,7 +685,13 @@ func (s *IntegrationTestSuite) TestTailDrop() { "ls", fmt.Sprintf("/tmp/file_from_%s", peername), } - fmt.Printf("Checking file in %s (%s) from %s (%s)\n", hostname, ips[hostname], peername, ip) + fmt.Printf( + "Checking file in %s (%s) from %s (%s)\n", + hostname, + ips[hostname], + peername, + ip, + ) result, err := ExecuteCommand( &tailscale, command, @@ -629,7 +699,11 @@ func (s *IntegrationTestSuite) TestTailDrop() { ) assert.Nil(t, err) fmt.Printf("Result for %s: %s\n", peername, result) - assert.Equal(t, result, fmt.Sprintf("/tmp/file_from_%s\n", peername)) + assert.Equal( + t, + result, + fmt.Sprintf("/tmp/file_from_%s\n", peername), + ) } }) } @@ -699,7 +773,9 @@ func getIPs(tailscales map[string]dockertest.Resource) (map[string]netaddr.IP, e return ips, nil } -func getAPIURLs(tailscales map[string]dockertest.Resource) (map[netaddr.IP]string, error) { +func getAPIURLs( + tailscales map[string]dockertest.Resource, +) (map[netaddr.IP]string, error) { fts := make(map[netaddr.IP]string) for _, tailscale := range tailscales { command := []string{ diff --git a/machine.go b/machine.go index 557ab5b..d0c07d0 100644 --- a/machine.go +++ b/machine.go @@ -73,8 +73,12 @@ func (m Machine) isExpired() bool { func (h *Headscale) updateMachineExpiry(m *Machine) { if m.isExpired() { now := time.Now().UTC() - maxExpiry := now.Add(h.cfg.MaxMachineRegistrationDuration) // calculate the maximum expiry - defaultExpiry := now.Add(h.cfg.DefaultMachineRegistrationDuration) // calculate the default expiry + maxExpiry := now.Add( + h.cfg.MaxMachineRegistrationDuration, + ) // calculate the maximum expiry + defaultExpiry := now.Add( + h.cfg.DefaultMachineRegistrationDuration, + ) // calculate the default expiry // clamp the expiry time of the machine registration to the maximum allowed, or use the default if none supplied if maxExpiry.Before(*m.RequestedExpiry) { @@ -157,7 +161,9 @@ func (h *Headscale) getSharedTo(m *Machine) (Machines, error) { peers := make(Machines, 0) for _, sharedMachine := range sharedMachines { - namespaceMachines, err := h.ListMachinesInNamespace(sharedMachine.Namespace.Name) + namespaceMachines, err := h.ListMachinesInNamespace( + sharedMachine.Namespace.Name, + ) if err != nil { return Machines{}, err } @@ -392,7 +398,11 @@ func (ms Machines) toNodes( // toNode converts a Machine into a Tailscale Node. includeRoutes is false for shared nodes // as per the expected behaviour in the official SaaS -func (m Machine) toNode(baseDomain string, dnsConfig *tailcfg.DNSConfig, includeRoutes bool) (*tailcfg.Node, error) { +func (m Machine) toNode( + baseDomain string, + dnsConfig *tailcfg.DNSConfig, + includeRoutes bool, +) (*tailcfg.Node, error) { nKey, err := wgkey.ParseHex(m.NodeKey) if err != nil { return nil, err @@ -425,7 +435,10 @@ func (m Machine) toNode(baseDomain string, dnsConfig *tailcfg.DNSConfig, include addrs = append(addrs, ip) // missing the ipv6 ? allowedIPs := []netaddr.IPPrefix{} - allowedIPs = append(allowedIPs, ip) // we append the node own IP, as it is required by the clients + allowedIPs = append( + allowedIPs, + ip, + ) // we append the node own IP, as it is required by the clients if includeRoutes { routesStr := []string{} @@ -571,7 +584,10 @@ func (h *Headscale) RegisterMachine(key string, namespace string) (*Machine, err } m := Machine{} - if result := h.db.First(&m, "machine_key = ?", mKey.HexString()); errors.Is(result.Error, gorm.ErrRecordNotFound) { + if result := h.db.First(&m, "machine_key = ?", mKey.HexString()); errors.Is( + result.Error, + gorm.ErrRecordNotFound, + ) { return nil, errors.New("Machine not found") } @@ -693,7 +709,11 @@ func (h *Headscale) EnableRoutes(m *Machine, routeStrs ...string) error { for _, newRoute := range newRoutes { if !containsIpPrefix(availableRoutes, newRoute) { - return fmt.Errorf("route (%s) is not available on node %s", m.Name, newRoute) + return fmt.Errorf( + "route (%s) is not available on node %s", + m.Name, + newRoute, + ) } } diff --git a/metrics.go b/metrics.go index 0d3dca3..f0ce16e 100644 --- a/metrics.go +++ b/metrics.go @@ -32,7 +32,7 @@ var ( Name: "update_request_sent_to_node_total", Help: "The number of calls/messages issued on a specific nodes update channel", }, []string{"namespace", "machine", "status"}) - //TODO(kradalby): This is very debugging, we might want to remove it. + // TODO(kradalby): This is very debugging, we might want to remove it. updateRequestsReceivedOnChannel = promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: prometheusNamespace, Name: "update_request_received_on_channel_total", diff --git a/namespaces.go b/namespaces.go index 66deb1a..59a8e2e 100644 --- a/namespaces.go +++ b/namespaces.go @@ -102,7 +102,10 @@ func (h *Headscale) RenameNamespace(oldName, newName string) error { // GetNamespace fetches a namespace by name func (h *Headscale) GetNamespace(name string) (*Namespace, error) { n := Namespace{} - if result := h.db.First(&n, "name = ?", name); errors.Is(result.Error, gorm.ErrRecordNotFound) { + if result := h.db.First(&n, "name = ?", name); errors.Is( + result.Error, + gorm.ErrRecordNotFound, + ) { return nil, errorNamespaceNotFound } return &n, nil @@ -144,7 +147,9 @@ func (h *Headscale) ListSharedMachinesInNamespace(name string) ([]Machine, error machines := []Machine{} for _, sharedMachine := range sharedMachines { - machine, err := h.GetMachineByID(sharedMachine.MachineID) // otherwise not everything comes filled + machine, err := h.GetMachineByID( + sharedMachine.MachineID, + ) // otherwise not everything comes filled if err != nil { return nil, err } @@ -173,7 +178,10 @@ func (h *Headscale) RequestMapUpdates(namespaceID uint) error { v, err := h.getValue("namespaces_pending_updates") if err != nil || v == "" { - err = h.setValue("namespaces_pending_updates", fmt.Sprintf(`["%s"]`, namespace.Name)) + err = h.setValue( + "namespaces_pending_updates", + fmt.Sprintf(`["%s"]`, namespace.Name), + ) if err != nil { return err } @@ -182,7 +190,10 @@ func (h *Headscale) RequestMapUpdates(namespaceID uint) error { names := []string{} err = json.Unmarshal([]byte(v), &names) if err != nil { - err = h.setValue("namespaces_pending_updates", fmt.Sprintf(`["%s"]`, namespace.Name)) + err = h.setValue( + "namespaces_pending_updates", + fmt.Sprintf(`["%s"]`, namespace.Name), + ) if err != nil { return err } diff --git a/oidc.go b/oidc.go index 51c443d..c3f7c2e 100644 --- a/oidc.go +++ b/oidc.go @@ -39,8 +39,11 @@ func (h *Headscale) initOIDC() error { ClientID: h.cfg.OIDC.ClientID, ClientSecret: h.cfg.OIDC.ClientSecret, Endpoint: h.oidcProvider.Endpoint(), - RedirectURL: fmt.Sprintf("%s/oidc/callback", strings.TrimSuffix(h.cfg.ServerURL, "/")), - Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, + RedirectURL: fmt.Sprintf( + "%s/oidc/callback", + strings.TrimSuffix(h.cfg.ServerURL, "/"), + ), + Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, } } @@ -127,7 +130,10 @@ func (h *Headscale) OIDCCallback(c *gin.Context) { // Extract custom claims var claims IDTokenClaims if err = idToken.Claims(&claims); err != nil { - c.String(http.StatusBadRequest, fmt.Sprintf("Failed to decode id token claims: %s", err)) + c.String( + http.StatusBadRequest, + fmt.Sprintf("Failed to decode id token claims: %s", err), + ) return } @@ -135,7 +141,8 @@ func (h *Headscale) OIDCCallback(c *gin.Context) { mKeyIf, mKeyFound := h.oidcStateCache.Get(state) if !mKeyFound { - log.Error().Msg("requested machine state key expired before authorisation completed") + log.Error(). + Msg("requested machine state key expired before authorisation completed") c.String(http.StatusBadRequest, "state has expired") return } @@ -151,7 +158,10 @@ func (h *Headscale) OIDCCallback(c *gin.Context) { m, err := h.GetMachineByMachineKey(mKeyStr) if err != nil { log.Error().Msg("machine key not found in database") - c.String(http.StatusInternalServerError, "could not get machine info from database") + c.String( + http.StatusInternalServerError, + "could not get machine info from database", + ) return } @@ -168,15 +178,22 @@ func (h *Headscale) OIDCCallback(c *gin.Context) { ns, err = h.CreateNamespace(nsName) if err != nil { - log.Error().Msgf("could not create new namespace '%s'", claims.Email) - c.String(http.StatusInternalServerError, "could not create new namespace") + log.Error(). + Msgf("could not create new namespace '%s'", claims.Email) + c.String( + http.StatusInternalServerError, + "could not create new namespace", + ) return } } ip, err := h.getAvailableIP() if err != nil { - c.String(http.StatusInternalServerError, "could not get an IP from the pool") + c.String( + http.StatusInternalServerError, + "could not get an IP from the pool", + ) return } @@ -209,7 +226,10 @@ func (h *Headscale) OIDCCallback(c *gin.Context) { Str("username", claims.Username). Str("machine", m.Name). Msg("Email could not be mapped to a namespace") - c.String(http.StatusBadRequest, "email from claim could not be mapped to a namespace") + c.String( + http.StatusBadRequest, + "email from claim could not be mapped to a namespace", + ) } // getNamespaceFromEmail passes the users email through a list of "matchers" diff --git a/oidc_test.go b/oidc_test.go index c7a29ce..6b01924 100644 --- a/oidc_test.go +++ b/oidc_test.go @@ -164,10 +164,18 @@ func TestHeadscale_getNamespaceFromEmail(t *testing.T) { } got, got1 := h.getNamespaceFromEmail(tt.args.email) if got != tt.want { - t.Errorf("Headscale.getNamespaceFromEmail() got = %v, want %v", got, tt.want) + t.Errorf( + "Headscale.getNamespaceFromEmail() got = %v, want %v", + got, + tt.want, + ) } if got1 != tt.want1 { - t.Errorf("Headscale.getNamespaceFromEmail() got1 = %v, want %v", got1, tt.want1) + t.Errorf( + "Headscale.getNamespaceFromEmail() got1 = %v, want %v", + got1, + tt.want1, + ) } }) } diff --git a/poll.go b/poll.go index 6a65280..038192f 100644 --- a/poll.go +++ b/poll.go @@ -158,7 +158,8 @@ func (h *Headscale) PollNetMapHandler(c *gin.Context) { // It sounds like we should update the nodes when we have received a endpoint update // even tho the comments in the tailscale code dont explicitly say so. - updateRequestsFromNode.WithLabelValues(m.Name, m.Namespace.Name, "endpoint-update").Inc() + updateRequestsFromNode.WithLabelValues(m.Name, m.Namespace.Name, "endpoint-update"). + Inc() go func() { updateChan <- struct{}{} }() return } else if req.OmitPeers && req.Stream { @@ -184,10 +185,20 @@ func (h *Headscale) PollNetMapHandler(c *gin.Context) { Str("handler", "PollNetMap"). Str("machine", m.Name). Msg("Notifying peers") - updateRequestsFromNode.WithLabelValues(m.Name, m.Namespace.Name, "full-update").Inc() + updateRequestsFromNode.WithLabelValues(m.Name, m.Namespace.Name, "full-update"). + Inc() go func() { updateChan <- struct{}{} }() - h.PollNetMapStream(c, m, req, mKey, pollDataChan, keepAliveChan, updateChan, cancelKeepAlive) + h.PollNetMapStream( + c, + m, + req, + mKey, + pollDataChan, + keepAliveChan, + updateChan, + cancelKeepAlive, + ) log.Trace(). Str("handler", "PollNetMap"). Str("id", c.Param("id")). @@ -260,7 +271,8 @@ func (h *Headscale) PollNetMapStream( now := time.Now().UTC() m.LastSeen = &now - lastStateUpdate.WithLabelValues(m.Namespace.Name, m.Name).Set(float64(now.Unix())) + lastStateUpdate.WithLabelValues(m.Namespace.Name, m.Name). + Set(float64(now.Unix())) m.LastSuccessfulUpdate = &now h.db.Save(&m) @@ -324,7 +336,8 @@ func (h *Headscale) PollNetMapStream( Str("machine", m.Name). Str("channel", "update"). Msg("Received a request for update") - updateRequestsReceivedOnChannel.WithLabelValues(m.Name, m.Namespace.Name).Inc() + updateRequestsReceivedOnChannel.WithLabelValues(m.Name, m.Namespace.Name). + Inc() if h.isOutdated(m) { log.Debug(). Str("handler", "PollNetMapStream"). @@ -349,7 +362,8 @@ func (h *Headscale) PollNetMapStream( Str("channel", "update"). Err(err). Msg("Could not write the map response") - updateRequestsSentToNode.WithLabelValues(m.Name, m.Namespace.Name, "failed").Inc() + updateRequestsSentToNode.WithLabelValues(m.Name, m.Namespace.Name, "failed"). + Inc() return false } log.Trace(). @@ -357,7 +371,8 @@ func (h *Headscale) PollNetMapStream( Str("machine", m.Name). Str("channel", "update"). Msg("Updated Map has been sent") - updateRequestsSentToNode.WithLabelValues(m.Name, m.Namespace.Name, "success").Inc() + updateRequestsSentToNode.WithLabelValues(m.Name, m.Namespace.Name, "success"). + Inc() // Keep track of the last successful update, // we sometimes end in a state were the update @@ -377,7 +392,8 @@ func (h *Headscale) PollNetMapStream( } now := time.Now().UTC() - lastStateUpdate.WithLabelValues(m.Namespace.Name, m.Name).Set(float64(now.Unix())) + lastStateUpdate.WithLabelValues(m.Namespace.Name, m.Name). + Set(float64(now.Unix())) m.LastSuccessfulUpdate = &now h.db.Save(&m) @@ -424,7 +440,7 @@ func (h *Headscale) PollNetMapStream( Str("machine", m.Name). Str("channel", "Done"). Msg("Closing update channel") - //h.closeUpdateChannel(m) + // h.closeUpdateChannel(m) close(updateChan) log.Trace(). @@ -483,7 +499,8 @@ func (h *Headscale) scheduledPollWorker( Str("func", "scheduledPollWorker"). Str("machine", m.Name). Msg("Sending update request") - updateRequestsFromNode.WithLabelValues(m.Name, m.Namespace.Name, "scheduled-update").Inc() + updateRequestsFromNode.WithLabelValues(m.Name, m.Namespace.Name, "scheduled-update"). + Inc() updateChan <- struct{}{} } } diff --git a/preauth_keys.go b/preauth_keys.go index 1cb9c11..68664c1 100644 --- a/preauth_keys.go +++ b/preauth_keys.go @@ -105,7 +105,10 @@ func (h *Headscale) ExpirePreAuthKey(k *PreAuthKey) error { // If returns no error and a PreAuthKey, it can be used func (h *Headscale) checkKeyValidity(k string) (*PreAuthKey, error) { pak := PreAuthKey{} - if result := h.db.Preload("Namespace").First(&pak, "key = ?", k); errors.Is(result.Error, gorm.ErrRecordNotFound) { + if result := h.db.Preload("Namespace").First(&pak, "key = ?", k); errors.Is( + result.Error, + gorm.ErrRecordNotFound, + ) { return nil, errorAuthKeyNotFound } diff --git a/routes.go b/routes.go index f07b709..84f8dfe 100644 --- a/routes.go +++ b/routes.go @@ -11,7 +11,10 @@ import ( // Deprecated: use machine function instead // GetAdvertisedNodeRoutes returns the subnet routes advertised by a node (identified by // namespace and node name) -func (h *Headscale) GetAdvertisedNodeRoutes(namespace string, nodeName string) (*[]netaddr.IPPrefix, error) { +func (h *Headscale) GetAdvertisedNodeRoutes( + namespace string, + nodeName string, +) (*[]netaddr.IPPrefix, error) { m, err := h.GetMachine(namespace, nodeName) if err != nil { return nil, err @@ -27,7 +30,10 @@ func (h *Headscale) GetAdvertisedNodeRoutes(namespace string, nodeName string) ( // Deprecated: use machine function instead // GetEnabledNodeRoutes returns the subnet routes enabled by a node (identified by // namespace and node name) -func (h *Headscale) GetEnabledNodeRoutes(namespace string, nodeName string) ([]netaddr.IPPrefix, error) { +func (h *Headscale) GetEnabledNodeRoutes( + namespace string, + nodeName string, +) ([]netaddr.IPPrefix, error) { m, err := h.GetMachine(namespace, nodeName) if err != nil { return nil, err @@ -58,7 +64,11 @@ func (h *Headscale) GetEnabledNodeRoutes(namespace string, nodeName string) ([]n // Deprecated: use machine function instead // IsNodeRouteEnabled checks if a certain route has been enabled -func (h *Headscale) IsNodeRouteEnabled(namespace string, nodeName string, routeStr string) bool { +func (h *Headscale) IsNodeRouteEnabled( + namespace string, + nodeName string, + routeStr string, +) bool { route, err := netaddr.ParseIPPrefix(routeStr) if err != nil { return false @@ -80,7 +90,11 @@ func (h *Headscale) IsNodeRouteEnabled(namespace string, nodeName string, routeS // Deprecated: use EnableRoute in machine.go // EnableNodeRoute enables a subnet route advertised by a node (identified by // namespace and node name) -func (h *Headscale) EnableNodeRoute(namespace string, nodeName string, routeStr string) error { +func (h *Headscale) EnableNodeRoute( + namespace string, + nodeName string, + routeStr string, +) error { m, err := h.GetMachine(namespace, nodeName) if err != nil { return err diff --git a/routes_test.go b/routes_test.go index ad16d21..a120eda 100644 --- a/routes_test.go +++ b/routes_test.go @@ -93,7 +93,10 @@ func (s *Suite) TestGetEnableRoutes(c *check.C) { } h.db.Save(&m) - availableRoutes, err := h.GetAdvertisedNodeRoutes("test", "test_enable_route_machine") + availableRoutes, err := h.GetAdvertisedNodeRoutes( + "test", + "test_enable_route_machine", + ) c.Assert(err, check.IsNil) c.Assert(len(*availableRoutes), check.Equals, 2) diff --git a/sharing.go b/sharing.go index 5f6a8f4..581c2af 100644 --- a/sharing.go +++ b/sharing.go @@ -2,9 +2,11 @@ package headscale import "gorm.io/gorm" -const errorSameNamespace = Error("Destination namespace same as origin") -const errorMachineAlreadyShared = Error("Node already shared to this namespace") -const errorMachineNotShared = Error("Machine not shared to this namespace") +const ( + errorSameNamespace = Error("Destination namespace same as origin") + errorMachineAlreadyShared = Error("Node already shared to this namespace") + errorMachineNotShared = Error("Machine not shared to this namespace") +) // SharedMachine is a join table to support sharing nodes between namespaces type SharedMachine struct { @@ -48,7 +50,9 @@ func (h *Headscale) RemoveSharedMachineFromNamespace(m *Machine, ns *Namespace) } sharedMachine := SharedMachine{} - result := h.db.Where("machine_id = ? AND namespace_id = ?", m.ID, ns.ID).Unscoped().Delete(&sharedMachine) + result := h.db.Where("machine_id = ? AND namespace_id = ?", m.ID, ns.ID). + Unscoped(). + Delete(&sharedMachine) if result.Error != nil { return result.Error } diff --git a/sharing_test.go b/sharing_test.go index 4d9e409..7d63a74 100644 --- a/sharing_test.go +++ b/sharing_test.go @@ -4,7 +4,10 @@ import ( "gopkg.in/check.v1" ) -func CreateNodeNamespace(c *check.C, namespace, node, key, IP string) (*Namespace, *Machine) { +func CreateNodeNamespace( + c *check.C, + namespace, node, key, IP string, +) (*Namespace, *Machine) { n1, err := h.CreateNamespace(namespace) c.Assert(err, check.IsNil) @@ -229,7 +232,11 @@ func (s *Suite) TestComplexSharingAcrossNamespaces(c *check.C) { p1sAfter, err := h.getPeers(m1) c.Assert(err, check.IsNil) - c.Assert(len(p1sAfter), check.Equals, 2) // node1 can see node2 (shared) and node4 (same namespace) + c.Assert( + len(p1sAfter), + check.Equals, + 2, + ) // node1 can see node2 (shared) and node4 (same namespace) c.Assert(p1sAfter[0].Name, check.Equals, m2.Name) c.Assert(p1sAfter[1].Name, check.Equals, m4.Name) diff --git a/swagger.go b/swagger.go index 17f5769..d3ae1b2 100644 --- a/swagger.go +++ b/swagger.go @@ -53,7 +53,11 @@ func SwaggerUI(c *gin.Context) { Caller(). Err(err). Msg("Could not render Swagger") - c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Could not render Swagger")) + c.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Could not render Swagger"), + ) return } diff --git a/utils.go b/utils.go index ad0a72d..0b76b5e 100644 --- a/utils.go +++ b/utils.go @@ -25,11 +25,21 @@ type Error string func (e Error) Error() string { return string(e) } -func decode(msg []byte, v interface{}, pubKey *wgkey.Key, privKey *wgkey.Private) error { +func decode( + msg []byte, + v interface{}, + pubKey *wgkey.Key, + privKey *wgkey.Private, +) error { return decodeMsg(msg, v, pubKey, privKey) } -func decodeMsg(msg []byte, v interface{}, pubKey *wgkey.Key, privKey *wgkey.Private) error { +func decodeMsg( + msg []byte, + v interface{}, + pubKey *wgkey.Key, + privKey *wgkey.Private, +) error { decrypted, err := decryptMsg(msg, pubKey, privKey) if err != nil { return err @@ -156,7 +166,11 @@ func tailNodesToString(nodes []*tailcfg.Node) string { } func tailMapResponseToString(resp tailcfg.MapResponse) string { - return fmt.Sprintf("{ Node: %s, Peers: %s }", resp.Node.Name, tailNodesToString(resp.Peers)) + return fmt.Sprintf( + "{ Node: %s, Peers: %s }", + resp.Node.Name, + tailNodesToString(resp.Peers), + ) } func GrpcSocketDialer(ctx context.Context, addr string) (net.Conn, error) {