From 52f372cdbe1272b76661f399b9d1dca5d3913fb0 Mon Sep 17 00:00:00 2001 From: Juan Font Date: Mon, 19 Jul 2021 19:42:42 +0200 Subject: [PATCH] Added init command to generate a working env --- app.go | 4 ++ cmd/headscale/cli/init.go | 75 ++++++++++++++++++++++++++++++++++++++ cmd/headscale/headscale.go | 7 +++- 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 cmd/headscale/cli/init.go diff --git a/app.go b/app.go index de6e8e6c..da2769dd 100644 --- a/app.go +++ b/app.go @@ -1,6 +1,7 @@ package headscale import ( + _ "embed" "errors" "fmt" "log" @@ -17,6 +18,9 @@ import ( "tailscale.com/types/wgkey" ) +//go:embed derp.yaml +var BaseDerp string + // Config contains the initial Headscale configuration type Config struct { ServerURL string diff --git a/cmd/headscale/cli/init.go b/cmd/headscale/cli/init.go new file mode 100644 index 00000000..01c4780e --- /dev/null +++ b/cmd/headscale/cli/init.go @@ -0,0 +1,75 @@ +package cli + +import ( + "fmt" + "log" + "os" + + "github.com/juanfont/headscale" + "github.com/spf13/cobra" + "tailscale.com/types/wgkey" +) + +var InitCmd = &cobra.Command{ + Use: "init", + Short: "Creates a basic Headscale env", +} + +var InitSqliteCmd = &cobra.Command{ + Use: "sqlite", + Short: "Creates a headscale env using SQLite as database", + Run: func(cmd *cobra.Command, args []string) { + force, _ := cmd.Flags().GetBool("force") + if !force { + if _, err := os.Stat("config.json"); err == nil { + fmt.Println("config.json already exists") + return + } + if _, err := os.Stat("private.key"); err == nil { + fmt.Println("private.key already exists") + return + } + if _, err := os.Stat("derp.yaml"); err == nil { + fmt.Println("derp.yaml already exists") + return + } + } + + fmt.Println("Creating config.json") + cfg := `{ + "server_url": "http://127.0.0.1:8000", + "listen_addr": "0.0.0.0:8000", + "private_key_path": "private.key", + "derp_map_path": "derp.yaml", + "ephemeral_node_inactivity_timeout": "30m", + "db_type": "sqlite3", + "db_path": "db.sqlite", + "tls_letsencrypt_hostname": "", + "tls_letsencrypt_cache_dir": ".cache", + "tls_letsencrypt_challenge_type": "HTTP-01", + "tls_cert_path": "", + "tls_key_path": "", + "acl_policy_path": "" + }` + err := os.WriteFile("config.json", []byte(cfg), 0644) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Generate the Wireguard private.key") + privk, err := wgkey.NewPrivate() + if err != nil { + log.Fatal(err) + } + err = os.WriteFile("private.key", []byte(privk.String()), 0644) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Writing basic derp.yaml") + err = os.WriteFile("derp.yaml", []byte(headscale.BaseDerp), 0644) + if err != nil { + log.Fatal(err) + } + }, +} diff --git a/cmd/headscale/headscale.go b/cmd/headscale/headscale.go index 195cec00..26f563e0 100644 --- a/cmd/headscale/headscale.go +++ b/cmd/headscale/headscale.go @@ -39,9 +39,10 @@ https://gitlab.com/juanfont/headscale`, func main() { err := cli.LoadConfig("") if err != nil { - log.Fatalf(err.Error()) + log.Printf("Warning: could not load config %s", err) } + headscaleCmd.AddCommand(cli.InitCmd) headscaleCmd.AddCommand(cli.NamespaceCmd) headscaleCmd.AddCommand(cli.NodeCmd) headscaleCmd.AddCommand(cli.PreauthkeysCmd) @@ -67,6 +68,8 @@ func main() { log.Fatalf(err.Error()) } + cli.InitCmd.AddCommand(cli.InitSqliteCmd) + cli.NamespaceCmd.AddCommand(cli.CreateNamespaceCmd) cli.NamespaceCmd.AddCommand(cli.ListNamespacesCmd) cli.NamespaceCmd.AddCommand(cli.DestroyNamespaceCmd) @@ -81,6 +84,8 @@ func main() { cli.PreauthkeysCmd.AddCommand(cli.ListPreAuthKeys) cli.PreauthkeysCmd.AddCommand(cli.CreatePreAuthKeyCmd) + cli.InitSqliteCmd.PersistentFlags().Bool("force", false, "Overwrite existing files if any") + cli.CreatePreAuthKeyCmd.PersistentFlags().Bool("reusable", false, "Make the preauthkey reusable") cli.CreatePreAuthKeyCmd.PersistentFlags().Bool("ephemeral", false, "Preauthkey for ephemeral nodes") cli.CreatePreAuthKeyCmd.Flags().StringP("expiration", "e", "", "Human-readable expiration of the key (30m, 24h, 365d...)")