update_image.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package v2
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "time"
  7. "github.com/porter-dev/porter/api/server/handlers/porter_app"
  8. "github.com/fatih/color"
  9. api "github.com/porter-dev/porter/api/client"
  10. )
  11. // UpdateImageInput is the input for the UpdateImage function
  12. type UpdateImageInput struct {
  13. ProjectID uint
  14. ClusterID uint
  15. AppName string
  16. DeploymentTargetName string
  17. Tag string
  18. WaitForSuccessfulUpdate bool
  19. Client api.Client
  20. }
  21. const (
  22. // DefaultWaitTimeoutMinutes is the default timeout for waiting for an update-image to complete
  23. DefaultWaitTimeoutMinutes = 10
  24. // DefaultRetryFrequencySeconds is the default frequency for checking the status of an update-image
  25. DefaultRetryFrequencySeconds = 10
  26. )
  27. // UpdateImage updates the image of an application
  28. func UpdateImage(ctx context.Context, input UpdateImageInput) error {
  29. if input.DeploymentTargetName == "" {
  30. return errors.New("please provide a deployment target")
  31. }
  32. tag := input.Tag
  33. if tag == "" {
  34. tag = "latest"
  35. }
  36. resp, err := input.Client.UpdateImage(ctx, input.ProjectID, input.ClusterID, input.AppName, input.DeploymentTargetName, tag)
  37. if err != nil {
  38. return fmt.Errorf("unable to update image: %w", err)
  39. }
  40. triggeredBackgroundColor := color.FgGreen
  41. if input.WaitForSuccessfulUpdate {
  42. triggeredBackgroundColor = color.FgBlue
  43. }
  44. _, _ = color.New(triggeredBackgroundColor).Printf("Updated application %s to use tag \"%s\"\n", input.AppName, tag)
  45. if !input.WaitForSuccessfulUpdate {
  46. return nil
  47. }
  48. timeoutMinutes := DefaultWaitTimeoutMinutes
  49. timeout := time.Duration(timeoutMinutes) * time.Minute
  50. deadline := time.Now().Add(timeout)
  51. color.New(color.FgBlue).Printf("Waiting %d minutes for update to complete\n", timeoutMinutes) // nolint:errcheck,gosec
  52. var status porter_app.HighLevelStatus
  53. for time.Now().Before(deadline) {
  54. statusResp, err := input.Client.GetRevisionStatus(ctx, input.ProjectID, input.ClusterID, input.AppName, resp.RevisionID)
  55. if err != nil {
  56. return fmt.Errorf("error getting app revision status: %w", err)
  57. }
  58. if statusResp == nil {
  59. return errors.New("unable to determine status of app revision")
  60. }
  61. status = statusResp.HighLevelStatus
  62. if status != porter_app.HighLevelStatus_Progressing {
  63. break
  64. }
  65. time.Sleep(DefaultRetryFrequencySeconds * time.Second)
  66. }
  67. switch status {
  68. case porter_app.HighLevelStatus_Progressing:
  69. return fmt.Errorf("timeout exceeded")
  70. case porter_app.HighLevelStatus_Successful:
  71. _, _ = color.New(color.FgGreen).Printf("Update completed successfully\n") // nolint:errcheck,gosec
  72. return nil
  73. case porter_app.HighLevelStatus_Failed:
  74. return fmt.Errorf("update failed: check dashboard for details")
  75. default:
  76. return fmt.Errorf("received unknown status: %s", status)
  77. }
  78. }