2
0

pre-deploy.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package stack
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/mitchellh/mapstructure"
  6. api "github.com/porter-dev/porter/api/client"
  7. "github.com/porter-dev/porter/cli/cmd/deploy"
  8. "github.com/porter-dev/porter/internal/integrations/preview"
  9. "github.com/porter-dev/porter/internal/telemetry"
  10. switchboardTypes "github.com/porter-dev/switchboard/pkg/types"
  11. )
  12. func maybeCreatePreDeployResource(ctx context.Context, client *api.Client, release *App, stackName, buildResourceName, pushResourceName string, projectID, clusterID uint, env map[string]string) (*switchboardTypes.Resource, string, error) {
  13. ctx, span := telemetry.NewSpan(ctx, "maybe-create-pre-deploy-resource")
  14. defer span.End()
  15. var finalCmd string
  16. if release != nil && release.Run != nil {
  17. finalCmd = *release.Run
  18. } else {
  19. finalCmd = getPreDeployCommandFromRelease(ctx, client, stackName, projectID, clusterID)
  20. if finalCmd == "" {
  21. return nil, "", nil
  22. }
  23. }
  24. telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "pre-deploy-cmd", Value: finalCmd})
  25. config := &preview.ApplicationConfig{}
  26. config.Build.Method = "registry"
  27. config.Build.Image = fmt.Sprintf("{ .%s.image }", buildResourceName)
  28. config.Build.Env = CopyEnv(env)
  29. config.WaitForJob = true
  30. config.InjectBuild = true
  31. helm_values := make(map[string]interface{})
  32. if release != nil && release.Config != nil {
  33. helm_values = release.Config
  34. }
  35. helm_values["container"] = map[string]interface{}{
  36. "command": finalCmd,
  37. "env": map[string]interface{}{
  38. "normal": CopyEnv(env),
  39. },
  40. }
  41. helm_values["paused"] = false
  42. config.Values = convertMap(helm_values).(map[string]interface{})
  43. rawConfig := make(map[string]any)
  44. err := mapstructure.Decode(config, &rawConfig)
  45. if err != nil {
  46. return nil, "", fmt.Errorf("could not decode config for release: %w", err)
  47. }
  48. return &switchboardTypes.Resource{
  49. Name: fmt.Sprintf("%s-r", stackName),
  50. DependsOn: []string{"get-env", buildResourceName, pushResourceName},
  51. Source: map[string]any{
  52. "name": "job",
  53. },
  54. Target: map[string]any{
  55. "app_name": fmt.Sprintf("%s-r", stackName),
  56. "namespace": fmt.Sprintf("porter-stack-%s", stackName),
  57. },
  58. Config: rawConfig,
  59. }, finalCmd, nil
  60. }
  61. func getPreDeployCommandFromRelease(ctx context.Context, client *api.Client, stackName string, projectID uint, clusterID uint) string {
  62. namespace := fmt.Sprintf("porter-stack-%s", stackName)
  63. releaseName := fmt.Sprintf("%s-r", stackName)
  64. release, err := client.GetRelease(
  65. ctx,
  66. projectID,
  67. clusterID,
  68. namespace,
  69. releaseName,
  70. )
  71. if err != nil || release == nil || release.Config == nil {
  72. return ""
  73. }
  74. containerMap, err := deploy.GetNestedMap(release.Config, "container")
  75. if err == nil {
  76. if command, ok := containerMap["command"]; ok {
  77. if commandString, ok := command.(string); ok {
  78. return commandString
  79. }
  80. }
  81. }
  82. return ""
  83. }
  84. func convertMap(m interface{}) interface{} {
  85. switch m := m.(type) {
  86. case map[string]interface{}:
  87. for k, v := range m {
  88. m[k] = convertMap(v)
  89. }
  90. case map[interface{}]interface{}:
  91. result := map[string]interface{}{}
  92. for k, v := range m {
  93. result[k.(string)] = convertMap(v)
  94. }
  95. return result
  96. case []interface{}:
  97. for i, v := range m {
  98. m[i] = convertMap(v)
  99. }
  100. }
  101. return m
  102. }