start.go 4.1 KB

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