2
0

utils.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package preview
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "strconv"
  7. api "github.com/porter-dev/porter/api/client"
  8. "github.com/porter-dev/porter/api/types"
  9. "github.com/porter-dev/porter/cli/cmd/config"
  10. "github.com/porter-dev/porter/internal/integrations/preview"
  11. )
  12. // GetSource extends switchboard
  13. func GetSource(ctx context.Context, projectID uint, resourceName string, input map[string]interface{}, apiClient api.Client) (*preview.Source, error) {
  14. output := &preview.Source{}
  15. // first read from env vars
  16. output.Name = os.Getenv("PORTER_SOURCE_NAME")
  17. output.Repo = os.Getenv("PORTER_SOURCE_REPO")
  18. output.Version = os.Getenv("PORTER_SOURCE_VERSION")
  19. // next, check for values in the YAML file
  20. if output.Name == "" {
  21. if name, ok := input["name"]; ok {
  22. nameVal, ok := name.(string)
  23. if !ok {
  24. return nil, fmt.Errorf("error parsing source for resource '%s': invalid name provided", resourceName)
  25. }
  26. output.Name = nameVal
  27. }
  28. }
  29. if output.Name == "" {
  30. return nil, fmt.Errorf("error parsing source for resource '%s': source name required", resourceName)
  31. }
  32. if output.Repo == "" {
  33. if repo, ok := input["repo"]; ok {
  34. repoVal, ok := repo.(string)
  35. if !ok {
  36. return nil, fmt.Errorf("error parsing source for resource '%s': invalid repo provided", resourceName)
  37. }
  38. output.Repo = repoVal
  39. }
  40. }
  41. if output.Version == "" {
  42. if version, ok := input["version"]; ok {
  43. versionVal, ok := version.(string)
  44. if !ok {
  45. return nil, fmt.Errorf("error parsing source for resource '%s': invalid version provided", resourceName)
  46. }
  47. output.Version = versionVal
  48. }
  49. }
  50. // lastly, just put in the defaults
  51. if output.Version == "" {
  52. output.Version = "latest"
  53. }
  54. serverMetadata, err := apiClient.GetPorterInstanceMetadata(ctx)
  55. if err != nil {
  56. return nil, fmt.Errorf("error fetching Porter instance metadata: %w", err)
  57. }
  58. if output.Repo == "" {
  59. if serverMetadata.DefaultAppHelmRepoURL != "" {
  60. output.Repo = serverMetadata.DefaultAppHelmRepoURL
  61. } else {
  62. output.Repo = "https://charts.getporter.dev"
  63. }
  64. values, err := existsInRepo(ctx, projectID, output.Name, output.Version, output.Repo, apiClient)
  65. if err == nil {
  66. output.SourceValues = values
  67. output.IsApplication = true
  68. return output, nil
  69. }
  70. if serverMetadata.DefaultAddonHelmRepoURL != "" {
  71. output.Repo = serverMetadata.DefaultAddonHelmRepoURL
  72. } else {
  73. output.Repo = "https://chart-addons.getporter.dev"
  74. }
  75. values, err = existsInRepo(ctx, projectID, output.Name, output.Version, output.Repo, apiClient)
  76. if err == nil {
  77. output.SourceValues = values
  78. return output, nil
  79. }
  80. return nil, fmt.Errorf("error parsing source for resource '%s': source chart does not exist in the default "+
  81. "Helm repositories", resourceName)
  82. } else {
  83. // we look in the passed-in repo
  84. values, err := existsInRepo(ctx, projectID, output.Name, output.Version, output.Repo, apiClient)
  85. if err == nil {
  86. output.SourceValues = values
  87. output.IsApplication = output.Repo == serverMetadata.DefaultAppHelmRepoURL || output.Repo == "https://charts.getporter.dev"
  88. return output, nil
  89. }
  90. }
  91. return nil, fmt.Errorf("error parsing source for resource '%s': source '%s' does not exist in repo '%s'",
  92. resourceName, output.Name, output.Repo)
  93. }
  94. // GetTarget extends switchboard
  95. func GetTarget(ctx context.Context, resourceName string, input map[string]interface{}, apiClient api.Client, cliConfig config.CLIConfig) (*preview.Target, error) {
  96. output := &preview.Target{}
  97. // first read from env vars
  98. if projectEnv := os.Getenv("PORTER_PROJECT"); projectEnv != "" {
  99. project, err := strconv.Atoi(projectEnv)
  100. if err != nil {
  101. return nil, fmt.Errorf("error parsing target for resource '%s': %w", resourceName, err)
  102. }
  103. output.Project = uint(project)
  104. }
  105. if clusterEnv := os.Getenv("PORTER_CLUSTER"); clusterEnv != "" {
  106. cluster, err := strconv.Atoi(clusterEnv)
  107. if err != nil {
  108. return nil, fmt.Errorf("error parsing target for resource '%s': %w", resourceName, err)
  109. }
  110. output.Cluster = uint(cluster)
  111. }
  112. output.Namespace = os.Getenv("PORTER_NAMESPACE")
  113. // next, check for values in the YAML file
  114. if output.Project == 0 {
  115. if project, ok := input["project"]; ok {
  116. projectVal, ok := project.(uint)
  117. if !ok {
  118. return nil, fmt.Errorf("error parsing target for resource '%s': project value must be an integer", resourceName)
  119. }
  120. output.Project = projectVal
  121. }
  122. }
  123. if output.Cluster == 0 {
  124. if cluster, ok := input["cluster"]; ok {
  125. clusterVal, ok := cluster.(uint)
  126. if !ok {
  127. return nil, fmt.Errorf("error parsing target for resource '%s': cluster value must be an integer",
  128. resourceName)
  129. }
  130. output.Cluster = clusterVal
  131. }
  132. }
  133. if output.Namespace == "" {
  134. if namespace, ok := input["namespace"]; ok {
  135. namespaceVal, ok := namespace.(string)
  136. if !ok {
  137. return nil, fmt.Errorf("error parsing target for resource '%s': invalid namespace provided", resourceName)
  138. }
  139. output.Namespace = namespaceVal
  140. }
  141. }
  142. if registryURL, ok := input["registry_url"]; ok {
  143. registryURLVal, ok := registryURL.(string)
  144. if !ok {
  145. return nil, fmt.Errorf("error parsing target for resource '%s': invalid registry_url provided", resourceName)
  146. }
  147. output.RegistryURL = registryURLVal
  148. }
  149. if appName, ok := input["app_name"]; ok {
  150. appNameVal, ok := appName.(string)
  151. if !ok {
  152. return nil, fmt.Errorf("error parsing target for resource '%s': invalid app_name provided", resourceName)
  153. }
  154. output.AppName = appNameVal
  155. }
  156. // lastly, just put in the defaults
  157. if output.Project == 0 {
  158. output.Project = cliConfig.Project
  159. }
  160. if output.Cluster == 0 {
  161. output.Cluster = cliConfig.Cluster
  162. }
  163. if output.Namespace == "" {
  164. output.Namespace = "default"
  165. }
  166. if output.RegistryURL == "" {
  167. if cliConfig.Registry == 0 {
  168. regList, err := apiClient.ListRegistries(ctx, output.Project)
  169. if err != nil {
  170. return nil, fmt.Errorf("for resource '%s', error listing registries in project: %w", resourceName, err)
  171. }
  172. if len(*regList) == 0 {
  173. return nil, fmt.Errorf("for resource '%s', no registries found in project", resourceName)
  174. }
  175. output.RegistryURL = (*regList)[0].URL
  176. } else {
  177. reg, err := apiClient.GetRegistry(ctx, output.Project, cliConfig.Registry)
  178. if err != nil {
  179. return nil, fmt.Errorf("for resource '%s', error getting registry from CLI config: %w", resourceName, err)
  180. }
  181. output.RegistryURL = reg.URL
  182. }
  183. }
  184. return output, nil
  185. }
  186. func existsInRepo(ctx context.Context, projectID uint, name, version, url string, apiClient api.Client) (map[string]interface{}, error) {
  187. chart, err := apiClient.GetTemplate(
  188. ctx,
  189. projectID,
  190. name, version,
  191. &types.GetTemplateRequest{
  192. TemplateGetBaseRequest: types.TemplateGetBaseRequest{
  193. RepoURL: url,
  194. },
  195. },
  196. )
  197. if err != nil {
  198. return nil, err
  199. }
  200. return chart.Values, nil
  201. }