hooks.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package stack
  2. import (
  3. "context"
  4. "encoding/base64"
  5. "fmt"
  6. "strings"
  7. "github.com/fatih/color"
  8. api "github.com/porter-dev/porter/api/client"
  9. "github.com/porter-dev/porter/api/types"
  10. "github.com/porter-dev/porter/cli/cmd/config"
  11. )
  12. type DeployStackHook struct {
  13. Client *api.Client
  14. StackName string
  15. ProjectID, ClusterID uint
  16. BuildImageDriverName string
  17. PorterYAML []byte
  18. }
  19. func (t *DeployStackHook) PreApply() error {
  20. err := config.ValidateCLIEnvironment()
  21. if err != nil {
  22. errMsg := composePreviewMessage("porter CLI is not configured correctly", Error)
  23. return fmt.Errorf("%s: %w", errMsg, err)
  24. }
  25. return nil
  26. }
  27. func (t *DeployStackHook) DataQueries() map[string]interface{} {
  28. res := map[string]interface{}{
  29. "image": fmt.Sprintf("{$.%s.image}", t.BuildImageDriverName),
  30. }
  31. return res
  32. }
  33. // deploy the stack
  34. func (t *DeployStackHook) PostApply(driverOutput map[string]interface{}) error {
  35. client := config.GetAPIClient()
  36. namespace := fmt.Sprintf("porter-stack-%s", t.StackName)
  37. _, err := client.GetRelease(
  38. context.Background(),
  39. t.ProjectID,
  40. t.ClusterID,
  41. namespace,
  42. t.StackName,
  43. )
  44. shouldCreate := err != nil
  45. if err != nil {
  46. color.New(color.FgYellow).Printf("Could not read release for stack %s (%s): attempting creation\n", t.StackName, err.Error())
  47. } else {
  48. color.New(color.FgGreen).Printf("Found release for stack %s: attempting update\n", t.StackName)
  49. }
  50. return t.applyStack(client, shouldCreate, driverOutput)
  51. }
  52. func (t *DeployStackHook) applyStack(client *api.Client, shouldCreate bool, driverOutput map[string]interface{}) error {
  53. var imageInfo types.ImageInfo
  54. image, ok := driverOutput["image"].(string)
  55. // if it contains a $, then it means the query didn't resolve to anything
  56. if ok && !strings.Contains(image, "$") {
  57. imageSpl := strings.Split(image, ":")
  58. if len(imageSpl) == 2 {
  59. imageInfo = types.ImageInfo{
  60. Repository: imageSpl[0],
  61. Tag: imageSpl[1],
  62. }
  63. } else {
  64. return fmt.Errorf("could not parse image info %s", image)
  65. }
  66. }
  67. if shouldCreate {
  68. err := client.CreateStack(
  69. context.Background(),
  70. t.ProjectID,
  71. t.ClusterID,
  72. &types.CreateStackReleaseRequest{
  73. StackName: t.StackName,
  74. PorterYAMLBase64: base64.StdEncoding.EncodeToString(t.PorterYAML),
  75. ImageInfo: imageInfo,
  76. },
  77. )
  78. if err != nil {
  79. return fmt.Errorf("error creating stack %s: %w", t.StackName, err)
  80. }
  81. } else {
  82. err := client.UpdateStack(
  83. context.Background(),
  84. t.ProjectID,
  85. t.ClusterID,
  86. t.StackName,
  87. &types.CreateStackReleaseRequest{
  88. StackName: t.StackName,
  89. PorterYAMLBase64: base64.StdEncoding.EncodeToString(t.PorterYAML),
  90. ImageInfo: imageInfo,
  91. },
  92. )
  93. if err != nil {
  94. return fmt.Errorf("error updating stack %s: %w", t.StackName, err)
  95. }
  96. }
  97. return nil
  98. }
  99. func (t *DeployStackHook) OnConsolidatedErrors(map[string]error) {}
  100. func (t *DeployStackHook) OnError(error) {}