config.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. package config
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "path/filepath"
  6. "strings"
  7. "github.com/fatih/color"
  8. api "github.com/porter-dev/porter/api/client"
  9. "github.com/porter-dev/porter/cli/cmd/utils"
  10. "github.com/spf13/viper"
  11. "k8s.io/client-go/util/homedir"
  12. )
  13. var home = homedir.HomeDir()
  14. // config is a shared object used by all commands
  15. var config = &CLIConfig{}
  16. // CLIConfig is the set of shared configuration options for the CLI commands.
  17. // This config is used by viper: calling Set() function for any parameter will
  18. // update the corresponding field in the viper config file.
  19. type CLIConfig struct {
  20. // Driver can be either "docker" or "local", and represents which driver is
  21. // used to run an instance of the server.
  22. Driver string `yaml:"driver"`
  23. Host string `yaml:"host"`
  24. Project uint `yaml:"project"`
  25. Cluster uint `yaml:"cluster"`
  26. Token string `yaml:"token"`
  27. Registry uint `yaml:"registry"`
  28. HelmRepo uint `yaml:"helm_repo"`
  29. }
  30. // InitAndLoadConfig populates the config object with the following precedence rules:
  31. // 1. flag
  32. // 2. env
  33. // 3. config
  34. // 4. default
  35. //
  36. // It populates the shared config object above
  37. func InitAndLoadConfig() {
  38. initAndLoadConfig(config)
  39. }
  40. func InitAndLoadNewConfig() *CLIConfig {
  41. newConfig := &CLIConfig{}
  42. initAndLoadConfig(newConfig)
  43. return newConfig
  44. }
  45. func initAndLoadConfig(_config *CLIConfig) {
  46. initFlagSet()
  47. // check that the .porter folder exists; create if not
  48. porterDir := filepath.Join(home, ".porter")
  49. if _, err := os.Stat(porterDir); os.IsNotExist(err) {
  50. os.Mkdir(porterDir, 0700)
  51. } else if err != nil {
  52. color.New(color.FgRed).Printf("%v\n", err)
  53. os.Exit(1)
  54. }
  55. viper.SetConfigName("porter")
  56. viper.SetConfigType("yaml")
  57. viper.AddConfigPath(porterDir)
  58. // Bind the flagset initialized above
  59. viper.BindPFlags(utils.DriverFlagSet)
  60. viper.BindPFlags(utils.DefaultFlagSet)
  61. viper.BindPFlags(utils.RegistryFlagSet)
  62. viper.BindPFlags(utils.HelmRepoFlagSet)
  63. // Bind the environment variables with prefix "PORTER_"
  64. viper.SetEnvPrefix("PORTER")
  65. viper.BindEnv("host")
  66. viper.BindEnv("project")
  67. viper.BindEnv("cluster")
  68. viper.BindEnv("token")
  69. err := viper.ReadInConfig()
  70. if err != nil {
  71. if _, ok := err.(viper.ConfigFileNotFoundError); ok {
  72. // create blank config file
  73. err := ioutil.WriteFile(filepath.Join(home, ".porter", "porter.yaml"), []byte{}, 0644)
  74. if err != nil {
  75. color.New(color.FgRed).Printf("%v\n", err)
  76. os.Exit(1)
  77. }
  78. } else {
  79. // Config file was found but another error was produced
  80. color.New(color.FgRed).Printf("%v\n", err)
  81. os.Exit(1)
  82. }
  83. }
  84. // unmarshal the config into the shared config struct
  85. viper.Unmarshal(_config)
  86. }
  87. // initFlagSet initializes the shared flags used by multiple commands
  88. func initFlagSet() {
  89. utils.DriverFlagSet.StringVar(
  90. &config.Driver,
  91. "driver",
  92. "local",
  93. "driver to use (local or docker)",
  94. )
  95. utils.DefaultFlagSet.StringVar(
  96. &config.Host,
  97. "host",
  98. "https://dashboard.getporter.dev",
  99. "host URL of Porter instance",
  100. )
  101. utils.DefaultFlagSet.UintVar(
  102. &config.Project,
  103. "project",
  104. 0,
  105. "project ID of Porter project",
  106. )
  107. utils.DefaultFlagSet.UintVar(
  108. &config.Cluster,
  109. "cluster",
  110. 0,
  111. "cluster ID of Porter cluster",
  112. )
  113. utils.DefaultFlagSet.StringVar(
  114. &config.Token,
  115. "token",
  116. "",
  117. "token for Porter authentication",
  118. )
  119. utils.RegistryFlagSet.UintVar(
  120. &config.Registry,
  121. "registry",
  122. 0,
  123. "registry ID of connected Porter registry",
  124. )
  125. utils.HelmRepoFlagSet.UintVar(
  126. &config.HelmRepo,
  127. "helmrepo",
  128. 0,
  129. "helm repo ID of connected Porter Helm repository",
  130. )
  131. }
  132. func GetCLIConfig() *CLIConfig {
  133. if config == nil {
  134. panic("GetCLIConfig() called before initialisation")
  135. }
  136. return config
  137. }
  138. func GetAPIClient() *api.Client {
  139. config := GetCLIConfig()
  140. if token := config.Token; token != "" {
  141. return api.NewClientWithToken(config.Host+"/api", token)
  142. }
  143. return api.NewClient(config.Host+"/api", "cookie.json")
  144. }
  145. func (c *CLIConfig) SetDriver(driver string) error {
  146. viper.Set("driver", driver)
  147. color.New(color.FgGreen).Printf("Set the current driver as %s\n", driver)
  148. err := viper.WriteConfig()
  149. if err != nil {
  150. return err
  151. }
  152. config.Driver = driver
  153. return nil
  154. }
  155. func (c *CLIConfig) SetHost(host string) error {
  156. // a trailing / can lead to errors with the api server
  157. host = strings.TrimRight(host, "/")
  158. viper.Set("host", host)
  159. color.New(color.FgGreen).Printf("Set the current host as %s\n", host)
  160. err := viper.WriteConfig()
  161. if err != nil {
  162. return err
  163. }
  164. config.Host = host
  165. return nil
  166. }
  167. func (c *CLIConfig) SetProject(projectID uint) error {
  168. viper.Set("project", projectID)
  169. color.New(color.FgGreen).Printf("Set the current project as %d\n", projectID)
  170. err := viper.WriteConfig()
  171. if err != nil {
  172. return err
  173. }
  174. config.Project = projectID
  175. return nil
  176. }
  177. func (c *CLIConfig) SetCluster(clusterID uint) error {
  178. viper.Set("cluster", clusterID)
  179. color.New(color.FgGreen).Printf("Set the current cluster as %d\n", clusterID)
  180. err := viper.WriteConfig()
  181. if err != nil {
  182. return err
  183. }
  184. config.Cluster = clusterID
  185. return nil
  186. }
  187. func (c *CLIConfig) SetToken(token string) error {
  188. viper.Set("token", token)
  189. err := viper.WriteConfig()
  190. if err != nil {
  191. return err
  192. }
  193. config.Token = token
  194. return nil
  195. }
  196. func (c *CLIConfig) SetRegistry(registryID uint) error {
  197. viper.Set("registry", registryID)
  198. color.New(color.FgGreen).Printf("Set the current registry as %d\n", registryID)
  199. err := viper.WriteConfig()
  200. if err != nil {
  201. return err
  202. }
  203. config.Registry = registryID
  204. return nil
  205. }
  206. func (c *CLIConfig) SetHelmRepo(helmRepoID uint) error {
  207. viper.Set("helm_repo", helmRepoID)
  208. color.New(color.FgGreen).Printf("Set the current Helm repo as %d\n", helmRepoID)
  209. err := viper.WriteConfig()
  210. if err != nil {
  211. return err
  212. }
  213. config.HelmRepo = helmRepoID
  214. return nil
  215. }