driver_validators.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. package preview
  2. import (
  3. "fmt"
  4. "github.com/mitchellh/mapstructure"
  5. "github.com/porter-dev/switchboard/pkg/types"
  6. "k8s.io/apimachinery/pkg/util/validation"
  7. )
  8. func commonValidator(resource *types.Resource) (*Source, *Target, error) {
  9. source := &Source{}
  10. err := mapstructure.Decode(resource.Source, source)
  11. if err != nil {
  12. return nil, nil, fmt.Errorf("for resource '%s': error parsing source: %w", resource.Name, err)
  13. }
  14. target := &Target{}
  15. err = mapstructure.Decode(resource.Target, target)
  16. if err != nil {
  17. return nil, nil, fmt.Errorf("for resource '%s': error parsing target: %w", resource.Name, err)
  18. }
  19. return source, target, nil
  20. }
  21. func deployDriverValidator(resource *types.Resource) error {
  22. source, _, err := commonValidator(resource)
  23. if err != nil {
  24. return err
  25. }
  26. if source.Name == "" {
  27. return fmt.Errorf("for resource '%s': source name cannot be empty", resource.Name)
  28. }
  29. if source.Repo == "" {
  30. source.Repo = "https://charts.getporter.dev"
  31. }
  32. if source.Repo == "https://charts.getporter.dev" {
  33. appConfig := &ApplicationConfig{}
  34. err = mapstructure.Decode(resource.Config, appConfig)
  35. if err != nil {
  36. return fmt.Errorf("for resource '%s': error parsing config: %w", resource.Name, err)
  37. }
  38. if appConfig.Build.Method == "" {
  39. return fmt.Errorf("for resource '%s': build method cannot be empty", resource.Name)
  40. } else if appConfig.Build.Method != "docker" &&
  41. appConfig.Build.Method != "pack" &&
  42. appConfig.Build.Method != "registry" {
  43. return fmt.Errorf("for resource '%s': build method must be one of 'docker', 'pack', or 'registry'", resource.Name)
  44. }
  45. if appConfig.Build.Method == "docker" && appConfig.Build.Dockerfile == "" {
  46. return fmt.Errorf("for resource '%s': dockerfile cannot be empty when using the 'docker' build method",
  47. resource.Name)
  48. } else if appConfig.Build.Method == "registry" && appConfig.Build.Image == "" {
  49. return fmt.Errorf("for resource '%s': image cannot be empty when using the 'registry' build method",
  50. resource.Name)
  51. }
  52. for _, eg := range appConfig.EnvGroups {
  53. if errStrs := validation.IsDNS1123Label(eg.Name); len(errStrs) > 0 {
  54. str := fmt.Sprintf("for resource '%s': invalid characters found in env group '%s' name:",
  55. resource.Name, eg.Name)
  56. for _, errStr := range errStrs {
  57. str += fmt.Sprintf("\n * %s", errStr)
  58. }
  59. return fmt.Errorf("%s", str)
  60. }
  61. }
  62. if len(appConfig.Values) > 0 {
  63. if source.Name == "web" {
  64. err := validateWebChartValues(appConfig.Values)
  65. if err != nil {
  66. return fmt.Errorf("for resource '%s': error validating values for web deployment: %w",
  67. resource.Name, err)
  68. }
  69. } else if source.Name == "worker" {
  70. err := validateWorkerChartValues(appConfig.Values)
  71. if err != nil {
  72. return fmt.Errorf("for resource '%s': error validating values for worker deployment: %w",
  73. resource.Name, err)
  74. }
  75. } else if source.Name == "job" {
  76. err := validateJobChartValues(appConfig.Values)
  77. if err != nil {
  78. return fmt.Errorf("for resource '%s': error validating values for job deployment: %w",
  79. resource.Name, err)
  80. }
  81. }
  82. }
  83. }
  84. return nil
  85. }
  86. func buildImageDriverValidator(resource *types.Resource) error {
  87. _, target, err := commonValidator(resource)
  88. if err != nil {
  89. return err
  90. }
  91. if target.AppName == "" {
  92. return fmt.Errorf("for resource '%s': target app_name is missing", resource.Name)
  93. } else {
  94. errStrs := validation.IsDNS1123Label(target.AppName)
  95. if len(errStrs) > 0 {
  96. str := fmt.Sprintf("for resource '%s': invalid characters found in app_name:", resource.Name)
  97. for _, errStr := range errStrs {
  98. str += fmt.Sprintf("\n * %s", errStr)
  99. }
  100. return fmt.Errorf("%s", str)
  101. }
  102. }
  103. driverConfig := &BuildDriverConfig{}
  104. err = mapstructure.Decode(resource.Config, driverConfig)
  105. if err != nil {
  106. return fmt.Errorf("for resource '%s': error parsing config: %w", resource.Name, err)
  107. }
  108. if driverConfig.Build.Method == "" {
  109. return fmt.Errorf("for resource '%s': build method cannot be empty", resource.Name)
  110. } else if driverConfig.Build.Method != "docker" &&
  111. driverConfig.Build.Method != "pack" &&
  112. driverConfig.Build.Method != "registry" {
  113. return fmt.Errorf("for resource '%s': build method must be one of 'docker', 'pack', or 'registry'", resource.Name)
  114. }
  115. if driverConfig.Build.Method == "docker" && driverConfig.Build.Dockerfile == "" {
  116. return fmt.Errorf("for resource '%s': dockerfile cannot be empty when using the 'docker' build method",
  117. resource.Name)
  118. } else if driverConfig.Build.Method == "registry" && driverConfig.Build.Image == "" {
  119. return fmt.Errorf("for resource '%s': image cannot be empty when using the 'registry' build method",
  120. resource.Name)
  121. }
  122. for _, eg := range driverConfig.EnvGroups {
  123. if errStrs := validation.IsDNS1123Label(eg.Name); len(errStrs) > 0 {
  124. str := fmt.Sprintf("for resource '%s': invalid characters found in env group '%s' name:",
  125. resource.Name, eg.Name)
  126. for _, errStr := range errStrs {
  127. str += fmt.Sprintf("\n * %s", errStr)
  128. }
  129. return fmt.Errorf("%s", str)
  130. }
  131. }
  132. return nil
  133. }
  134. func pushImageDriverValidator(resource *types.Resource) error {
  135. _, target, err := commonValidator(resource)
  136. if err != nil {
  137. return err
  138. }
  139. if target.AppName == "" {
  140. return fmt.Errorf("for resource '%s': target app_name is missing", resource.Name)
  141. } else {
  142. errStrs := validation.IsDNS1123Label(target.AppName)
  143. if len(errStrs) > 0 {
  144. str := fmt.Sprintf("for resource '%s': invalid characters found in app_name:", resource.Name)
  145. for _, errStr := range errStrs {
  146. str += fmt.Sprintf("\n * %s", errStr)
  147. }
  148. return fmt.Errorf("%s", str)
  149. }
  150. }
  151. driverConfig := &PushDriverConfig{}
  152. err = mapstructure.Decode(resource.Config, driverConfig)
  153. if err != nil {
  154. return fmt.Errorf("for resource '%s': error parsing config: %w", resource.Name, err)
  155. }
  156. if driverConfig.Push.Image == "" {
  157. return fmt.Errorf("for resource '%s': image cannot be empty", resource.Name)
  158. }
  159. return nil
  160. }
  161. func updateConfigDriverValidator(resource *types.Resource) error {
  162. _, target, err := commonValidator(resource)
  163. if err != nil {
  164. return err
  165. }
  166. if target.AppName == "" {
  167. return fmt.Errorf("for resource '%s': target app_name is missing", resource.Name)
  168. } else {
  169. errStrs := validation.IsDNS1123Label(target.AppName)
  170. if len(errStrs) > 0 {
  171. str := fmt.Sprintf("for resource '%s': invalid characters found in app_name:", resource.Name)
  172. for _, errStr := range errStrs {
  173. str += fmt.Sprintf("\n * %s", errStr)
  174. }
  175. return fmt.Errorf("%s", str)
  176. }
  177. }
  178. driverConfig := &UpdateConfigDriverConfig{}
  179. err = mapstructure.Decode(resource.Config, driverConfig)
  180. if err != nil {
  181. return fmt.Errorf("for resource '%s': error parsing config: %w", resource.Name, err)
  182. }
  183. if driverConfig.UpdateConfig.Image == "" {
  184. return fmt.Errorf("for resource '%s': image cannot be empty", resource.Name)
  185. }
  186. for _, eg := range driverConfig.EnvGroups {
  187. if errStrs := validation.IsDNS1123Label(eg.Name); len(errStrs) > 0 {
  188. str := fmt.Sprintf("for resource '%s': invalid characters found in env group '%s' name:",
  189. resource.Name, eg.Name)
  190. for _, errStr := range errStrs {
  191. str += fmt.Sprintf("\n * %s", errStr)
  192. }
  193. return fmt.Errorf("%s", str)
  194. }
  195. }
  196. return nil
  197. }
  198. func randomStringDriverValidator(resource *types.Resource) error {
  199. driverConfig := &RandomStringDriverConfig{}
  200. err := mapstructure.Decode(resource.Config, driverConfig)
  201. if err != nil {
  202. return fmt.Errorf("for resource '%s': error parsing config: %w", resource.Name, err)
  203. }
  204. return nil
  205. }
  206. func envGroupDriverValidator(resource *types.Resource) error {
  207. target := &Target{}
  208. err := mapstructure.Decode(resource.Target, target)
  209. if err != nil {
  210. return fmt.Errorf("for resource '%s': error parsing target: %w", resource.Name, err)
  211. }
  212. config := &EnvGroupDriverConfig{}
  213. err = mapstructure.Decode(resource.Config, config)
  214. if err != nil {
  215. return fmt.Errorf("for resource '%s': error parsing config: %w", resource.Name, err)
  216. }
  217. for _, eg := range config.EnvGroups {
  218. if errStrs := validation.IsDNS1123Label(eg.Name); len(errStrs) > 0 {
  219. str := fmt.Sprintf("for resource '%s': invalid characters found in env group '%s' name:",
  220. resource.Name, eg.Name)
  221. for _, errStr := range errStrs {
  222. str += fmt.Sprintf("\n * %s", errStr)
  223. }
  224. return fmt.Errorf("%s", str)
  225. }
  226. }
  227. return nil
  228. }
  229. func osEnvDriverValidator(resource *types.Resource) error {
  230. return nil
  231. }