Go format with shorter lines

This commit is contained in:
Kristoffer Dalby 2021-11-13 08:36:45 +00:00
parent edfcdc466c
commit 03b7ec62ca
35 changed files with 794 additions and 192 deletions

View file

@ -108,7 +108,9 @@ func (h *Headscale) generateACLPolicySrcIP(u string) ([]string, error) {
return h.expandAlias(u) 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, ":") tokens := strings.Split(d, ":")
if len(tokens) < 2 || len(tokens) > 3 { if len(tokens) < 2 || len(tokens) > 3 {
return nil, errorInvalidPortFormat return nil, errorInvalidPortFormat

View file

@ -22,7 +22,11 @@ func (s *Suite) TestInvalidPolicyHuson(c *check.C) {
func (s *Suite) TestParseHosts(c *check.C) { func (s *Suite) TestParseHosts(c *check.C) {
var hs Hosts 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(hs, check.NotNil)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
} }

55
api.go
View file

@ -95,7 +95,8 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) {
Str("handler", "Registration"). Str("handler", "Registration").
Err(err). Err(err).
Msg("Could not create row") Msg("Could not create row")
machineRegistrations.WithLabelValues("unknown", "web", "error", m.Namespace.Name).Inc() machineRegistrations.WithLabelValues("unknown", "web", "error", m.Namespace.Name).
Inc()
return return
} }
m = &newMachine m = &newMachine
@ -156,11 +157,13 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) {
Str("handler", "Registration"). Str("handler", "Registration").
Err(err). Err(err).
Msg("Cannot encode message") 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, "") c.String(http.StatusInternalServerError, "")
return 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) c.Data(200, "application/json; charset=utf-8", respBody)
return return
} }
@ -195,11 +198,13 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) {
Str("handler", "Registration"). Str("handler", "Registration").
Err(err). Err(err).
Msg("Cannot encode message") 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, "") c.String(http.StatusInternalServerError, "")
return 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) c.Data(200, "application/json; charset=utf-8", respBody)
return return
} }
@ -234,7 +239,11 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) {
Str("machine", m.Name). Str("machine", m.Name).
Msg("The node is sending us a new NodeKey, sending auth url") Msg("The node is sending us a new NodeKey, sending auth url")
if h.cfg.OIDC.Issuer != "" { 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 { } else {
resp.AuthURL = fmt.Sprintf("%s/register?key=%s", resp.AuthURL = fmt.Sprintf("%s/register?key=%s",
strings.TrimSuffix(h.cfg.ServerURL, "/"), mKey.HexString()) 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) 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(). log.Trace().
Str("func", "getMapResponse"). Str("func", "getMapResponse").
Str("machine", req.Hostinfo.Hostname). Str("machine", req.Hostinfo.Hostname).
@ -291,7 +304,12 @@ func (h *Headscale) getMapResponse(mKey wgkey.Key, req tailcfg.MapRequest, m *Ma
return nil, err 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 { if err != nil {
log.Error(). log.Error().
Str("func", "getMapResponse"). Str("func", "getMapResponse").
@ -340,7 +358,11 @@ func (h *Headscale) getMapResponse(mKey wgkey.Key, req tailcfg.MapRequest, m *Ma
return data, nil 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{ resp := tailcfg.MapResponse{
KeepAlive: true, KeepAlive: true,
} }
@ -394,7 +416,8 @@ func (h *Headscale) handleAuthKey(
Err(err). Err(err).
Msg("Cannot encode message") Msg("Cannot encode message")
c.String(http.StatusInternalServerError, "") c.String(http.StatusInternalServerError, "")
machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name).Inc() machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name).
Inc()
return return
} }
c.Data(401, "application/json; charset=utf-8", respBody) c.Data(401, "application/json; charset=utf-8", respBody)
@ -402,7 +425,8 @@ func (h *Headscale) handleAuthKey(
Str("func", "handleAuthKey"). Str("func", "handleAuthKey").
Str("machine", m.Name). Str("machine", m.Name).
Msg("Failed authentication via AuthKey") Msg("Failed authentication via AuthKey")
machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name).Inc() machineRegistrations.WithLabelValues("new", "authkey", "error", m.Namespace.Name).
Inc()
return return
} }
@ -416,7 +440,8 @@ func (h *Headscale) handleAuthKey(
Str("func", "handleAuthKey"). Str("func", "handleAuthKey").
Str("machine", m.Name). Str("machine", m.Name).
Msg("Failed to find an available IP") 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 return
} }
log.Info(). log.Info().
@ -445,11 +470,13 @@ func (h *Headscale) handleAuthKey(
Str("machine", m.Name). Str("machine", m.Name).
Err(err). Err(err).
Msg("Cannot encode message") 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!") c.String(http.StatusInternalServerError, "Extremely sad!")
return 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) c.Data(200, "application/json; charset=utf-8", respBody)
log.Info(). log.Info().
Str("func", "handleAuthKey"). Str("func", "handleAuthKey").

75
app.go
View file

@ -152,8 +152,14 @@ func NewHeadscale(cfg Config) (*Headscale, error) {
var dbString string var dbString string
switch cfg.DBtype { switch cfg.DBtype {
case "postgres": case "postgres":
dbString = fmt.Sprintf("host=%s port=%d dbname=%s user=%s password=%s sslmode=disable", cfg.DBhost, dbString = fmt.Sprintf(
cfg.DBport, cfg.DBname, cfg.DBuser, cfg.DBpass) "host=%s port=%d dbname=%s user=%s password=%s sslmode=disable",
cfg.DBhost,
cfg.DBport,
cfg.DBname,
cfg.DBuser,
cfg.DBpass,
)
case "sqlite3": case "sqlite3":
dbString = cfg.DBpath dbString = cfg.DBpath
default: default:
@ -182,7 +188,10 @@ func NewHeadscale(cfg Config) (*Headscale, error) {
} }
if h.cfg.DNSConfig != nil && h.cfg.DNSConfig.Proxied { // if MagicDNS 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 { if err != nil {
return nil, err return nil, err
} }
@ -224,7 +233,10 @@ func (h *Headscale) expireEphemeralNodesWorker() {
for _, ns := range namespaces { for _, ns := range namespaces {
machines, err := h.ListMachinesInNamespace(ns.Name) machines, err := h.ListMachinesInNamespace(ns.Name)
if err != nil { 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 return
} }
@ -232,7 +244,9 @@ func (h *Headscale) expireEphemeralNodesWorker() {
for _, m := range machines { for _, m := range machines {
if m.AuthKey != nil && m.LastSeen != nil && m.AuthKey.Ephemeral && if m.AuthKey != nil && m.LastSeen != nil && m.AuthKey.Ephemeral &&
time.Now().After(m.LastSeen.Add(h.cfg.EphemeralNodeInactivityTimeout)) { 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 err = h.db.Unscoped().Delete(m).Error
if err != nil { if err != nil {
@ -274,18 +288,33 @@ func (h *Headscale) grpcAuthenticationInterceptor(ctx context.Context,
// the server // the server
p, _ := peer.FromContext(ctx) 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) md, ok := metadata.FromIncomingContext(ctx)
if !ok { if !ok {
log.Error().Caller().Str("client_address", p.Addr.String()).Msg("Retrieving metadata is failed") log.Error().
return ctx, status.Errorf(codes.InvalidArgument, "Retrieving metadata is failed") 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"] authHeader, ok := md["authorization"]
if !ok { if !ok {
log.Error().Caller().Str("client_address", p.Addr.String()).Msg("Authorization token is not supplied") log.Error().
return ctx, status.Errorf(codes.Unauthenticated, "Authorization token is not supplied") 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] token := authHeader[0]
@ -295,7 +324,10 @@ func (h *Headscale) grpcAuthenticationInterceptor(ctx context.Context,
Caller(). Caller().
Str("client_address", p.Addr.String()). Str("client_address", p.Addr.String()).
Msg(`missing "Bearer " prefix in "Authorization" header`) 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: // 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 // 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 // us to make use of gRPC for our CLI, but not having to implement any of the remote capabilities
// and API key auth // 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 { //if strings.TrimPrefix(token, AUTH_PREFIX) != a.Token {
// log.Error().Caller().Str("client_address", p.Addr.String()).Msg("invalid 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 // Match gRPC requests here
grpcListener := m.MatchWithWriters( grpcListener := m.MatchWithWriters(
cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc"), 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. // Otherwise match regular http requests.
httpListener := m.Match(cmux.Any()) httpListener := m.Match(cmux.Any())
@ -436,7 +474,10 @@ func (h *Headscale) Serve() error {
p := ginprometheus.NewPrometheus("gin") p := ginprometheus.NewPrometheus("gin")
p.Use(r) 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("/key", h.KeyHandler)
r.GET("/register", h.RegisterWebAPI) r.GET("/register", h.RegisterWebAPI)
r.POST("/machine/:id/map", h.PollNetMapHandler) r.POST("/machine/:id/map", h.PollNetMapHandler)
@ -537,7 +578,8 @@ func (h *Headscale) Serve() error {
g.Go(func() error { return m.Serve() }) 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() return g.Wait()
} }
@ -545,7 +587,8 @@ func (h *Headscale) Serve() error {
func (h *Headscale) getTLSSettings() (*tls.Config, error) { func (h *Headscale) getTLSSettings() (*tls.Config, error) {
if h.cfg.TLSLetsEncryptHostname != "" { if h.cfg.TLSLetsEncryptHostname != "" {
if !strings.HasPrefix(h.cfg.ServerURL, "https://") { 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{ m := autocert.Manager{

View file

@ -17,8 +17,10 @@ var _ = check.Suite(&Suite{})
type Suite struct{} type Suite struct{}
var tmpDir string var (
var h Headscale tmpDir string
h Headscale
)
func (s *Suite) SetUpTest(c *check.C) { func (s *Suite) SetUpTest(c *check.C) {
s.ResetDB(c) s.ResetDB(c)

View file

@ -73,7 +73,11 @@ func (h *Headscale) AppleMobileConfig(c *gin.Context) {
Str("handler", "AppleMobileConfig"). Str("handler", "AppleMobileConfig").
Err(err). Err(err).
Msg("Could not render Apple index template") 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 return
} }
@ -89,7 +93,11 @@ func (h *Headscale) ApplePlatformConfig(c *gin.Context) {
Str("handler", "ApplePlatformConfig"). Str("handler", "ApplePlatformConfig").
Err(err). Err(err).
Msg("Failed not create UUID") 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 return
} }
@ -99,7 +107,11 @@ func (h *Headscale) ApplePlatformConfig(c *gin.Context) {
Str("handler", "ApplePlatformConfig"). Str("handler", "ApplePlatformConfig").
Err(err). Err(err).
Msg("Failed not create UUID") 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 return
} }
@ -117,7 +129,11 @@ func (h *Headscale) ApplePlatformConfig(c *gin.Context) {
Str("handler", "ApplePlatformConfig"). Str("handler", "ApplePlatformConfig").
Err(err). Err(err).
Msg("Could not render Apple macOS template") 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 return
} }
case "ios": case "ios":
@ -126,11 +142,19 @@ func (h *Headscale) ApplePlatformConfig(c *gin.Context) {
Str("handler", "ApplePlatformConfig"). Str("handler", "ApplePlatformConfig").
Err(err). Err(err).
Msg("Could not render Apple iOS template") 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 return
} }
default: 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 return
} }
@ -146,11 +170,19 @@ func (h *Headscale) ApplePlatformConfig(c *gin.Context) {
Str("handler", "ApplePlatformConfig"). Str("handler", "ApplePlatformConfig").
Err(err). Err(err).
Msg("Could not render Apple platform template") 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 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 { type AppleMobileConfig struct {
@ -164,7 +196,8 @@ type AppleMobilePlatformConfig struct {
Url string Url string
} }
var commonTemplate = template.Must(template.New("mobileconfig").Parse(`<?xml version="1.0" encoding="UTF-8"?> var commonTemplate = template.Must(
template.New("mobileconfig").Parse(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
@ -187,7 +220,8 @@ var commonTemplate = template.Must(template.New("mobileconfig").Parse(`<?xml ver
{{.Payload}} {{.Payload}}
</array> </array>
</dict> </dict>
</plist>`)) </plist>`),
)
var iosTemplate = template.Must(template.New("iosTemplate").Parse(` var iosTemplate = template.Must(template.New("iosTemplate").Parse(`
<dict> <dict>

View file

@ -28,7 +28,10 @@ func (s *Suite) TestRegisterMachine(c *check.C) {
_, err = h.GetMachine("test", "testmachine") _, err = h.GetMachine("test", "testmachine")
c.Assert(err, check.IsNil) 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(err, check.IsNil)
c.Assert(m2.Registered, check.Equals, true) c.Assert(m2.Registered, check.Equals, true)

View file

@ -27,7 +27,8 @@ func init() {
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("") 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) debugCmd.AddCommand(createNodeCmd)
} }
@ -56,19 +57,31 @@ var createNodeCmd = &cobra.Command{
name, err := cmd.Flags().GetString("name") name, err := cmd.Flags().GetString("name")
if err != nil { 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 return
} }
machineKey, err := cmd.Flags().GetString("key") machineKey, err := cmd.Flags().GetString("key")
if err != nil { 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 return
} }
routes, err := cmd.Flags().GetStringSlice("route") routes, err := cmd.Flags().GetStringSlice("route")
if err != nil { 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 return
} }
@ -81,7 +94,11 @@ var createNodeCmd = &cobra.Command{
response, err := client.DebugCreateMachine(ctx, request) response, err := client.DebugCreateMachine(ctx, request)
if err != nil { 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 return
} }

View file

@ -48,7 +48,14 @@ var createNamespaceCmd = &cobra.Command{
log.Trace().Interface("request", request).Msg("Sending CreateNamespace request") log.Trace().Interface("request", request).Msg("Sending CreateNamespace request")
response, err := client.CreateNamespace(ctx, request) response, err := client.CreateNamespace(ctx, request)
if err != nil { 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 return
} }
@ -78,7 +85,14 @@ var destroyNamespaceCmd = &cobra.Command{
response, err := client.DeleteNamespace(ctx, request) response, err := client.DeleteNamespace(ctx, request)
if err != nil { 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 return
} }
@ -100,7 +114,11 @@ var listNamespacesCmd = &cobra.Command{
response, err := client.ListNamespaces(ctx, request) response, err := client.ListNamespaces(ctx, request)
if err != nil { 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 return
} }
@ -122,7 +140,11 @@ var listNamespacesCmd = &cobra.Command{
} }
err = pterm.DefaultTable.WithHasHeader().WithData(d).Render() err = pterm.DefaultTable.WithHasHeader().WithData(d).Render()
if err != nil { 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 return
} }
}, },
@ -151,7 +173,14 @@ var renameNamespaceCmd = &cobra.Command{
response, err := client.RenameNamespace(ctx, request) response, err := client.RenameNamespace(ctx, request)
if err != nil { 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 return
} }

View file

@ -86,7 +86,11 @@ var registerNodeCmd = &cobra.Command{
machineKey, err := cmd.Flags().GetString("key") machineKey, err := cmd.Flags().GetString("key")
if err != nil { 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 return
} }
@ -97,7 +101,14 @@ var registerNodeCmd = &cobra.Command{
response, err := client.RegisterMachine(ctx, request) response, err := client.RegisterMachine(ctx, request)
if err != nil { 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 return
} }
@ -126,7 +137,11 @@ var listNodesCmd = &cobra.Command{
response, err := client.ListMachines(ctx, request) response, err := client.ListMachines(ctx, request)
if err != nil { 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 return
} }
@ -143,7 +158,11 @@ var listNodesCmd = &cobra.Command{
err = pterm.DefaultTable.WithHasHeader().WithData(d).Render() err = pterm.DefaultTable.WithHasHeader().WithData(d).Render()
if err != nil { 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 return
} }
}, },
@ -157,7 +176,11 @@ var deleteNodeCmd = &cobra.Command{
id, err := cmd.Flags().GetInt("identifier") id, err := cmd.Flags().GetInt("identifier")
if err != nil { 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 return
} }
@ -171,7 +194,14 @@ var deleteNodeCmd = &cobra.Command{
getResponse, err := client.GetMachine(ctx, getRequest) getResponse, err := client.GetMachine(ctx, getRequest)
if err != nil { 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 return
} }
@ -183,7 +213,10 @@ var deleteNodeCmd = &cobra.Command{
force, _ := cmd.Flags().GetBool("force") force, _ := cmd.Flags().GetBool("force")
if !force { if !force {
prompt := &survey.Confirm{ 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) err = survey.AskOne(prompt, &confirm)
if err != nil { if err != nil {
@ -198,10 +231,21 @@ var deleteNodeCmd = &cobra.Command{
return return
} }
if err != nil { 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 return
} }
SuccessOutput(map[string]string{"Result": "Node deleted"}, "Node deleted", output) SuccessOutput(
map[string]string{"Result": "Node deleted"},
"Node deleted",
output,
)
} else { } else {
SuccessOutput(map[string]string{"Result": "Node not deleted"}, "Node not deleted", output) SuccessOutput(map[string]string{"Result": "Node not deleted"}, "Node not deleted", output)
} }
@ -235,7 +279,11 @@ func sharingWorker(
machineResponse, err := client.GetMachine(ctx, machineRequest) machineResponse, err := client.GetMachine(ctx, machineRequest)
if err != nil { 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 return "", nil, nil, err
} }
@ -245,7 +293,11 @@ func sharingWorker(
namespaceResponse, err := client.GetNamespace(ctx, namespaceRequest) namespaceResponse, err := client.GetNamespace(ctx, namespaceRequest)
if err != nil { 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 return "", nil, nil, err
} }
@ -258,7 +310,11 @@ var shareMachineCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
output, machine, namespace, err := sharingWorker(cmd, args) output, machine, namespace, err := sharingWorker(cmd, args)
if err != nil { 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 return
} }
@ -273,7 +329,11 @@ var shareMachineCmd = &cobra.Command{
response, err := client.ShareMachine(ctx, request) response, err := client.ShareMachine(ctx, request)
if err != nil { 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 return
} }
@ -287,7 +347,11 @@ var unshareMachineCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
output, machine, namespace, err := sharingWorker(cmd, args) output, machine, namespace, err := sharingWorker(cmd, args)
if err != nil { 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 return
} }
@ -302,7 +366,11 @@ var unshareMachineCmd = &cobra.Command{
response, err := client.UnshareMachine(ctx, request) response, err := client.UnshareMachine(ctx, request)
if err != nil { 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 return
} }
@ -310,8 +378,22 @@ var unshareMachineCmd = &cobra.Command{
}, },
} }
func nodesToPtables(currentNamespace string, machines []*v1.Machine) (pterm.TableData, error) { func nodesToPtables(
d := pterm.TableData{{"ID", "Name", "NodeKey", "Namespace", "IP address", "Ephemeral", "Last seen", "Online"}} 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 { for _, machine := range machines {
var ephemeral bool var ephemeral bool
@ -331,7 +413,9 @@ func nodesToPtables(currentNamespace string, machines []*v1.Machine) (pterm.Tabl
nodeKey := tailcfg.NodeKey(nKey) nodeKey := tailcfg.NodeKey(nKey)
var online string 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") online = pterm.LightGreen("true")
} else { } else {
online = pterm.LightRed("false") online = pterm.LightRed("false")

View file

@ -22,8 +22,10 @@ func init() {
preauthkeysCmd.AddCommand(listPreAuthKeys) preauthkeysCmd.AddCommand(listPreAuthKeys)
preauthkeysCmd.AddCommand(createPreAuthKeyCmd) preauthkeysCmd.AddCommand(createPreAuthKeyCmd)
preauthkeysCmd.AddCommand(expirePreAuthKeyCmd) preauthkeysCmd.AddCommand(expirePreAuthKeyCmd)
createPreAuthKeyCmd.PersistentFlags().Bool("reusable", false, "Make the preauthkey reusable") createPreAuthKeyCmd.PersistentFlags().
createPreAuthKeyCmd.PersistentFlags().Bool("ephemeral", false, "Preauthkey for ephemeral nodes") Bool("reusable", false, "Make the preauthkey reusable")
createPreAuthKeyCmd.PersistentFlags().
Bool("ephemeral", false, "Preauthkey for ephemeral nodes")
createPreAuthKeyCmd.Flags(). createPreAuthKeyCmd.Flags().
DurationP("expiration", "e", 24*time.Hour, "Human-readable expiration of the key (30m, 24h, 365d...)") 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) response, err := client.ListPreAuthKeys(ctx, request)
if err != nil { 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 return
} }
@ -64,7 +70,9 @@ var listPreAuthKeys = &cobra.Command{
return 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 { for _, k := range response.PreAuthKeys {
expiration := "-" expiration := "-"
if k.GetExpiration() != nil { if k.GetExpiration() != nil {
@ -91,7 +99,11 @@ var listPreAuthKeys = &cobra.Command{
} }
err = pterm.DefaultTable.WithHasHeader().WithData(d).Render() err = pterm.DefaultTable.WithHasHeader().WithData(d).Render()
if err != nil { 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 return
} }
}, },
@ -139,7 +151,11 @@ var createPreAuthKeyCmd = &cobra.Command{
response, err := client.CreatePreAuthKey(ctx, request) response, err := client.CreatePreAuthKey(ctx, request)
if err != nil { 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 return
} }
@ -175,7 +191,11 @@ var expirePreAuthKeyCmd = &cobra.Command{
response, err := client.ExpirePreAuthKey(ctx, request) response, err := client.ExpirePreAuthKey(ctx, request)
if err != nil { 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 return
} }

View file

@ -10,7 +10,8 @@ import (
func init() { func init() {
rootCmd.PersistentFlags(). rootCmd.PersistentFlags().
StringP("output", "o", "", "Output format. Empty for human-readable, 'json', 'json-line' or 'yaml'") 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{ var rootCmd = &cobra.Command{

View file

@ -21,7 +21,8 @@ func init() {
} }
routesCmd.AddCommand(listRoutesCmd) 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)") enableRouteCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)")
err = enableRouteCmd.MarkFlagRequired("identifier") err = enableRouteCmd.MarkFlagRequired("identifier")
if err != nil { if err != nil {
@ -46,7 +47,11 @@ var listRoutesCmd = &cobra.Command{
machineId, err := cmd.Flags().GetUint64("identifier") machineId, err := cmd.Flags().GetUint64("identifier")
if err != nil { 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 return
} }
@ -60,7 +65,11 @@ var listRoutesCmd = &cobra.Command{
response, err := client.GetMachineRoute(ctx, request) response, err := client.GetMachineRoute(ctx, request)
if err != nil { 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 return
} }
@ -77,7 +86,11 @@ var listRoutesCmd = &cobra.Command{
err = pterm.DefaultTable.WithHasHeader().WithData(d).Render() err = pterm.DefaultTable.WithHasHeader().WithData(d).Render()
if err != nil { 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 return
} }
}, },
@ -95,13 +108,21 @@ omit the route you do not want to enable.
output, _ := cmd.Flags().GetString("output") output, _ := cmd.Flags().GetString("output")
machineId, err := cmd.Flags().GetUint64("identifier") machineId, err := cmd.Flags().GetUint64("identifier")
if err != nil { 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 return
} }
routes, err := cmd.Flags().GetStringSlice("route") routes, err := cmd.Flags().GetStringSlice("route")
if err != nil { 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 return
} }
@ -116,7 +137,14 @@ omit the route you do not want to enable.
response, err := client.EnableMachineRoutes(ctx, request) response, err := client.EnableMachineRoutes(ctx, request)
if err != nil { 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 return
} }
@ -133,7 +161,11 @@ omit the route you do not want to enable.
err = pterm.DefaultTable.WithHasHeader().WithData(d).Render() err = pterm.DefaultTable.WithHasHeader().WithData(d).Render()
if err != nil { 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 return
} }
}, },

View file

@ -149,9 +149,14 @@ func GetDNSConfig() (*tailcfg.DNSConfig, string) {
if viper.IsSet("dns_config.restricted_nameservers") { if viper.IsSet("dns_config.restricted_nameservers") {
if len(dnsConfig.Nameservers) > 0 { if len(dnsConfig.Nameservers) > 0 {
dnsConfig.Routes = make(map[string][]dnstype.Resolver) 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 { for domain, restrictedNameservers := range restrictedDNS {
restrictedResolvers := make([]dnstype.Resolver, len(restrictedNameservers)) restrictedResolvers := make(
[]dnstype.Resolver,
len(restrictedNameservers),
)
for index, nameserverStr := range restrictedNameservers { for index, nameserverStr := range restrictedNameservers {
nameserver, err := netaddr.ParseIP(nameserverStr) nameserver, err := netaddr.ParseIP(nameserverStr)
if err != nil { if err != nil {
@ -219,7 +224,9 @@ func getHeadscaleConfig() headscale.Config {
"10h", "10h",
) // use 10h here because it is the length of a standard business day plus a small amount of leeway ) // 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 { 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 // defaultMachineRegistrationDuration is the default time assigned to a machine registration if one is not
@ -229,7 +236,9 @@ func getHeadscaleConfig() headscale.Config {
"8h", "8h",
) // use 8h here because it's the length of a standard business day ) // use 8h here because it's the length of a standard business day
if viper.GetDuration("default_machine_registration_duration") >= time.Second { 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() dnsConfig, baseDomain := GetDNSConfig()
@ -244,7 +253,9 @@ func getHeadscaleConfig() headscale.Config {
DERP: derpConfig, DERP: derpConfig,
EphemeralNodeInactivityTimeout: viper.GetDuration("ephemeral_node_inactivity_timeout"), EphemeralNodeInactivityTimeout: viper.GetDuration(
"ephemeral_node_inactivity_timeout",
),
DBtype: viper.GetString("db_type"), DBtype: viper.GetString("db_type"),
DBpath: absPath(viper.GetString("db_path")), DBpath: absPath(viper.GetString("db_path")),
@ -256,7 +267,9 @@ func getHeadscaleConfig() headscale.Config {
TLSLetsEncryptHostname: viper.GetString("tls_letsencrypt_hostname"), TLSLetsEncryptHostname: viper.GetString("tls_letsencrypt_hostname"),
TLSLetsEncryptListen: viper.GetString("tls_letsencrypt_listen"), TLSLetsEncryptListen: viper.GetString("tls_letsencrypt_listen"),
TLSLetsEncryptCacheDir: absPath(viper.GetString("tls_letsencrypt_cache_dir")), TLSLetsEncryptCacheDir: absPath(
viper.GetString("tls_letsencrypt_cache_dir"),
),
TLSLetsEncryptChallengeType: viper.GetString("tls_letsencrypt_challenge_type"), TLSLetsEncryptChallengeType: viper.GetString("tls_letsencrypt_challenge_type"),
TLSCertPath: absPath(viper.GetString("tls_cert_path")), TLSCertPath: absPath(viper.GetString("tls_cert_path")),
@ -431,7 +444,10 @@ type tokenAuth struct {
} }
// Return value is mapped to request headers. // 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{ return map[string]string{
"authorization": "Bearer " + t.token, "authorization": "Bearer " + t.token,
}, nil }, nil

View file

@ -63,7 +63,8 @@ func main() {
} }
if !viper.GetBool("disable_check_updates") && !machineOutput { 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{ githubTag := &latest.GithubTag{
Owner: "juanfont", Owner: "juanfont",
Repository: "headscale", Repository: "headscale",

View file

@ -40,7 +40,10 @@ func (*Suite) TestConfigLoading(c *check.C) {
} }
// Symlink the example config file // 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 { if err != nil {
c.Fatal(err) c.Fatal(err)
} }
@ -74,7 +77,10 @@ func (*Suite) TestDNSConfigLoading(c *check.C) {
} }
// Symlink the example config file // 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 { if err != nil {
c.Fatal(err) c.Fatal(err)
} }
@ -128,7 +134,11 @@ func (*Suite) TestTLSConfigValidation(c *check.C) {
check.Matches, check.Matches,
".*Fatal config error: the only supported values for tls_letsencrypt_challenge_type are.*", ".*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) fmt.Println(tmp)
// Check configuration validation errors (2) // Check configuration validation errors (2)

5
db.go
View file

@ -87,7 +87,10 @@ func (h *Headscale) openDB() (*gorm.DB, error) {
// getValue returns the value for the given key in KV // getValue returns the value for the given key in KV
func (h *Headscale) getValue(key string) (string, error) { func (h *Headscale) getValue(key string) (string, error) {
var row KV 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 "", errors.New("not found")
} }
return row.Value, nil return row.Value, nil

17
dns.go
View file

@ -30,7 +30,10 @@ import (
// From the netmask we can find out the wildcard bits (the bits that are not set in the netmask). // 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. // 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 // 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) // 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.") 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 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 var dnsConfig *tailcfg.DNSConfig
if dnsConfigOrig != nil && dnsConfigOrig.Proxied { // if MagicDNS is enabled 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 // Only inject the Search Domain of the current namespace - shared nodes should use their full FQDN
dnsConfig = dnsConfigOrig.Clone() 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 := set.New(set.ThreadSafe)
namespaceSet.Add(m.Namespace) namespaceSet.Add(m.Namespace)

View file

@ -155,7 +155,10 @@ func (api headscaleV1APIServer) RegisterMachine(
ctx context.Context, ctx context.Context,
request *v1.RegisterMachineRequest, request *v1.RegisterMachineRequest,
) (*v1.RegisterMachineResponse, error) { ) (*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( machine, err := api.h.RegisterMachine(
request.GetKey(), request.GetKey(),
request.GetNamespace(), request.GetNamespace(),
@ -208,7 +211,9 @@ func (api headscaleV1APIServer) ListMachines(
return nil, err return nil, err
} }
sharedMachines, err := api.h.ListSharedMachinesInNamespace(request.GetNamespace()) sharedMachines, err := api.h.ListSharedMachinesInNamespace(
request.GetNamespace(),
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -338,7 +343,11 @@ func (api headscaleV1APIServer) DebugCreateMachine(
return nil, err 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{ hostinfo := tailcfg.Hostinfo{
RoutableIPs: routes, RoutableIPs: routes,

View file

@ -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 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[3].Expiration.AsTime().After(time.Now()))
assert.True(s.T(), listedPreAuthKeys[4].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(
assert.True(s.T(), listedPreAuthKeys[1].Expiration.AsTime().Before(time.Now().Add(time.Hour*26))) s.T(),
assert.True(s.T(), listedPreAuthKeys[2].Expiration.AsTime().Before(time.Now().Add(time.Hour*26))) listedPreAuthKeys[0].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[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 // Expire three keys
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
@ -341,11 +359,26 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommand() {
err = json.Unmarshal([]byte(listAfterExpireResult), &listedAfterExpirePreAuthKeys) err = json.Unmarshal([]byte(listAfterExpireResult), &listedAfterExpirePreAuthKeys)
assert.Nil(s.T(), err) assert.Nil(s.T(), err)
assert.True(s.T(), listedAfterExpirePreAuthKeys[0].Expiration.AsTime().Before(time.Now())) assert.True(
assert.True(s.T(), listedAfterExpirePreAuthKeys[1].Expiration.AsTime().Before(time.Now())) s.T(),
assert.True(s.T(), listedAfterExpirePreAuthKeys[2].Expiration.AsTime().Before(time.Now())) listedAfterExpirePreAuthKeys[0].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[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() { func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandWithoutExpiry() {
@ -689,7 +722,10 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
assert.Nil(s.T(), err) assert.Nil(s.T(), err)
var listOnlySharedMachineNamespace []v1.Machine var listOnlySharedMachineNamespace []v1.Machine
err = json.Unmarshal([]byte(listOnlySharedMachineNamespaceResult), &listOnlySharedMachineNamespace) err = json.Unmarshal(
[]byte(listOnlySharedMachineNamespaceResult),
&listOnlySharedMachineNamespace,
)
assert.Nil(s.T(), err) assert.Nil(s.T(), err)
assert.Len(s.T(), listOnlySharedMachineNamespace, 2) assert.Len(s.T(), listOnlySharedMachineNamespace, 2)
@ -738,7 +774,10 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
assert.Nil(s.T(), err) assert.Nil(s.T(), err)
var listOnlyMachineNamespaceAfterDelete []v1.Machine var listOnlyMachineNamespaceAfterDelete []v1.Machine
err = json.Unmarshal([]byte(listOnlyMachineNamespaceAfterDeleteResult), &listOnlyMachineNamespaceAfterDelete) err = json.Unmarshal(
[]byte(listOnlyMachineNamespaceAfterDeleteResult),
&listOnlyMachineNamespaceAfterDelete,
)
assert.Nil(s.T(), err) assert.Nil(s.T(), err)
assert.Len(s.T(), listOnlyMachineNamespaceAfterDelete, 4) assert.Len(s.T(), listOnlyMachineNamespaceAfterDelete, 4)
@ -789,7 +828,10 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
assert.Nil(s.T(), err) assert.Nil(s.T(), err)
var listOnlyMachineNamespaceAfterShare []v1.Machine var listOnlyMachineNamespaceAfterShare []v1.Machine
err = json.Unmarshal([]byte(listOnlyMachineNamespaceAfterShareResult), &listOnlyMachineNamespaceAfterShare) err = json.Unmarshal(
[]byte(listOnlyMachineNamespaceAfterShareResult),
&listOnlyMachineNamespaceAfterShare,
)
assert.Nil(s.T(), err) assert.Nil(s.T(), err)
assert.Len(s.T(), listOnlyMachineNamespaceAfterShare, 5) assert.Len(s.T(), listOnlyMachineNamespaceAfterShare, 5)
@ -846,7 +888,10 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
assert.Nil(s.T(), err) assert.Nil(s.T(), err)
var listOnlyMachineNamespaceAfterUnshare []v1.Machine var listOnlyMachineNamespaceAfterUnshare []v1.Machine
err = json.Unmarshal([]byte(listOnlyMachineNamespaceAfterUnshareResult), &listOnlyMachineNamespaceAfterUnshare) err = json.Unmarshal(
[]byte(listOnlyMachineNamespaceAfterUnshareResult),
&listOnlyMachineNamespaceAfterUnshare,
)
assert.Nil(s.T(), err) assert.Nil(s.T(), err)
assert.Len(s.T(), listOnlyMachineNamespaceAfterUnshare, 4) assert.Len(s.T(), listOnlyMachineNamespaceAfterUnshare, 4)
@ -1010,5 +1055,9 @@ func (s *IntegrationCLITestSuite) TestRouteCommand() {
) )
assert.Nil(s.T(), err) 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",
)
} }

View file

@ -12,7 +12,11 @@ import (
"github.com/ory/dockertest/v3/docker" "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 stdout bytes.Buffer
var stderr bytes.Buffer var stderr bytes.Buffer

View file

@ -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) err := os.MkdirAll(basePath, os.ModePerm)
if err != nil { if err != nil {
return err 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) 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 { if err != nil {
return err 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 { if err != nil {
return err 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{ tailscaleOptions := &dockertest.RunOptions{
Name: hostname, Name: hostname,
Networks: []*dockertest.Network{&s.network}, 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 { if err != nil {
log.Fatalf("Could not start resource: %s", err) log.Fatalf("Could not start resource: %s", err)
} }
@ -210,7 +234,11 @@ func (s *IntegrationTestSuite) SetupSuite() {
for i := 0; i < scales.count; i++ { for i := 0; i < scales.count; i++ {
version := tailscaleVersions[i%len(tailscaleVersions)] 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 scales.tailscales[hostname] = *container
} }
} }
@ -273,7 +301,10 @@ func (s *IntegrationTestSuite) SetupSuite() {
headscaleEndpoint := "http://headscale:8080" 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 { for hostname, tailscale := range scales.tailscales {
command := []string{ command := []string{
"tailscale", "tailscale",
@ -307,7 +338,10 @@ func (s *IntegrationTestSuite) SetupSuite() {
func (s *IntegrationTestSuite) TearDownSuite() { 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 s.stats = stats
} }
@ -427,7 +461,13 @@ func (s *IntegrationTestSuite) TestPingAllPeers() {
ip.String(), 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( result, err := ExecuteCommand(
&tailscale, &tailscale,
command, command,
@ -449,7 +489,15 @@ func (s *IntegrationTestSuite) TestSharedNodes() {
result, err := ExecuteCommand( result, err := ExecuteCommand(
&s.headscale, &s.headscale,
[]string{"headscale", "nodes", "list", "--output", "json", "--namespace", "shared"}, []string{
"headscale",
"nodes",
"list",
"--output",
"json",
"--namespace",
"shared",
},
[]string{}, []string{},
) )
assert.Nil(s.T(), err) assert.Nil(s.T(), err)
@ -520,7 +568,13 @@ func (s *IntegrationTestSuite) TestSharedNodes() {
ip.String(), 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( result, err := ExecuteCommand(
&tailscale, &tailscale,
command, command,
@ -578,9 +632,19 @@ func (s *IntegrationTestSuite) TestTailDrop() {
"PUT", "PUT",
"--upload-file", "--upload-file",
fmt.Sprintf("/tmp/file_from_%s", hostname), 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( _, err = ExecuteCommand(
&tailscale, &tailscale,
command, command,
@ -621,7 +685,13 @@ func (s *IntegrationTestSuite) TestTailDrop() {
"ls", "ls",
fmt.Sprintf("/tmp/file_from_%s", peername), 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( result, err := ExecuteCommand(
&tailscale, &tailscale,
command, command,
@ -629,7 +699,11 @@ func (s *IntegrationTestSuite) TestTailDrop() {
) )
assert.Nil(t, err) assert.Nil(t, err)
fmt.Printf("Result for %s: %s\n", peername, result) 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 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) fts := make(map[netaddr.IP]string)
for _, tailscale := range tailscales { for _, tailscale := range tailscales {
command := []string{ command := []string{

View file

@ -73,8 +73,12 @@ func (m Machine) isExpired() bool {
func (h *Headscale) updateMachineExpiry(m *Machine) { func (h *Headscale) updateMachineExpiry(m *Machine) {
if m.isExpired() { if m.isExpired() {
now := time.Now().UTC() now := time.Now().UTC()
maxExpiry := now.Add(h.cfg.MaxMachineRegistrationDuration) // calculate the maximum expiry maxExpiry := now.Add(
defaultExpiry := now.Add(h.cfg.DefaultMachineRegistrationDuration) // calculate the default expiry 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 // clamp the expiry time of the machine registration to the maximum allowed, or use the default if none supplied
if maxExpiry.Before(*m.RequestedExpiry) { if maxExpiry.Before(*m.RequestedExpiry) {
@ -157,7 +161,9 @@ func (h *Headscale) getSharedTo(m *Machine) (Machines, error) {
peers := make(Machines, 0) peers := make(Machines, 0)
for _, sharedMachine := range sharedMachines { for _, sharedMachine := range sharedMachines {
namespaceMachines, err := h.ListMachinesInNamespace(sharedMachine.Namespace.Name) namespaceMachines, err := h.ListMachinesInNamespace(
sharedMachine.Namespace.Name,
)
if err != nil { if err != nil {
return Machines{}, err 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 // toNode converts a Machine into a Tailscale Node. includeRoutes is false for shared nodes
// as per the expected behaviour in the official SaaS // 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) nKey, err := wgkey.ParseHex(m.NodeKey)
if err != nil { if err != nil {
return nil, err return nil, err
@ -425,7 +435,10 @@ func (m Machine) toNode(baseDomain string, dnsConfig *tailcfg.DNSConfig, include
addrs = append(addrs, ip) // missing the ipv6 ? addrs = append(addrs, ip) // missing the ipv6 ?
allowedIPs := []netaddr.IPPrefix{} 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 { if includeRoutes {
routesStr := []string{} routesStr := []string{}
@ -571,7 +584,10 @@ func (h *Headscale) RegisterMachine(key string, namespace string) (*Machine, err
} }
m := Machine{} 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") return nil, errors.New("Machine not found")
} }
@ -693,7 +709,11 @@ func (h *Headscale) EnableRoutes(m *Machine, routeStrs ...string) error {
for _, newRoute := range newRoutes { for _, newRoute := range newRoutes {
if !containsIpPrefix(availableRoutes, newRoute) { 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,
)
} }
} }

View file

@ -32,7 +32,7 @@ var (
Name: "update_request_sent_to_node_total", Name: "update_request_sent_to_node_total",
Help: "The number of calls/messages issued on a specific nodes update channel", Help: "The number of calls/messages issued on a specific nodes update channel",
}, []string{"namespace", "machine", "status"}) }, []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{ updateRequestsReceivedOnChannel = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: prometheusNamespace, Namespace: prometheusNamespace,
Name: "update_request_received_on_channel_total", Name: "update_request_received_on_channel_total",

View file

@ -102,7 +102,10 @@ func (h *Headscale) RenameNamespace(oldName, newName string) error {
// GetNamespace fetches a namespace by name // GetNamespace fetches a namespace by name
func (h *Headscale) GetNamespace(name string) (*Namespace, error) { func (h *Headscale) GetNamespace(name string) (*Namespace, error) {
n := Namespace{} 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 nil, errorNamespaceNotFound
} }
return &n, nil return &n, nil
@ -144,7 +147,9 @@ func (h *Headscale) ListSharedMachinesInNamespace(name string) ([]Machine, error
machines := []Machine{} machines := []Machine{}
for _, sharedMachine := range sharedMachines { 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 { if err != nil {
return nil, err return nil, err
} }
@ -173,7 +178,10 @@ func (h *Headscale) RequestMapUpdates(namespaceID uint) error {
v, err := h.getValue("namespaces_pending_updates") v, err := h.getValue("namespaces_pending_updates")
if err != nil || v == "" { 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 { if err != nil {
return err return err
} }
@ -182,7 +190,10 @@ func (h *Headscale) RequestMapUpdates(namespaceID uint) error {
names := []string{} names := []string{}
err = json.Unmarshal([]byte(v), &names) err = json.Unmarshal([]byte(v), &names)
if err != nil { 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 { if err != nil {
return err return err
} }

36
oidc.go
View file

@ -39,7 +39,10 @@ func (h *Headscale) initOIDC() error {
ClientID: h.cfg.OIDC.ClientID, ClientID: h.cfg.OIDC.ClientID,
ClientSecret: h.cfg.OIDC.ClientSecret, ClientSecret: h.cfg.OIDC.ClientSecret,
Endpoint: h.oidcProvider.Endpoint(), Endpoint: h.oidcProvider.Endpoint(),
RedirectURL: fmt.Sprintf("%s/oidc/callback", strings.TrimSuffix(h.cfg.ServerURL, "/")), RedirectURL: fmt.Sprintf(
"%s/oidc/callback",
strings.TrimSuffix(h.cfg.ServerURL, "/"),
),
Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
} }
} }
@ -127,7 +130,10 @@ func (h *Headscale) OIDCCallback(c *gin.Context) {
// Extract custom claims // Extract custom claims
var claims IDTokenClaims var claims IDTokenClaims
if err = idToken.Claims(&claims); err != nil { 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 return
} }
@ -135,7 +141,8 @@ func (h *Headscale) OIDCCallback(c *gin.Context) {
mKeyIf, mKeyFound := h.oidcStateCache.Get(state) mKeyIf, mKeyFound := h.oidcStateCache.Get(state)
if !mKeyFound { 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") c.String(http.StatusBadRequest, "state has expired")
return return
} }
@ -151,7 +158,10 @@ func (h *Headscale) OIDCCallback(c *gin.Context) {
m, err := h.GetMachineByMachineKey(mKeyStr) m, err := h.GetMachineByMachineKey(mKeyStr)
if err != nil { if err != nil {
log.Error().Msg("machine key not found in database") 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 return
} }
@ -168,15 +178,22 @@ func (h *Headscale) OIDCCallback(c *gin.Context) {
ns, err = h.CreateNamespace(nsName) ns, err = h.CreateNamespace(nsName)
if err != nil { if err != nil {
log.Error().Msgf("could not create new namespace '%s'", claims.Email) log.Error().
c.String(http.StatusInternalServerError, "could not create new namespace") Msgf("could not create new namespace '%s'", claims.Email)
c.String(
http.StatusInternalServerError,
"could not create new namespace",
)
return return
} }
} }
ip, err := h.getAvailableIP() ip, err := h.getAvailableIP()
if err != nil { 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 return
} }
@ -209,7 +226,10 @@ func (h *Headscale) OIDCCallback(c *gin.Context) {
Str("username", claims.Username). Str("username", claims.Username).
Str("machine", m.Name). Str("machine", m.Name).
Msg("Email could not be mapped to a namespace") 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" // getNamespaceFromEmail passes the users email through a list of "matchers"

View file

@ -164,10 +164,18 @@ func TestHeadscale_getNamespaceFromEmail(t *testing.T) {
} }
got, got1 := h.getNamespaceFromEmail(tt.args.email) got, got1 := h.getNamespaceFromEmail(tt.args.email)
if got != tt.want { 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 { 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,
)
} }
}) })
} }

37
poll.go
View file

@ -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 // 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. // 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{}{} }() go func() { updateChan <- struct{}{} }()
return return
} else if req.OmitPeers && req.Stream { } else if req.OmitPeers && req.Stream {
@ -184,10 +185,20 @@ func (h *Headscale) PollNetMapHandler(c *gin.Context) {
Str("handler", "PollNetMap"). Str("handler", "PollNetMap").
Str("machine", m.Name). Str("machine", m.Name).
Msg("Notifying peers") 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{}{} }() 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(). log.Trace().
Str("handler", "PollNetMap"). Str("handler", "PollNetMap").
Str("id", c.Param("id")). Str("id", c.Param("id")).
@ -260,7 +271,8 @@ func (h *Headscale) PollNetMapStream(
now := time.Now().UTC() now := time.Now().UTC()
m.LastSeen = &now 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 m.LastSuccessfulUpdate = &now
h.db.Save(&m) h.db.Save(&m)
@ -324,7 +336,8 @@ func (h *Headscale) PollNetMapStream(
Str("machine", m.Name). Str("machine", m.Name).
Str("channel", "update"). Str("channel", "update").
Msg("Received a request for 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) { if h.isOutdated(m) {
log.Debug(). log.Debug().
Str("handler", "PollNetMapStream"). Str("handler", "PollNetMapStream").
@ -349,7 +362,8 @@ func (h *Headscale) PollNetMapStream(
Str("channel", "update"). Str("channel", "update").
Err(err). Err(err).
Msg("Could not write the map response") 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 return false
} }
log.Trace(). log.Trace().
@ -357,7 +371,8 @@ func (h *Headscale) PollNetMapStream(
Str("machine", m.Name). Str("machine", m.Name).
Str("channel", "update"). Str("channel", "update").
Msg("Updated Map has been sent") 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, // Keep track of the last successful update,
// we sometimes end in a state were the update // we sometimes end in a state were the update
@ -377,7 +392,8 @@ func (h *Headscale) PollNetMapStream(
} }
now := time.Now().UTC() 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 m.LastSuccessfulUpdate = &now
h.db.Save(&m) h.db.Save(&m)
@ -424,7 +440,7 @@ func (h *Headscale) PollNetMapStream(
Str("machine", m.Name). Str("machine", m.Name).
Str("channel", "Done"). Str("channel", "Done").
Msg("Closing update channel") Msg("Closing update channel")
//h.closeUpdateChannel(m) // h.closeUpdateChannel(m)
close(updateChan) close(updateChan)
log.Trace(). log.Trace().
@ -483,7 +499,8 @@ func (h *Headscale) scheduledPollWorker(
Str("func", "scheduledPollWorker"). Str("func", "scheduledPollWorker").
Str("machine", m.Name). Str("machine", m.Name).
Msg("Sending update request") 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{}{} updateChan <- struct{}{}
} }
} }

View file

@ -105,7 +105,10 @@ func (h *Headscale) ExpirePreAuthKey(k *PreAuthKey) error {
// If returns no error and a PreAuthKey, it can be used // If returns no error and a PreAuthKey, it can be used
func (h *Headscale) checkKeyValidity(k string) (*PreAuthKey, error) { func (h *Headscale) checkKeyValidity(k string) (*PreAuthKey, error) {
pak := PreAuthKey{} 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 return nil, errorAuthKeyNotFound
} }

View file

@ -11,7 +11,10 @@ import (
// Deprecated: use machine function instead // Deprecated: use machine function instead
// GetAdvertisedNodeRoutes returns the subnet routes advertised by a node (identified by // GetAdvertisedNodeRoutes returns the subnet routes advertised by a node (identified by
// namespace and node name) // 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) m, err := h.GetMachine(namespace, nodeName)
if err != nil { if err != nil {
return nil, err return nil, err
@ -27,7 +30,10 @@ func (h *Headscale) GetAdvertisedNodeRoutes(namespace string, nodeName string) (
// Deprecated: use machine function instead // Deprecated: use machine function instead
// GetEnabledNodeRoutes returns the subnet routes enabled by a node (identified by // GetEnabledNodeRoutes returns the subnet routes enabled by a node (identified by
// namespace and node name) // 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) m, err := h.GetMachine(namespace, nodeName)
if err != nil { if err != nil {
return nil, err return nil, err
@ -58,7 +64,11 @@ func (h *Headscale) GetEnabledNodeRoutes(namespace string, nodeName string) ([]n
// Deprecated: use machine function instead // Deprecated: use machine function instead
// IsNodeRouteEnabled checks if a certain route has been enabled // 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) route, err := netaddr.ParseIPPrefix(routeStr)
if err != nil { if err != nil {
return false return false
@ -80,7 +90,11 @@ func (h *Headscale) IsNodeRouteEnabled(namespace string, nodeName string, routeS
// Deprecated: use EnableRoute in machine.go // Deprecated: use EnableRoute in machine.go
// EnableNodeRoute enables a subnet route advertised by a node (identified by // EnableNodeRoute enables a subnet route advertised by a node (identified by
// namespace and node name) // 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) m, err := h.GetMachine(namespace, nodeName)
if err != nil { if err != nil {
return err return err

View file

@ -93,7 +93,10 @@ func (s *Suite) TestGetEnableRoutes(c *check.C) {
} }
h.db.Save(&m) 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(err, check.IsNil)
c.Assert(len(*availableRoutes), check.Equals, 2) c.Assert(len(*availableRoutes), check.Equals, 2)

View file

@ -2,9 +2,11 @@ package headscale
import "gorm.io/gorm" import "gorm.io/gorm"
const errorSameNamespace = Error("Destination namespace same as origin") const (
const errorMachineAlreadyShared = Error("Node already shared to this namespace") errorSameNamespace = Error("Destination namespace same as origin")
const errorMachineNotShared = Error("Machine not shared to this namespace") 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 // SharedMachine is a join table to support sharing nodes between namespaces
type SharedMachine struct { type SharedMachine struct {
@ -48,7 +50,9 @@ func (h *Headscale) RemoveSharedMachineFromNamespace(m *Machine, ns *Namespace)
} }
sharedMachine := SharedMachine{} 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 { if result.Error != nil {
return result.Error return result.Error
} }

View file

@ -4,7 +4,10 @@ import (
"gopkg.in/check.v1" "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) n1, err := h.CreateNamespace(namespace)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
@ -229,7 +232,11 @@ func (s *Suite) TestComplexSharingAcrossNamespaces(c *check.C) {
p1sAfter, err := h.getPeers(m1) p1sAfter, err := h.getPeers(m1)
c.Assert(err, check.IsNil) 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[0].Name, check.Equals, m2.Name)
c.Assert(p1sAfter[1].Name, check.Equals, m4.Name) c.Assert(p1sAfter[1].Name, check.Equals, m4.Name)

View file

@ -53,7 +53,11 @@ func SwaggerUI(c *gin.Context) {
Caller(). Caller().
Err(err). Err(err).
Msg("Could not render Swagger") 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 return
} }

View file

@ -25,11 +25,21 @@ type Error string
func (e Error) Error() string { return string(e) } 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) 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) decrypted, err := decryptMsg(msg, pubKey, privKey)
if err != nil { if err != nil {
return err return err
@ -156,7 +166,11 @@ func tailNodesToString(nodes []*tailcfg.Node) string {
} }
func tailMapResponseToString(resp tailcfg.MapResponse) 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) { func GrpcSocketDialer(ctx context.Context, addr string) (net.Conn, error) {