mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-11-04 10:01:05 +01:00 
			
		
		
		
	Merge branch 'main' into acl-syntax-fixes
This commit is contained in:
		
						commit
						7cd0f5e8a4
					
				@ -27,6 +27,7 @@
 | 
				
			|||||||
- Use [Prometheus]'s duration parser, supporting days (`d`), weeks (`w`) and years (`y`) [#598](https://github.com/juanfont/headscale/pull/598)
 | 
					- Use [Prometheus]'s duration parser, supporting days (`d`), weeks (`w`) and years (`y`) [#598](https://github.com/juanfont/headscale/pull/598)
 | 
				
			||||||
- Add support for reloading ACLs with SIGHUP [#601](https://github.com/juanfont/headscale/pull/601)
 | 
					- Add support for reloading ACLs with SIGHUP [#601](https://github.com/juanfont/headscale/pull/601)
 | 
				
			||||||
- Use new ACL syntax [#618](https://github.com/juanfont/headscale/pull/618)
 | 
					- Use new ACL syntax [#618](https://github.com/juanfont/headscale/pull/618)
 | 
				
			||||||
 | 
					- Add -c option to specify config file from command line [#285](https://github.com/juanfont/headscale/issues/285) [#612](https://github.com/juanfont/headscale/pull/601)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.15.0 (2022-03-20)
 | 
					## 0.15.0 (2022-03-20)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										20
									
								
								app.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								app.go
									
									
									
									
									
								
							@ -657,7 +657,9 @@ func (h *Headscale) Serve() error {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
					log.Info().
 | 
										log.Info().
 | 
				
			||||||
						Str("path", aclPath).
 | 
											Str("path", aclPath).
 | 
				
			||||||
						Msg("ACL policy successfully reloaded")
 | 
											Msg("ACL policy successfully reloaded, notifying nodes of change")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										h.setLastStateChangeToNow()
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
@ -756,13 +758,25 @@ func (h *Headscale) getTLSSettings() (*tls.Config, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (h *Headscale) setLastStateChangeToNow(namespace string) {
 | 
					func (h *Headscale) setLastStateChangeToNow(namespaces ...string) {
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	now := time.Now().UTC()
 | 
						now := time.Now().UTC()
 | 
				
			||||||
	lastStateUpdate.WithLabelValues("", "headscale").Set(float64(now.Unix()))
 | 
					
 | 
				
			||||||
 | 
						if len(namespaces) == 0 {
 | 
				
			||||||
 | 
							namespaces, err = h.ListNamespacesStr()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Error().Caller().Err(err).Msg("failed to fetch all namespaces, failing to update last changed state.")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, namespace := range namespaces {
 | 
				
			||||||
 | 
							lastStateUpdate.WithLabelValues(namespace, "headscale").Set(float64(now.Unix()))
 | 
				
			||||||
		if h.lastStateChange == nil {
 | 
							if h.lastStateChange == nil {
 | 
				
			||||||
			h.lastStateChange = xsync.NewMapOf[time.Time]()
 | 
								h.lastStateChange = xsync.NewMapOf[time.Time]()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		h.lastStateChange.Store(namespace, now)
 | 
							h.lastStateChange.Store(namespace, now)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (h *Headscale) getLastStateChange(namespaces ...string) time.Time {
 | 
					func (h *Headscale) getLastStateChange(namespaces ...string) time.Time {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										28
									
								
								cmd/headscale/cli/dump_config.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								cmd/headscale/cli/dump_config.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					package cli
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
						"github.com/spf13/viper"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						rootCmd.AddCommand(dumpConfigCmd)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var dumpConfigCmd = &cobra.Command{
 | 
				
			||||||
 | 
						Use:    "dumpConfig",
 | 
				
			||||||
 | 
						Short:  "dump current config to /etc/headscale/config.dump.yaml, integration test only",
 | 
				
			||||||
 | 
						Hidden: true,
 | 
				
			||||||
 | 
						Args: func(cmd *cobra.Command, args []string) error {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						Run: func(cmd *cobra.Command, args []string) {
 | 
				
			||||||
 | 
							err := viper.WriteConfigAs("/etc/headscale/config.dump.yaml")
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								//nolint
 | 
				
			||||||
 | 
								fmt.Println("Failed to dump config")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -3,17 +3,75 @@ package cli
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/juanfont/headscale"
 | 
				
			||||||
 | 
						"github.com/rs/zerolog"
 | 
				
			||||||
 | 
						"github.com/rs/zerolog/log"
 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
						"github.com/tcnksm/go-latest"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var cfgFile string = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
 | 
						cobra.OnInitialize(initConfig)
 | 
				
			||||||
 | 
						rootCmd.PersistentFlags().
 | 
				
			||||||
 | 
							StringVarP(&cfgFile, "config", "c", "", "config file (default is /etc/headscale/config.yaml)")
 | 
				
			||||||
	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().
 | 
						rootCmd.PersistentFlags().
 | 
				
			||||||
		Bool("force", false, "Disable prompts and forces the execution")
 | 
							Bool("force", false, "Disable prompts and forces the execution")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func initConfig() {
 | 
				
			||||||
 | 
						if cfgFile != "" {
 | 
				
			||||||
 | 
							err := headscale.LoadConfig(cfgFile, true)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatal().Caller().Err(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							err := headscale.LoadConfig("", false)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatal().Caller().Err(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cfg, err := headscale.GetHeadscaleConfig()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal().Caller().Err(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						machineOutput := HasMachineOutputFlag()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						zerolog.SetGlobalLevel(cfg.LogLevel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If the user has requested a "machine" readable format,
 | 
				
			||||||
 | 
						// then disable login so the output remains valid.
 | 
				
			||||||
 | 
						if machineOutput {
 | 
				
			||||||
 | 
							zerolog.SetGlobalLevel(zerolog.Disabled)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !cfg.DisableUpdateCheck && !machineOutput {
 | 
				
			||||||
 | 
							if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") &&
 | 
				
			||||||
 | 
								Version != "dev" {
 | 
				
			||||||
 | 
								githubTag := &latest.GithubTag{
 | 
				
			||||||
 | 
									Owner:      "juanfont",
 | 
				
			||||||
 | 
									Repository: "headscale",
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								res, err := latest.Check(githubTag, Version)
 | 
				
			||||||
 | 
								if err == nil && res.Outdated {
 | 
				
			||||||
 | 
									//nolint
 | 
				
			||||||
 | 
									fmt.Printf(
 | 
				
			||||||
 | 
										"An updated version of Headscale has been found (%s vs. your current %s). Check it out https://github.com/juanfont/headscale/releases\n",
 | 
				
			||||||
 | 
										res.Current,
 | 
				
			||||||
 | 
										Version,
 | 
				
			||||||
 | 
									)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var rootCmd = &cobra.Command{
 | 
					var rootCmd = &cobra.Command{
 | 
				
			||||||
	Use:   "headscale",
 | 
						Use:   "headscale",
 | 
				
			||||||
	Short: "headscale - a Tailscale control server",
 | 
						Short: "headscale - a Tailscale control server",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,17 +1,13 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"runtime"
 | 
					 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/efekarakus/termcolor"
 | 
						"github.com/efekarakus/termcolor"
 | 
				
			||||||
	"github.com/juanfont/headscale"
 | 
					 | 
				
			||||||
	"github.com/juanfont/headscale/cmd/headscale/cli"
 | 
						"github.com/juanfont/headscale/cmd/headscale/cli"
 | 
				
			||||||
	"github.com/rs/zerolog"
 | 
						"github.com/rs/zerolog"
 | 
				
			||||||
	"github.com/rs/zerolog/log"
 | 
						"github.com/rs/zerolog/log"
 | 
				
			||||||
	"github.com/tcnksm/go-latest"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
@ -43,39 +39,5 @@ func main() {
 | 
				
			|||||||
		NoColor:    !colors,
 | 
							NoColor:    !colors,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg, err := headscale.GetHeadscaleConfig()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatal().Caller().Err(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	machineOutput := cli.HasMachineOutputFlag()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	zerolog.SetGlobalLevel(cfg.LogLevel)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// If the user has requested a "machine" readable format,
 | 
					 | 
				
			||||||
	// then disable login so the output remains valid.
 | 
					 | 
				
			||||||
	if machineOutput {
 | 
					 | 
				
			||||||
		zerolog.SetGlobalLevel(zerolog.Disabled)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !cfg.DisableUpdateCheck && !machineOutput {
 | 
					 | 
				
			||||||
		if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") &&
 | 
					 | 
				
			||||||
			cli.Version != "dev" {
 | 
					 | 
				
			||||||
			githubTag := &latest.GithubTag{
 | 
					 | 
				
			||||||
				Owner:      "juanfont",
 | 
					 | 
				
			||||||
				Repository: "headscale",
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			res, err := latest.Check(githubTag, cli.Version)
 | 
					 | 
				
			||||||
			if err == nil && res.Outdated {
 | 
					 | 
				
			||||||
				//nolint
 | 
					 | 
				
			||||||
				fmt.Printf(
 | 
					 | 
				
			||||||
					"An updated version of Headscale has been found (%s vs. your current %s). Check it out https://github.com/juanfont/headscale/releases\n",
 | 
					 | 
				
			||||||
					res.Current,
 | 
					 | 
				
			||||||
					cli.Version,
 | 
					 | 
				
			||||||
				)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cli.Execute()
 | 
						cli.Execute()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -27,6 +27,51 @@ func (s *Suite) SetUpSuite(c *check.C) {
 | 
				
			|||||||
func (s *Suite) TearDownSuite(c *check.C) {
 | 
					func (s *Suite) TearDownSuite(c *check.C) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (*Suite) TestConfigFileLoading(c *check.C) {
 | 
				
			||||||
 | 
						tmpDir, err := ioutil.TempDir("", "headscale")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							c.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer os.RemoveAll(tmpDir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						path, err := os.Getwd()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							c.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cfgFile := filepath.Join(tmpDir, "config.yaml")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Symlink the example config file
 | 
				
			||||||
 | 
						err = os.Symlink(
 | 
				
			||||||
 | 
							filepath.Clean(path+"/../../config-example.yaml"),
 | 
				
			||||||
 | 
							cfgFile,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							c.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Load example config, it should load without validation errors
 | 
				
			||||||
 | 
						err = headscale.LoadConfig(cfgFile, true)
 | 
				
			||||||
 | 
						c.Assert(err, check.IsNil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Test that config file was interpreted correctly
 | 
				
			||||||
 | 
						c.Assert(viper.GetString("server_url"), check.Equals, "http://127.0.0.1:8080")
 | 
				
			||||||
 | 
						c.Assert(viper.GetString("listen_addr"), check.Equals, "0.0.0.0:8080")
 | 
				
			||||||
 | 
						c.Assert(viper.GetString("metrics_listen_addr"), check.Equals, "127.0.0.1:9090")
 | 
				
			||||||
 | 
						c.Assert(viper.GetString("db_type"), check.Equals, "sqlite3")
 | 
				
			||||||
 | 
						c.Assert(viper.GetString("db_path"), check.Equals, "/var/lib/headscale/db.sqlite")
 | 
				
			||||||
 | 
						c.Assert(viper.GetString("tls_letsencrypt_hostname"), check.Equals, "")
 | 
				
			||||||
 | 
						c.Assert(viper.GetString("tls_letsencrypt_listen"), check.Equals, ":http")
 | 
				
			||||||
 | 
						c.Assert(viper.GetString("tls_letsencrypt_challenge_type"), check.Equals, "HTTP-01")
 | 
				
			||||||
 | 
						c.Assert(viper.GetStringSlice("dns_config.nameservers")[0], check.Equals, "1.1.1.1")
 | 
				
			||||||
 | 
						c.Assert(
 | 
				
			||||||
 | 
							headscale.GetFileMode("unix_socket_permission"),
 | 
				
			||||||
 | 
							check.Equals,
 | 
				
			||||||
 | 
							fs.FileMode(0o770),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						c.Assert(viper.GetBool("logtail.enabled"), check.Equals, false)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (*Suite) TestConfigLoading(c *check.C) {
 | 
					func (*Suite) TestConfigLoading(c *check.C) {
 | 
				
			||||||
	tmpDir, err := ioutil.TempDir("", "headscale")
 | 
						tmpDir, err := ioutil.TempDir("", "headscale")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@ -49,7 +94,7 @@ func (*Suite) TestConfigLoading(c *check.C) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Load example config, it should load without validation errors
 | 
						// Load example config, it should load without validation errors
 | 
				
			||||||
	err = headscale.LoadConfig(tmpDir)
 | 
						err = headscale.LoadConfig(tmpDir, false)
 | 
				
			||||||
	c.Assert(err, check.IsNil)
 | 
						c.Assert(err, check.IsNil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test that config file was interpreted correctly
 | 
						// Test that config file was interpreted correctly
 | 
				
			||||||
@ -92,7 +137,7 @@ func (*Suite) TestDNSConfigLoading(c *check.C) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Load example config, it should load without validation errors
 | 
						// Load example config, it should load without validation errors
 | 
				
			||||||
	err = headscale.LoadConfig(tmpDir)
 | 
						err = headscale.LoadConfig(tmpDir, false)
 | 
				
			||||||
	c.Assert(err, check.IsNil)
 | 
						c.Assert(err, check.IsNil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dnsConfig, baseDomain := headscale.GetDNSConfig()
 | 
						dnsConfig, baseDomain := headscale.GetDNSConfig()
 | 
				
			||||||
@ -125,7 +170,7 @@ func (*Suite) TestTLSConfigValidation(c *check.C) {
 | 
				
			|||||||
	writeConfig(c, tmpDir, configYaml)
 | 
						writeConfig(c, tmpDir, configYaml)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check configuration validation errors (1)
 | 
						// Check configuration validation errors (1)
 | 
				
			||||||
	err = headscale.LoadConfig(tmpDir)
 | 
						err = headscale.LoadConfig(tmpDir, false)
 | 
				
			||||||
	c.Assert(err, check.NotNil)
 | 
						c.Assert(err, check.NotNil)
 | 
				
			||||||
	// check.Matches can not handle multiline strings
 | 
						// check.Matches can not handle multiline strings
 | 
				
			||||||
	tmp := strings.ReplaceAll(err.Error(), "\n", "***")
 | 
						tmp := strings.ReplaceAll(err.Error(), "\n", "***")
 | 
				
			||||||
@ -150,6 +195,6 @@ func (*Suite) TestTLSConfigValidation(c *check.C) {
 | 
				
			|||||||
		"---\nserver_url: \"http://127.0.0.1:8080\"\ntls_letsencrypt_hostname: \"example.com\"\ntls_letsencrypt_challenge_type: \"TLS-ALPN-01\"",
 | 
							"---\nserver_url: \"http://127.0.0.1:8080\"\ntls_letsencrypt_hostname: \"example.com\"\ntls_letsencrypt_challenge_type: \"TLS-ALPN-01\"",
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	writeConfig(c, tmpDir, configYaml)
 | 
						writeConfig(c, tmpDir, configYaml)
 | 
				
			||||||
	err = headscale.LoadConfig(tmpDir)
 | 
						err = headscale.LoadConfig(tmpDir, false)
 | 
				
			||||||
	c.Assert(err, check.IsNil)
 | 
						c.Assert(err, check.IsNil)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								config.go
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								config.go
									
									
									
									
									
								
							@ -114,7 +114,10 @@ type ACLConfig struct {
 | 
				
			|||||||
	PolicyPath string
 | 
						PolicyPath string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func LoadConfig(path string) error {
 | 
					func LoadConfig(path string, isFile bool) error {
 | 
				
			||||||
 | 
						if isFile {
 | 
				
			||||||
 | 
							viper.SetConfigFile(path)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		viper.SetConfigName("config")
 | 
							viper.SetConfigName("config")
 | 
				
			||||||
		if path == "" {
 | 
							if path == "" {
 | 
				
			||||||
			viper.AddConfigPath("/etc/headscale/")
 | 
								viper.AddConfigPath("/etc/headscale/")
 | 
				
			||||||
@ -124,6 +127,7 @@ func LoadConfig(path string) error {
 | 
				
			|||||||
			// For testing
 | 
								// For testing
 | 
				
			||||||
			viper.AddConfigPath(path)
 | 
								viper.AddConfigPath(path)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	viper.SetEnvPrefix("headscale")
 | 
						viper.SetEnvPrefix("headscale")
 | 
				
			||||||
	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
 | 
						viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
 | 
				
			||||||
@ -377,11 +381,6 @@ func GetDNSConfig() (*tailcfg.DNSConfig, string) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetHeadscaleConfig() (*Config, error) {
 | 
					func GetHeadscaleConfig() (*Config, error) {
 | 
				
			||||||
	err := LoadConfig("")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dnsConfig, baseDomain := GetDNSConfig()
 | 
						dnsConfig, baseDomain := GetDNSConfig()
 | 
				
			||||||
	derpConfig := GetDERPConfig()
 | 
						derpConfig := GetDERPConfig()
 | 
				
			||||||
	logConfig := GetLogTailConfig()
 | 
						logConfig := GetLogTailConfig()
 | 
				
			||||||
 | 
				
			|||||||
@ -27,6 +27,7 @@ written by community members. It is _not_ verified by `headscale` developers.
 | 
				
			|||||||
**It might be outdated and it might miss necessary steps**.
 | 
					**It might be outdated and it might miss necessary steps**.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [Running headscale in a container](running-headscale-container.md)
 | 
					- [Running headscale in a container](running-headscale-container.md)
 | 
				
			||||||
 | 
					- [Running headscale on OpenBSD](running-headscale-openbsd.md)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Misc
 | 
					## Misc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										206
									
								
								docs/running-headscale-openbsd.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								docs/running-headscale-openbsd.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,206 @@
 | 
				
			|||||||
 | 
					# Running headscale on OpenBSD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Goal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This documentation has the goal of showing a user how-to install and run `headscale` on OpenBSD 7.1.
 | 
				
			||||||
 | 
					In additional to the "get up and running section", there is an optional [rc.d section](#running-headscale-in-the-background-with-rcd)
 | 
				
			||||||
 | 
					describing how to make `headscale` run properly in a server environment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Install `headscale`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Install from ports (Not Recommend)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   As of OpenBSD 7.1, there's a headscale in ports collection, however, it's severely outdated(v0.12.4).
 | 
				
			||||||
 | 
					   You can install it via `pkg_add headscale`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. Install from source on OpenBSD 7.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					# Install prerequistes
 | 
				
			||||||
 | 
					# 1. go v1.18+: headscale newer than 0.15 needs go 1.18+ to compile
 | 
				
			||||||
 | 
					# 2. gmake: Makefile in the headscale repo is written in GNU make syntax
 | 
				
			||||||
 | 
					pkg_add -D snap go
 | 
				
			||||||
 | 
					pkg_add gmake
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/juanfont/headscale.git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd headscale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# optionally checkout a release
 | 
				
			||||||
 | 
					# option a. you can find offical relase at https://github.com/juanfont/headscale/releases/latest
 | 
				
			||||||
 | 
					# option b. get latest tag, this may be a beta release
 | 
				
			||||||
 | 
					latestTag=$(git describe --tags `git rev-list --tags --max-count=1`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git checkout $latestTag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gmake build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make it executable
 | 
				
			||||||
 | 
					chmod a+x headscale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# copy it to /usr/local/sbin
 | 
				
			||||||
 | 
					cp headscale /usr/local/sbin
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. Install from source via cross compile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					# Install prerequistes
 | 
				
			||||||
 | 
					# 1. go v1.18+: headscale newer than 0.15 needs go 1.18+ to compile
 | 
				
			||||||
 | 
					# 2. gmake: Makefile in the headscale repo is written in GNU make syntax
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/juanfont/headscale.git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd headscale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# optionally checkout a release
 | 
				
			||||||
 | 
					# option a. you can find offical relase at https://github.com/juanfont/headscale/releases/latest
 | 
				
			||||||
 | 
					# option b. get latest tag, this may be a beta release
 | 
				
			||||||
 | 
					latestTag=$(git describe --tags `git rev-list --tags --max-count=1`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git checkout $latestTag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					make build GOOS=openbsd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# copy headscale to openbsd machine and put it in /usr/local/sbin
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Configure and run `headscale`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Prepare a directory to hold `headscale` configuration and the [SQLite](https://www.sqlite.org/) database:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					# Directory for configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mkdir -p /etc/headscale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Directory for Database, and other variable data (like certificates)
 | 
				
			||||||
 | 
					mkdir -p /var/lib/headscale
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. Create an empty SQLite database:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					touch /var/lib/headscale/db.sqlite
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. Create a `headscale` configuration:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					touch /etc/headscale/config.yaml
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is **strongly recommended** to copy and modify the [example configuration](../config-example.yaml)
 | 
				
			||||||
 | 
					from the [headscale repository](../)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. Start the headscale server:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					headscale serve
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This command will start `headscale` in the current terminal session.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To continue the tutorial, open a new terminal and let it run in the background.
 | 
				
			||||||
 | 
					Alternatively use terminal emulators like [tmux](https://github.com/tmux/tmux).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To run `headscale` in the background, please follow the steps in the [rc.d section](#running-headscale-in-the-background-with-rcd) before continuing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					5. Verify `headscale` is running:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Verify `headscale` is available:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					curl http://127.0.0.1:9090/metrics
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					6. Create a namespace ([tailnet](https://tailscale.com/kb/1136/tailnet/)):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					headscale namespaces create myfirstnamespace
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Register a machine (normal login)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On a client machine, execute the `tailscale` login command:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					tailscale up --login-server YOUR_HEADSCALE_URL
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Register the machine:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					headscale --namespace myfirstnamespace nodes register --key <YOU_+MACHINE_KEY>
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Register machine using a pre authenticated key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generate a key using the command line:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					headscale --namespace myfirstnamespace preauthkeys create --reusable --expiration 24h
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This will return a pre-authenticated key that can be used to connect a node to `headscale` during the `tailscale` command:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					tailscale up --login-server <YOUR_HEADSCALE_URL> --authkey <YOUR_AUTH_KEY>
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Running `headscale` in the background with rc.d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This section demonstrates how to run `headscale` as a service in the background with [rc.d](https://man.openbsd.org/rc.d).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Create a rc.d service at `/etc/rc.d/headscale` containing:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					#!/bin/ksh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					daemon="/usr/local/sbin/headscale"
 | 
				
			||||||
 | 
					daemon_logger="daemon.info"
 | 
				
			||||||
 | 
					daemon_user="root"
 | 
				
			||||||
 | 
					daemon_flags="serve"
 | 
				
			||||||
 | 
					daemon_timeout=60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					. /etc/rc.d/rc.subr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rc_bg=YES
 | 
				
			||||||
 | 
					rc_reload=NO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rc_cmd $1
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. `/etc/rc.d/headscale` needs execute permission:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					chmod a+x /etc/rc.d/headscale
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. Start `headscale` service:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					rcctl start headscale
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. Make `headscale` service start at boot:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					rcctl enable headscale
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					5. Verify the headscale service:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					rcctl check headscale
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Verify `headscale` is available:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					curl http://127.0.0.1:9090/metrics
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`headscale` will now run in the background and start at boot.
 | 
				
			||||||
@ -1721,3 +1721,43 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	assert.Equal(s.T(), machine.Namespace, oldNamespace)
 | 
						assert.Equal(s.T(), machine.Namespace, oldNamespace)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *IntegrationCLITestSuite) TestLoadConfigFromCommand() {
 | 
				
			||||||
 | 
						// TODO: make sure defaultConfig is not same as altConfig
 | 
				
			||||||
 | 
						defaultConfig, err := os.ReadFile("integration_test/etc/config.dump.gold.yaml")
 | 
				
			||||||
 | 
						assert.Nil(s.T(), err)
 | 
				
			||||||
 | 
						altConfig, err := os.ReadFile("integration_test/etc/alt-config.dump.gold.yaml")
 | 
				
			||||||
 | 
						assert.Nil(s.T(), err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = ExecuteCommand(
 | 
				
			||||||
 | 
							&s.headscale,
 | 
				
			||||||
 | 
							[]string{
 | 
				
			||||||
 | 
								"headscale",
 | 
				
			||||||
 | 
								"dumpConfig",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[]string{},
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						assert.Nil(s.T(), err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defaultDumpConfig, err := os.ReadFile("integration_test/etc/config.dump.yaml")
 | 
				
			||||||
 | 
						assert.Nil(s.T(), err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert.YAMLEq(s.T(), string(defaultConfig), string(defaultDumpConfig))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = ExecuteCommand(
 | 
				
			||||||
 | 
							&s.headscale,
 | 
				
			||||||
 | 
							[]string{
 | 
				
			||||||
 | 
								"headscale",
 | 
				
			||||||
 | 
								"-c",
 | 
				
			||||||
 | 
								"/etc/headscale/alt-config.yaml",
 | 
				
			||||||
 | 
								"dumpConfig",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[]string{},
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						assert.Nil(s.T(), err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						altDumpConfig, err := os.ReadFile("integration_test/etc/config.dump.yaml")
 | 
				
			||||||
 | 
						assert.Nil(s.T(), err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert.YAMLEq(s.T(), string(altConfig), string(altDumpConfig))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										46
									
								
								integration_test/etc/alt-config.dump.gold.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								integration_test/etc/alt-config.dump.gold.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					acl_policy_path: ""
 | 
				
			||||||
 | 
					cli:
 | 
				
			||||||
 | 
					  insecure: false
 | 
				
			||||||
 | 
					  timeout: 5s
 | 
				
			||||||
 | 
					db_path: /tmp/integration_test_db.sqlite3
 | 
				
			||||||
 | 
					db_type: sqlite3
 | 
				
			||||||
 | 
					derp:
 | 
				
			||||||
 | 
					  auto_update_enabled: false
 | 
				
			||||||
 | 
					  server:
 | 
				
			||||||
 | 
					    enabled: false
 | 
				
			||||||
 | 
					    stun:
 | 
				
			||||||
 | 
					      enabled: true
 | 
				
			||||||
 | 
					  update_frequency: 1m
 | 
				
			||||||
 | 
					  urls:
 | 
				
			||||||
 | 
					    - https://controlplane.tailscale.com/derpmap/default
 | 
				
			||||||
 | 
					dns_config:
 | 
				
			||||||
 | 
					  base_domain: headscale.net
 | 
				
			||||||
 | 
					  domains: []
 | 
				
			||||||
 | 
					  magic_dns: true
 | 
				
			||||||
 | 
					  nameservers:
 | 
				
			||||||
 | 
					    - 1.1.1.1
 | 
				
			||||||
 | 
					ephemeral_node_inactivity_timeout: 30m
 | 
				
			||||||
 | 
					grpc_allow_insecure: false
 | 
				
			||||||
 | 
					grpc_listen_addr: :50443
 | 
				
			||||||
 | 
					ip_prefixes:
 | 
				
			||||||
 | 
					  - fd7a:115c:a1e0::/48
 | 
				
			||||||
 | 
					  - 100.64.0.0/10
 | 
				
			||||||
 | 
					listen_addr: 0.0.0.0:18080
 | 
				
			||||||
 | 
					log_level: disabled
 | 
				
			||||||
 | 
					logtail:
 | 
				
			||||||
 | 
					  enabled: false
 | 
				
			||||||
 | 
					metrics_listen_addr: 127.0.0.1:19090
 | 
				
			||||||
 | 
					oidc:
 | 
				
			||||||
 | 
					  scope:
 | 
				
			||||||
 | 
					    - openid
 | 
				
			||||||
 | 
					    - profile
 | 
				
			||||||
 | 
					    - email
 | 
				
			||||||
 | 
					  strip_email_domain: true
 | 
				
			||||||
 | 
					private_key_path: private.key
 | 
				
			||||||
 | 
					server_url: http://headscale:18080
 | 
				
			||||||
 | 
					tls_client_auth_mode: relaxed
 | 
				
			||||||
 | 
					tls_letsencrypt_cache_dir: /var/www/.cache
 | 
				
			||||||
 | 
					tls_letsencrypt_challenge_type: HTTP-01
 | 
				
			||||||
 | 
					unix_socket: /var/run/headscale.sock
 | 
				
			||||||
 | 
					unix_socket_permission: "0o770"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										24
									
								
								integration_test/etc/alt-config.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								integration_test/etc/alt-config.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					log_level: trace
 | 
				
			||||||
 | 
					acl_policy_path: ""
 | 
				
			||||||
 | 
					db_type: sqlite3
 | 
				
			||||||
 | 
					ephemeral_node_inactivity_timeout: 30m
 | 
				
			||||||
 | 
					ip_prefixes:
 | 
				
			||||||
 | 
					  - fd7a:115c:a1e0::/48
 | 
				
			||||||
 | 
					  - 100.64.0.0/10
 | 
				
			||||||
 | 
					dns_config:
 | 
				
			||||||
 | 
					  base_domain: headscale.net
 | 
				
			||||||
 | 
					  magic_dns: true
 | 
				
			||||||
 | 
					  domains: []
 | 
				
			||||||
 | 
					  nameservers:
 | 
				
			||||||
 | 
					    - 1.1.1.1
 | 
				
			||||||
 | 
					db_path: /tmp/integration_test_db.sqlite3
 | 
				
			||||||
 | 
					private_key_path: private.key
 | 
				
			||||||
 | 
					listen_addr: 0.0.0.0:18080
 | 
				
			||||||
 | 
					metrics_listen_addr: 127.0.0.1:19090
 | 
				
			||||||
 | 
					server_url: http://headscale:18080
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					derp:
 | 
				
			||||||
 | 
					  urls:
 | 
				
			||||||
 | 
					    - https://controlplane.tailscale.com/derpmap/default
 | 
				
			||||||
 | 
					  auto_update_enabled: false
 | 
				
			||||||
 | 
					  update_frequency: 1m
 | 
				
			||||||
							
								
								
									
										46
									
								
								integration_test/etc/config.dump.gold.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								integration_test/etc/config.dump.gold.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					acl_policy_path: ""
 | 
				
			||||||
 | 
					cli:
 | 
				
			||||||
 | 
					  insecure: false
 | 
				
			||||||
 | 
					  timeout: 5s
 | 
				
			||||||
 | 
					db_path: /tmp/integration_test_db.sqlite3
 | 
				
			||||||
 | 
					db_type: sqlite3
 | 
				
			||||||
 | 
					derp:
 | 
				
			||||||
 | 
					  auto_update_enabled: false
 | 
				
			||||||
 | 
					  server:
 | 
				
			||||||
 | 
					    enabled: false
 | 
				
			||||||
 | 
					    stun:
 | 
				
			||||||
 | 
					      enabled: true
 | 
				
			||||||
 | 
					  update_frequency: 1m
 | 
				
			||||||
 | 
					  urls:
 | 
				
			||||||
 | 
					    - https://controlplane.tailscale.com/derpmap/default
 | 
				
			||||||
 | 
					dns_config:
 | 
				
			||||||
 | 
					  base_domain: headscale.net
 | 
				
			||||||
 | 
					  domains: []
 | 
				
			||||||
 | 
					  magic_dns: true
 | 
				
			||||||
 | 
					  nameservers:
 | 
				
			||||||
 | 
					    - 1.1.1.1
 | 
				
			||||||
 | 
					ephemeral_node_inactivity_timeout: 30m
 | 
				
			||||||
 | 
					grpc_allow_insecure: false
 | 
				
			||||||
 | 
					grpc_listen_addr: :50443
 | 
				
			||||||
 | 
					ip_prefixes:
 | 
				
			||||||
 | 
					  - fd7a:115c:a1e0::/48
 | 
				
			||||||
 | 
					  - 100.64.0.0/10
 | 
				
			||||||
 | 
					listen_addr: 0.0.0.0:8080
 | 
				
			||||||
 | 
					log_level: disabled
 | 
				
			||||||
 | 
					logtail:
 | 
				
			||||||
 | 
					  enabled: false
 | 
				
			||||||
 | 
					metrics_listen_addr: 127.0.0.1:9090
 | 
				
			||||||
 | 
					oidc:
 | 
				
			||||||
 | 
					  scope:
 | 
				
			||||||
 | 
					    - openid
 | 
				
			||||||
 | 
					    - profile
 | 
				
			||||||
 | 
					    - email
 | 
				
			||||||
 | 
					  strip_email_domain: true
 | 
				
			||||||
 | 
					private_key_path: private.key
 | 
				
			||||||
 | 
					server_url: http://headscale:8080
 | 
				
			||||||
 | 
					tls_client_auth_mode: relaxed
 | 
				
			||||||
 | 
					tls_letsencrypt_cache_dir: /var/www/.cache
 | 
				
			||||||
 | 
					tls_letsencrypt_challenge_type: HTTP-01
 | 
				
			||||||
 | 
					unix_socket: /var/run/headscale.sock
 | 
				
			||||||
 | 
					unix_socket_permission: "0o770"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -148,6 +148,21 @@ func (h *Headscale) ListNamespaces() ([]Namespace, error) {
 | 
				
			|||||||
	return namespaces, nil
 | 
						return namespaces, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *Headscale) ListNamespacesStr() ([]string, error) {
 | 
				
			||||||
 | 
						namespaces, err := h.ListNamespaces()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return []string{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						namespaceStrs := make([]string, len(namespaces))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for index, namespace := range namespaces {
 | 
				
			||||||
 | 
							namespaceStrs[index] = namespace.Name
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return namespaceStrs, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ListMachinesInNamespace gets all the nodes in a given namespace.
 | 
					// ListMachinesInNamespace gets all the nodes in a given namespace.
 | 
				
			||||||
func (h *Headscale) ListMachinesInNamespace(name string) ([]Machine, error) {
 | 
					func (h *Headscale) ListMachinesInNamespace(name string) ([]Machine, error) {
 | 
				
			||||||
	err := CheckForFQDNRules(name)
 | 
						err := CheckForFQDNRules(name)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user