config.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package commands
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "os"
  7. "path/filepath"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "github.com/briandowns/spinner"
  12. "github.com/fatih/color"
  13. api "github.com/porter-dev/porter/api/client"
  14. "github.com/porter-dev/porter/api/types"
  15. "github.com/porter-dev/porter/cli/cmd/config"
  16. "github.com/porter-dev/porter/cli/cmd/utils"
  17. "github.com/spf13/cobra"
  18. )
  19. // func registerCommand_Config() *cobra.Command {
  20. func registerCommand_Config() *cobra.Command {
  21. configCmd := &cobra.Command{
  22. Use: "config",
  23. Short: "Commands that control local configuration settings",
  24. Run: func(cmd *cobra.Command, args []string) {
  25. if err := printConfig(); err != nil {
  26. _, _ = color.New(color.FgRed).Fprintf(os.Stderr, "An error occurred: %v\n", err)
  27. os.Exit(1)
  28. }
  29. },
  30. }
  31. configSetProjectCmd := &cobra.Command{
  32. Use: "set-project [id]",
  33. Args: cobra.MaximumNArgs(1),
  34. Short: "Saves the project id in the default configuration",
  35. RunE: func(cmd *cobra.Command, args []string) error {
  36. if len(args) == 0 {
  37. err := checkLoginAndRunWithConfig(cmd, args, listAndSetProject)
  38. if err != nil {
  39. if errors.Is(err, errCreatingPorterAPIClient) {
  40. return errors.New("error creating porter API client. Please ensure you are logged in")
  41. }
  42. return fmt.Errorf("error checking login and setting project: %w", err)
  43. }
  44. return nil
  45. }
  46. err := checkLoginAndRunWithConfig(cmd, args, setProjectAndCluster)
  47. if err != nil {
  48. if errors.Is(err, errCreatingPorterAPIClient) {
  49. return errors.New("error creating porter API client. Please ensure you are logged in")
  50. }
  51. return fmt.Errorf("error checking login and setting project with cluster: %w", err)
  52. }
  53. return nil
  54. },
  55. }
  56. configSetClusterCmd := &cobra.Command{
  57. Use: "set-cluster [id]",
  58. Args: cobra.MaximumNArgs(1),
  59. Short: "Saves the cluster id in the default configuration",
  60. RunE: func(cmd *cobra.Command, args []string) error {
  61. if len(args) == 0 {
  62. err := checkLoginAndRunWithConfig(cmd, args, listAndSetCluster)
  63. if err != nil {
  64. if errors.Is(err, errCreatingPorterAPIClient) {
  65. return errors.New("error creating porter API client. Please ensure you are logged in")
  66. }
  67. return fmt.Errorf("error checking login and setting project: %w", err)
  68. }
  69. return nil
  70. }
  71. _, currentProfile, err := currentProfileIncludingFlags(cmd)
  72. if err != nil {
  73. return fmt.Errorf("error whilst initialising config: %w", err)
  74. }
  75. clusterID, err := strconv.ParseUint(args[0], 10, 64)
  76. if err != nil {
  77. _, _ = color.New(color.FgRed).Fprintf(os.Stderr, "An error occurred: %v\n", err)
  78. os.Exit(1)
  79. }
  80. err = config.SetCluster(uint(clusterID), currentProfile)
  81. if err != nil {
  82. _, _ = color.New(color.FgRed).Fprintf(os.Stderr, "An error occurred: %v\n", err)
  83. os.Exit(1)
  84. }
  85. return nil
  86. },
  87. }
  88. configSetRegistryCmd := &cobra.Command{
  89. Use: "set-registry [id]",
  90. Args: cobra.MaximumNArgs(1),
  91. Short: "Saves the registry id in the default configuration",
  92. Run: func(cmd *cobra.Command, args []string) {
  93. if len(args) == 0 {
  94. err := checkLoginAndRunWithConfig(cmd, args, listAndSetRegistry)
  95. if err != nil {
  96. os.Exit(1)
  97. }
  98. } else {
  99. registryID, err := strconv.ParseUint(args[0], 10, 64)
  100. if err != nil {
  101. _, _ = color.New(color.FgRed).Fprintf(os.Stderr, "An error occurred: %v\n", err)
  102. os.Exit(1)
  103. }
  104. err = config.SetRegistry(uint(registryID))
  105. if err != nil {
  106. _, _ = color.New(color.FgRed).Fprintf(os.Stderr, "An error occurred: %v\n", err)
  107. os.Exit(1)
  108. }
  109. }
  110. },
  111. }
  112. configSetHelmRepoCmd := &cobra.Command{
  113. Use: "set-helmrepo [id]",
  114. Args: cobra.ExactArgs(1),
  115. Short: "Saves the helm repo id in the default configuration",
  116. Run: func(cmd *cobra.Command, args []string) {
  117. hrID, err := strconv.ParseUint(args[0], 10, 64)
  118. if err != nil {
  119. _, _ = color.New(color.FgRed).Fprintf(os.Stderr, "An error occurred: %v\n", err)
  120. os.Exit(1)
  121. }
  122. err = config.SetHelmRepo(uint(hrID))
  123. if err != nil {
  124. _, _ = color.New(color.FgRed).Fprintf(os.Stderr, "An error occurred: %v\n", err)
  125. os.Exit(1)
  126. }
  127. },
  128. }
  129. configSetHostCmd := &cobra.Command{
  130. Use: "set-host [host]",
  131. Args: cobra.ExactArgs(1),
  132. Short: "Saves the host in the default configuration",
  133. RunE: func(cmd *cobra.Command, args []string) error {
  134. _, currentProfile, err := currentProfileIncludingFlags(cmd)
  135. if err != nil {
  136. return fmt.Errorf("error whilst initialising config: %w", err)
  137. }
  138. err = config.SetHost(args[0], currentProfile)
  139. if err != nil {
  140. _, _ = color.New(color.FgRed).Fprintf(os.Stderr, "An error occurred: %s\n", err.Error())
  141. return err
  142. }
  143. return nil
  144. },
  145. }
  146. configSetKubeconfigCmd := &cobra.Command{
  147. Use: "set-kubeconfig [kubeconfig-path]",
  148. Args: cobra.ExactArgs(1),
  149. Short: "Saves the path to kubeconfig in the default configuration",
  150. Run: func(cmd *cobra.Command, args []string) {
  151. err := config.SetKubeconfig(args[0])
  152. if err != nil {
  153. _, _ = color.New(color.FgRed).Fprintf(os.Stderr, "An error occurred: %s\n", err.Error())
  154. os.Exit(1)
  155. }
  156. },
  157. }
  158. configSetProfileCmd := &cobra.Command{
  159. Use: "set-profile [profile-name]",
  160. Args: cobra.ExactArgs(1),
  161. Short: "Saves the path to kubeconfig in the default configuration",
  162. RunE: func(cmd *cobra.Command, args []string) error {
  163. return config.SetProfile(args[0])
  164. },
  165. }
  166. configCmd.AddCommand(configSetProjectCmd)
  167. configCmd.AddCommand(configSetClusterCmd)
  168. configCmd.AddCommand(configSetHostCmd)
  169. configCmd.AddCommand(configSetRegistryCmd)
  170. configCmd.AddCommand(configSetHelmRepoCmd)
  171. configCmd.AddCommand(configSetKubeconfigCmd)
  172. configCmd.AddCommand(configSetProfileCmd)
  173. return configCmd
  174. }
  175. func printConfig() error {
  176. config, err := os.ReadFile(filepath.Join(home, ".porter", "porter.yaml"))
  177. if err != nil {
  178. return err
  179. }
  180. fmt.Println(string(config))
  181. return nil
  182. }
  183. func listAndSetProject(ctx context.Context, _ *types.GetAuthenticatedUserResponse, client api.Client, cliConf config.CLIConfig, currentProfile string, featureFlags config.FeatureFlags, cmd *cobra.Command, args []string) error {
  184. s := spinner.New(spinner.CharSets[9], 100*time.Millisecond)
  185. _ = s.Color("cyan")
  186. s.Suffix = " Loading list of projects"
  187. s.Start()
  188. resp, err := client.ListUserProjects(ctx)
  189. if err != nil {
  190. return fmt.Errorf("error listing projects to set config: %w", err)
  191. }
  192. s.Stop()
  193. var projID uint64
  194. if len(*resp) > 1 {
  195. // only give the option to select when more than one option exists
  196. projName, err := utils.PromptSelect("Select a project with ID", func() []string {
  197. var names []string
  198. for _, proj := range *resp {
  199. names = append(names, fmt.Sprintf("%s - %d", proj.Name, proj.ID))
  200. }
  201. return names
  202. }())
  203. if err != nil {
  204. return err
  205. }
  206. projID, _ = strconv.ParseUint(strings.Split(projName, " - ")[1], 10, 64)
  207. } else {
  208. projID = uint64((*resp)[0].ID)
  209. }
  210. err = config.SetProject(uint(projID), currentProfile)
  211. if err != nil {
  212. return err
  213. }
  214. return nil
  215. }
  216. func setProjectAndCluster(ctx context.Context, _ *types.GetAuthenticatedUserResponse, client api.Client, cliConf config.CLIConfig, currentProfile string, featureFlags config.FeatureFlags, cmd *cobra.Command, args []string) error {
  217. projID, err := strconv.ParseUint(args[0], 10, 64)
  218. if err != nil {
  219. return fmt.Errorf("error parsing project id: %w", err)
  220. }
  221. err = config.SetProject(uint(projID), currentProfile)
  222. if err != nil {
  223. return fmt.Errorf("error setting project: %w", err)
  224. }
  225. err = listAndSetProject(ctx, nil, client, cliConf, currentProfile, featureFlags, cmd, args)
  226. if err != nil {
  227. return err
  228. }
  229. err = listAndSetCluster(ctx, nil, client, cliConf, currentProfile, featureFlags, cmd, args)
  230. if err != nil {
  231. return err
  232. }
  233. return nil
  234. }
  235. func listAndSetCluster(ctx context.Context, _ *types.GetAuthenticatedUserResponse, client api.Client, cliConf config.CLIConfig, currentProfile string, featureFlags config.FeatureFlags, cmd *cobra.Command, args []string) error {
  236. s := spinner.New(spinner.CharSets[9], 100*time.Millisecond)
  237. _ = s.Color("cyan")
  238. s.Suffix = " Loading list of clusters"
  239. s.Start()
  240. resp, err := client.ListProjectClusters(ctx, cliConf.Project)
  241. if err != nil {
  242. return err
  243. }
  244. s.Stop()
  245. var clusterID uint64
  246. if len(*resp) > 1 {
  247. clusterName, err := utils.PromptSelect("Select a cluster with ID", func() []string {
  248. var names []string
  249. for _, cluster := range *resp {
  250. names = append(names, fmt.Sprintf("%s - %d", cluster.Name, cluster.ID))
  251. }
  252. return names
  253. }())
  254. if err != nil {
  255. return err
  256. }
  257. clusterID, _ = strconv.ParseUint(strings.Split(clusterName, " - ")[1], 10, 64)
  258. } else {
  259. clusterID = uint64((*resp)[0].ID)
  260. }
  261. err = config.SetCluster(uint(clusterID), currentProfile)
  262. if err != nil {
  263. return fmt.Errorf("unable to set cluster: %w", err)
  264. }
  265. return nil
  266. }
  267. func listAndSetRegistry(ctx context.Context, _ *types.GetAuthenticatedUserResponse, client api.Client, cliConf config.CLIConfig, currentProfile string, featureFlags config.FeatureFlags, cmd *cobra.Command, args []string) error {
  268. s := spinner.New(spinner.CharSets[9], 100*time.Millisecond)
  269. _ = s.Color("cyan")
  270. s.Suffix = " Loading list of registries"
  271. s.Start()
  272. resp, err := client.ListRegistries(ctx, cliConf.Project)
  273. s.Stop()
  274. if err != nil {
  275. return err
  276. }
  277. var regID uint64
  278. if len(*resp) > 1 {
  279. regName, err := utils.PromptSelect("Select a registry with ID", func() []string {
  280. var names []string
  281. for _, cluster := range *resp {
  282. names = append(names, fmt.Sprintf("%s - %d", cluster.Name, cluster.ID))
  283. }
  284. return names
  285. }())
  286. if err != nil {
  287. return err
  288. }
  289. regID, _ = strconv.ParseUint(strings.Split(regName, " - ")[1], 10, 64)
  290. } else {
  291. regID = uint64((*resp)[0].ID)
  292. }
  293. err = config.SetRegistry(uint(regID))
  294. if err != nil {
  295. return fmt.Errorf("error setting registry: %w", err)
  296. }
  297. return nil
  298. }