start.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package cmd
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "path/filepath"
  7. "runtime"
  8. "time"
  9. "github.com/porter-dev/porter/cli/cmd/docker"
  10. "k8s.io/client-go/util/homedir"
  11. "github.com/porter-dev/porter/cli/cmd/credstore"
  12. "github.com/spf13/cobra"
  13. )
  14. type startOps struct {
  15. insecure *bool
  16. skipKubeconfig *bool
  17. kubeconfigPath string
  18. contexts *[]string
  19. imageTag string `form:"required"`
  20. db string `form:"oneof=sqlite postgres"`
  21. }
  22. var opts = &startOps{}
  23. // startCmd represents the start command
  24. var startCmd = &cobra.Command{
  25. Args: func(cmd *cobra.Command, args []string) error {
  26. return nil
  27. },
  28. Use: "start",
  29. Short: "Starts a Porter instance using the Docker engine.",
  30. Run: func(cmd *cobra.Command, args []string) {
  31. err := start(
  32. opts.imageTag,
  33. opts.kubeconfigPath,
  34. opts.db,
  35. *opts.contexts,
  36. *opts.insecure,
  37. *opts.skipKubeconfig,
  38. )
  39. if err != nil {
  40. fmt.Println("Error running start:", err.Error())
  41. fmt.Println("Shutting down...")
  42. err = stop()
  43. if err != nil {
  44. fmt.Println("Shutdown unsuccessful:", err.Error())
  45. }
  46. os.Exit(1)
  47. }
  48. },
  49. }
  50. func init() {
  51. rootCmd.AddCommand(startCmd)
  52. opts.insecure = startCmd.PersistentFlags().Bool(
  53. "insecure",
  54. false,
  55. "skip admin setup and authorization",
  56. )
  57. opts.skipKubeconfig = startCmd.PersistentFlags().Bool(
  58. "skip-kubeconfig",
  59. false,
  60. "skip initialization of the kubeconfig",
  61. )
  62. opts.contexts = startCmd.PersistentFlags().StringArray(
  63. "contexts",
  64. nil,
  65. "the list of contexts to use (defaults to the current context)",
  66. )
  67. startCmd.PersistentFlags().StringVar(
  68. &opts.db,
  69. "db",
  70. "sqlite",
  71. "the db to use, one of sqlite or postgres",
  72. )
  73. startCmd.PersistentFlags().StringVar(
  74. &opts.kubeconfigPath,
  75. "kubeconfig",
  76. "",
  77. "path to kubeconfig",
  78. )
  79. startCmd.PersistentFlags().StringVar(
  80. &opts.imageTag,
  81. "image-tag",
  82. "latest",
  83. "the Porter image tag to use",
  84. )
  85. }
  86. func stop() error {
  87. agent, err := docker.NewAgentFromEnv()
  88. if err != nil {
  89. return err
  90. }
  91. err = agent.StopPorterContainersWithProcessID("main", false)
  92. if err != nil {
  93. return err
  94. }
  95. return nil
  96. }
  97. func start(
  98. imageTag string,
  99. kubeconfigPath string,
  100. db string,
  101. contexts []string,
  102. insecure bool,
  103. skipKubeconfig bool,
  104. ) error {
  105. var username, pw string
  106. var err error
  107. home := homedir.HomeDir()
  108. outputConfPath := filepath.Join(home, ".porter", "porter.kubeconfig")
  109. // if not insecure, or username/pw set incorrectly, prompt for new username/pw
  110. if username, pw, err = credstore.Get(); !insecure && err != nil {
  111. fmt.Println("Please register your admin account with an email and password:")
  112. username, err = promptPlaintext("Email: ")
  113. if err != nil {
  114. return err
  115. }
  116. pw, err = promptPasswordWithConfirmation()
  117. if err != nil {
  118. return err
  119. }
  120. credstore.Set(username, pw)
  121. }
  122. if !skipKubeconfig {
  123. err = generate(
  124. kubeconfigPath,
  125. outputConfPath,
  126. false,
  127. contexts,
  128. )
  129. if err != nil {
  130. return err
  131. }
  132. }
  133. env := make([]string, 0)
  134. env = append(env, []string{
  135. "ADMIN_INIT=true",
  136. "ADMIN_EMAIL=" + username,
  137. "ADMIN_PASSWORD=" + pw,
  138. }...)
  139. var porterDB docker.PorterDB
  140. switch db {
  141. case "postgres":
  142. porterDB = docker.Postgres
  143. case "sqlite":
  144. porterDB = docker.SQLite
  145. }
  146. port := 8080
  147. startOpts := &docker.PorterStartOpts{
  148. ProcessID: "main",
  149. ServerImageTag: imageTag,
  150. ServerPort: port,
  151. DB: porterDB,
  152. KubeconfigPath: kubeconfigPath,
  153. SkipKubeconfig: skipKubeconfig,
  154. Env: env,
  155. }
  156. _, _, err = docker.StartPorter(startOpts)
  157. fmt.Println("Spinning up the server...")
  158. time.Sleep(7 * time.Second)
  159. openBrowser(fmt.Sprintf("http://localhost:%d/login?email=%s", port, username))
  160. fmt.Printf("Server ready: listening on localhost:%d\n", port)
  161. return nil
  162. }
  163. // openBrowser opens the specified URL in the default browser of the user.
  164. func openBrowser(url string) error {
  165. var cmd string
  166. var args []string
  167. switch runtime.GOOS {
  168. case "windows":
  169. cmd = "cmd"
  170. args = []string{"/c", "start"}
  171. case "darwin":
  172. cmd = "open"
  173. default: // "linux", "freebsd", "openbsd", "netbsd"
  174. cmd = "xdg-open"
  175. }
  176. args = append(args, url)
  177. return exec.Command(cmd, args...).Start()
  178. }