update_config_driver.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. package preview
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "strings"
  7. "github.com/cli/cli/git"
  8. "github.com/fatih/color"
  9. "github.com/mitchellh/mapstructure"
  10. api "github.com/porter-dev/porter/api/client"
  11. "github.com/porter-dev/porter/cli/cmd/config"
  12. "github.com/porter-dev/porter/cli/cmd/deploy"
  13. "github.com/porter-dev/porter/cli/cmd/deploy/wait"
  14. cliUtils "github.com/porter-dev/porter/cli/cmd/utils"
  15. "github.com/porter-dev/porter/internal/integrations/preview"
  16. "github.com/porter-dev/porter/internal/templater/utils"
  17. "github.com/porter-dev/switchboard/pkg/drivers"
  18. "github.com/porter-dev/switchboard/pkg/models"
  19. )
  20. type UpdateConfigDriver struct {
  21. source *preview.Source
  22. target *preview.Target
  23. config *preview.UpdateConfigDriverConfig
  24. lookupTable *map[string]drivers.Driver
  25. output map[string]interface{}
  26. }
  27. func NewUpdateConfigDriver(resource *models.Resource, opts *drivers.SharedDriverOpts) (drivers.Driver, error) {
  28. driver := &UpdateConfigDriver{
  29. lookupTable: opts.DriverLookupTable,
  30. output: make(map[string]interface{}),
  31. }
  32. target, err := GetTarget(resource.Name, resource.Target)
  33. if err != nil {
  34. return nil, err
  35. }
  36. driver.target = target
  37. source, err := GetSource(driver.target.Project, resource.Name, resource.Source)
  38. if err != nil {
  39. return nil, err
  40. }
  41. driver.source = source
  42. return driver, nil
  43. }
  44. func (d *UpdateConfigDriver) ShouldApply(resource *models.Resource) bool {
  45. return true
  46. }
  47. func (d *UpdateConfigDriver) Apply(resource *models.Resource) (*models.Resource, error) {
  48. ctx := context.Background()
  49. updateConfigDriverConfig, err := d.getConfig(resource)
  50. if err != nil {
  51. return nil, err
  52. }
  53. d.config = updateConfigDriverConfig
  54. client := config.GetAPIClient()
  55. _, err = client.GetRelease(
  56. ctx,
  57. d.target.Project,
  58. d.target.Cluster,
  59. d.target.Namespace,
  60. d.target.AppName,
  61. )
  62. shouldCreate := err != nil
  63. color.New(color.FgBlue).Println("checking for the existence of PORTER_TAG environment variable for the image tag")
  64. tag := os.Getenv("PORTER_TAG")
  65. if tag == "" {
  66. color.New(color.FgBlue).Println("PORTER_TAG environment variable not found, checking for update_config.tag in porter.yaml for the image tag")
  67. tag = d.config.UpdateConfig.Tag
  68. }
  69. if tag == "" {
  70. color.New(color.FgBlue).Println("update_config.tag not found in porter.yaml, falling back to the latest git commit SHA as the image tag")
  71. commit, err := git.LastCommit()
  72. if err != nil {
  73. return nil, err
  74. }
  75. tag = commit.Sha[:7]
  76. }
  77. regList, err := client.ListRegistries(context.Background(), d.target.Project)
  78. if err != nil {
  79. return nil, err
  80. }
  81. var registryURL string
  82. if len(*regList) == 0 {
  83. return nil, fmt.Errorf("no registry found")
  84. } else {
  85. registryURL = (*regList)[0].URL
  86. }
  87. var repoSuffix string
  88. if repoName := os.Getenv("PORTER_REPO_NAME"); repoName != "" {
  89. if repoOwner := os.Getenv("PORTER_REPO_OWNER"); repoOwner != "" {
  90. repoSuffix = cliUtils.SlugifyRepoSuffix(repoOwner, repoName)
  91. }
  92. }
  93. sharedOpts := &deploy.SharedOpts{
  94. ProjectID: d.target.Project,
  95. ClusterID: d.target.Cluster,
  96. OverrideTag: tag,
  97. Namespace: d.target.Namespace,
  98. Method: "registry",
  99. EnvGroups: d.config.EnvGroups,
  100. }
  101. if shouldCreate {
  102. color.New(color.FgYellow).Printf("Could not read release %s/%s: attempting creation\n", d.target.Namespace, d.target.AppName)
  103. createAgent := &deploy.CreateAgent{
  104. Client: client,
  105. CreateOpts: &deploy.CreateOpts{
  106. SharedOpts: sharedOpts,
  107. Kind: d.source.Name,
  108. ReleaseName: d.target.AppName,
  109. RegistryURL: registryURL,
  110. RepoSuffix: repoSuffix,
  111. },
  112. }
  113. image := fmt.Sprintf("%s:%s", strings.Split(d.config.UpdateConfig.Image, ":")[0], tag)
  114. _, err = createAgent.CreateFromRegistry(image, d.config.Values)
  115. if err != nil {
  116. return nil, err
  117. }
  118. } else if !updateConfigDriverConfig.OnlyCreate {
  119. updateAgent, err := deploy.NewDeployAgent(client, d.target.AppName, &deploy.DeployOpts{
  120. SharedOpts: sharedOpts,
  121. Local: false,
  122. })
  123. if err != nil {
  124. return nil, err
  125. }
  126. err = updateAgent.UpdateImageAndValues(d.config.Values)
  127. if err != nil {
  128. return nil, err
  129. }
  130. }
  131. if d.source.Name == "job" && updateConfigDriverConfig.WaitForJob && (shouldCreate || !updateConfigDriverConfig.OnlyCreate) {
  132. color.New(color.FgYellow).Printf("Waiting for job '%s' to finish\n", resource.Name)
  133. err = wait.WaitForJob(client, &wait.WaitOpts{
  134. ProjectID: d.target.Project,
  135. ClusterID: d.target.Cluster,
  136. Namespace: d.target.Namespace,
  137. Name: d.target.AppName,
  138. })
  139. if err != nil {
  140. return nil, err
  141. }
  142. }
  143. err = d.assignOutput(resource, client)
  144. if err != nil {
  145. return nil, err
  146. }
  147. return resource, nil
  148. }
  149. func (d *UpdateConfigDriver) Output() (map[string]interface{}, error) {
  150. return d.output, nil
  151. }
  152. func (d *UpdateConfigDriver) getConfig(resource *models.Resource) (*preview.UpdateConfigDriverConfig, error) {
  153. populatedConf, err := drivers.ConstructConfig(&drivers.ConstructConfigOpts{
  154. RawConf: resource.Config,
  155. LookupTable: *d.lookupTable,
  156. Dependencies: resource.Dependencies,
  157. })
  158. if err != nil {
  159. return nil, err
  160. }
  161. config := &preview.UpdateConfigDriverConfig{}
  162. err = mapstructure.Decode(populatedConf, config)
  163. if err != nil {
  164. return nil, err
  165. }
  166. return config, nil
  167. }
  168. func (d *UpdateConfigDriver) assignOutput(resource *models.Resource, client *api.Client) error {
  169. release, err := client.GetRelease(
  170. context.Background(),
  171. d.target.Project,
  172. d.target.Cluster,
  173. d.target.Namespace,
  174. d.target.AppName,
  175. )
  176. if err != nil {
  177. return err
  178. }
  179. d.output = utils.CoalesceValues(d.source.SourceValues, release.Config)
  180. return nil
  181. }