apply.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package cmd
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "path/filepath"
  6. "github.com/mitchellh/mapstructure"
  7. api "github.com/porter-dev/porter/api/client"
  8. "github.com/porter-dev/porter/api/types"
  9. "github.com/porter-dev/switchboard/pkg/drivers"
  10. "github.com/porter-dev/switchboard/pkg/models"
  11. "github.com/porter-dev/switchboard/pkg/parser"
  12. switchboardTypes "github.com/porter-dev/switchboard/pkg/types"
  13. "github.com/porter-dev/switchboard/pkg/worker"
  14. "github.com/rs/zerolog"
  15. "github.com/spf13/cobra"
  16. )
  17. // applyCmd represents the "porter apply" base command when called
  18. // with a porter.yaml file as an argument
  19. var applyCmd = &cobra.Command{
  20. Use: "apply",
  21. Short: "Applies the provided porter.yaml to a project",
  22. Run: func(cmd *cobra.Command, args []string) {
  23. err := checkLoginAndRun(args, apply)
  24. if err != nil {
  25. os.Exit(1)
  26. }
  27. },
  28. }
  29. var porterYAML string
  30. func init() {
  31. rootCmd.AddCommand(applyCmd)
  32. applyCmd.Flags().StringVarP(&porterYAML, "file", "f", "", "path to porter.yaml")
  33. applyCmd.MarkFlagRequired("file")
  34. }
  35. func apply(_ *types.GetAuthenticatedUserResponse, client *api.Client, args []string) error {
  36. fileBytes, err := ioutil.ReadFile(porterYAML)
  37. if err != nil {
  38. return err
  39. }
  40. resGroup, err := parser.ParseRawBytes(fileBytes)
  41. if err != nil {
  42. return err
  43. }
  44. basePath, err := os.Getwd()
  45. if err != nil {
  46. return err
  47. }
  48. worker := worker.NewWorker()
  49. worker.RegisterDriver("", NewPorterDriver) // FIXME: workaround for when driver is not present
  50. worker.RegisterDriver("porter.deploy", NewPorterDriver)
  51. return worker.Apply(resGroup, &switchboardTypes.ApplyOpts{
  52. BasePath: basePath,
  53. })
  54. }
  55. type Source struct {
  56. Name string
  57. Repo string
  58. Version string
  59. }
  60. type Target struct {
  61. Project uint
  62. Cluster uint
  63. Namespace string
  64. }
  65. type Config struct {
  66. Build struct {
  67. Method string
  68. Context string
  69. }
  70. Values map[string]interface{}
  71. }
  72. type Driver struct {
  73. source *Source
  74. target *Target
  75. config *Config
  76. output map[string]interface{}
  77. lookupTable *map[string]drivers.Driver
  78. logger *zerolog.Logger
  79. }
  80. func NewPorterDriver(resource *models.Resource, opts *drivers.SharedDriverOpts) (drivers.Driver, error) {
  81. driver := &Driver{
  82. lookupTable: opts.DriverLookupTable,
  83. logger: opts.Logger,
  84. }
  85. if resource.Source != nil {
  86. source, err := getSource(resource.Source)
  87. if err != nil {
  88. return nil, err
  89. }
  90. driver.source = source
  91. } else {
  92. // default source
  93. driver.source = &Source{
  94. Name: "web",
  95. Repo: "https://charts.getporter.dev",
  96. Version: "v0.13.0",
  97. }
  98. }
  99. if resource.Target != nil {
  100. target, err := getTarget(resource.Target)
  101. if err != nil {
  102. return nil, err
  103. }
  104. driver.target = target
  105. } else {
  106. // default target
  107. driver.target = &Target{
  108. Project: config.Project,
  109. Cluster: config.Cluster,
  110. Namespace: "default",
  111. }
  112. }
  113. if resource.Config != nil {
  114. config, err := getConfig(resource.Config)
  115. if err != nil {
  116. return nil, err
  117. }
  118. driver.config = config
  119. }
  120. return driver, nil
  121. }
  122. func (d *Driver) ShouldApply(resource *models.Resource) bool {
  123. return true
  124. }
  125. func (d *Driver) Apply(resource *models.Resource) (*models.Resource, error) {
  126. // TODO: use source.repo, source.version, config.values
  127. name = resource.Name
  128. source = "local"
  129. namespace = d.target.Namespace
  130. if d.config != nil {
  131. method = d.config.Build.Method
  132. absPath, err := filepath.Abs(d.config.Build.Context)
  133. if err != nil {
  134. return nil, err
  135. }
  136. localPath = absPath
  137. }
  138. config.SetProject(d.target.Project)
  139. config.SetCluster(d.target.Cluster)
  140. err := createFull(nil, GetAPIClient(config), []string{d.source.Name})
  141. if err != nil {
  142. return nil, err
  143. }
  144. return resource, nil
  145. }
  146. func (d *Driver) Output() (map[string]interface{}, error) {
  147. return d.output, nil
  148. }
  149. func getSource(genericSource map[string]interface{}) (*Source, error) {
  150. source := &Source{}
  151. err := mapstructure.Decode(genericSource, source)
  152. if err != nil {
  153. return nil, err
  154. }
  155. return source, nil
  156. }
  157. func getTarget(genericTarget map[string]interface{}) (*Target, error) {
  158. target := &Target{}
  159. err := mapstructure.Decode(genericTarget, target)
  160. if err != nil {
  161. return nil, err
  162. }
  163. return target, nil
  164. }
  165. func getConfig(genericConfig map[string]interface{}) (*Config, error) {
  166. config := &Config{}
  167. err := mapstructure.Decode(genericConfig, config)
  168. if err != nil {
  169. return nil, err
  170. }
  171. return config, nil
  172. }