github.com/grafana/tanka@v0.26.1-0.20240506093700-c22cfc35c21a/cmd/tk/init.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "os/exec" 8 "strconv" 9 10 "github.com/go-clix/cli" 11 12 "github.com/grafana/tanka/pkg/spec/v1alpha1" 13 ) 14 15 const defaultK8sVersion = "1.20" 16 17 // initCmd creates a new application 18 func initCmd() *cli.Command { 19 cmd := &cli.Command{ 20 Use: "init", 21 Short: "Create the directory structure", 22 Args: cli.ArgsNone(), 23 } 24 25 force := cmd.Flags().BoolP("force", "f", false, "ignore the working directory not being empty") 26 installK8s := cmd.Flags().String("k8s", defaultK8sVersion, "choose the version of k8s-libsonnet, set to false to skip") 27 inline := cmd.Flags().BoolP("inline", "i", false, "create an inline environment") 28 29 cmd.Run = func(cmd *cli.Command, args []string) error { 30 failed := false 31 32 files, err := os.ReadDir(".") 33 if err != nil { 34 return fmt.Errorf("error listing files: %s", err) 35 } 36 if len(files) > 0 && !*force { 37 return fmt.Errorf("error: directory not empty. Use `-f` to force") 38 } 39 40 if err := writeNewFile("jsonnetfile.json", "{}"); err != nil { 41 return fmt.Errorf("error creating `jsonnetfile.json`: %s", err) 42 } 43 44 if err := os.Mkdir("vendor", os.ModePerm); err != nil { 45 return fmt.Errorf("error creating `vendor/` folder: %s", err) 46 } 47 48 if err := os.Mkdir("lib", os.ModePerm); err != nil { 49 return fmt.Errorf("error creating `lib/` folder: %s", err) 50 } 51 52 cfg := v1alpha1.New() 53 if err := addEnv("environments/default", cfg, *inline); err != nil { 54 return err 55 } 56 57 version := *installK8s 58 doInstall, err := strconv.ParseBool(*installK8s) 59 if err != nil { 60 // --k8s=<non-boolean> 61 doInstall = true 62 } else { 63 // --k8s=<boolean>, fallback to default version 64 version = defaultK8sVersion 65 } 66 67 if doInstall { 68 if err := installK8sLib(version); err != nil { 69 // This is not fatal, as most of Tanka will work anyways 70 fmt.Println("Installing k.libsonnet:", err) 71 failed = true 72 } 73 } 74 75 if *inline { 76 fmt.Println("Directory structure set up! Remember to configure the API endpoint in environments/default/main.jsonnet") 77 } else { 78 fmt.Println("Directory structure set up! Remember to configure the API endpoint:\n`tk env set environments/default --server=https://127.0.0.1:6443`") 79 } 80 if failed { 81 fmt.Println("Errors occurred while initializing the project. Check the above logs for details.") 82 } 83 84 return nil 85 } 86 return cmd 87 } 88 89 func installK8sLib(version string) error { 90 jbBinary := "jb" 91 if env := os.Getenv("TANKA_JB_PATH"); env != "" { 92 jbBinary = env 93 } 94 95 if _, err := exec.LookPath(jbBinary); err != nil { 96 return errors.New("jsonnet-bundler not found in $PATH. Follow https://tanka.dev/install#jsonnet-bundler for installation instructions") 97 } 98 99 var initialPackages = []string{ 100 "github.com/jsonnet-libs/k8s-libsonnet/" + version + "@main", 101 "github.com/grafana/jsonnet-libs/ksonnet-util", 102 "github.com/jsonnet-libs/docsonnet/doc-util", // install docsonnet to make `tk lint` work 103 } 104 105 if err := writeNewFile("lib/k.libsonnet", "import 'github.com/jsonnet-libs/k8s-libsonnet/"+version+"/main.libsonnet'\n"); err != nil { 106 return err 107 } 108 109 cmd := exec.Command(jbBinary, append([]string{"install"}, initialPackages...)...) 110 cmd.Stdout = os.Stdout 111 cmd.Stderr = os.Stderr 112 113 return cmd.Run() 114 } 115 116 // writeNewFile writes the content to a file if it does not exist 117 func writeNewFile(name, content string) error { 118 if _, err := os.Stat(name); os.IsNotExist(err) { 119 return os.WriteFile(name, []byte(content), 0644) 120 } 121 return nil 122 }