uffizzi-core 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (257) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +52 -0
  4. data/Rakefile +31 -0
  5. data/app/assets/config/uffizzi_core_manifest.js +1 -0
  6. data/app/assets/stylesheets/uffizzi_core/application.css +15 -0
  7. data/app/clients/uffizzi_core/amazon_registry_client.rb +18 -0
  8. data/app/clients/uffizzi_core/azure_registry_client/request_result.rb +5 -0
  9. data/app/clients/uffizzi_core/azure_registry_client.rb +42 -0
  10. data/app/clients/uffizzi_core/controller_client/request_result.rb +5 -0
  11. data/app/clients/uffizzi_core/controller_client.rb +106 -0
  12. data/app/clients/uffizzi_core/docker_hub_client/request_result.rb +7 -0
  13. data/app/clients/uffizzi_core/docker_hub_client.rb +141 -0
  14. data/app/clients/uffizzi_core/github_container_registry_client/request_result.rb +7 -0
  15. data/app/clients/uffizzi_core/github_container_registry_client.rb +52 -0
  16. data/app/clients/uffizzi_core/google_registry_client/request_result.rb +5 -0
  17. data/app/clients/uffizzi_core/google_registry_client.rb +42 -0
  18. data/app/contexts/uffizzi_core/base_context.rb +12 -0
  19. data/app/contexts/uffizzi_core/project_context.rb +13 -0
  20. data/app/contexts/uffizzi_core/webhooks_context.rb +9 -0
  21. data/app/controllers/concerns/uffizzi_core/auth_management.rb +23 -0
  22. data/app/controllers/concerns/uffizzi_core/authorization_concern.rb +38 -0
  23. data/app/controllers/concerns/uffizzi_core/dependency_injection_concern.rb +19 -0
  24. data/app/controllers/uffizzi_core/api/cli/v1/account/application_controller.rb +7 -0
  25. data/app/controllers/uffizzi_core/api/cli/v1/account/credentials_controller.rb +91 -0
  26. data/app/controllers/uffizzi_core/api/cli/v1/application_controller.rb +5 -0
  27. data/app/controllers/uffizzi_core/api/cli/v1/projects/application_controller.rb +11 -0
  28. data/app/controllers/uffizzi_core/api/cli/v1/projects/compose_files_controller.rb +93 -0
  29. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/activity_items_controller.rb +36 -0
  30. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/application_controller.rb +7 -0
  31. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers/application_controller.rb +8 -0
  32. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers/logs_controller.rb +27 -0
  33. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers_controller.rb +24 -0
  34. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/events_controller.rb +29 -0
  35. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments_controller.rb +179 -0
  36. data/app/controllers/uffizzi_core/api/cli/v1/projects/secrets_controller.rb +61 -0
  37. data/app/controllers/uffizzi_core/api/cli/v1/projects_controller.rb +85 -0
  38. data/app/controllers/uffizzi_core/api/cli/v1/sessions_controller.rb +43 -0
  39. data/app/controllers/uffizzi_core/application_controller.rb +57 -0
  40. data/app/errors/uffizzi_core/compose_file/build_error.rb +4 -0
  41. data/app/errors/uffizzi_core/compose_file/credential_error.rb +4 -0
  42. data/app/errors/uffizzi_core/compose_file/parse_error.rb +4 -0
  43. data/app/errors/uffizzi_core/compose_file/secrets_error.rb +4 -0
  44. data/app/errors/uffizzi_core/deployment/image_pull_error.rb +10 -0
  45. data/app/errors/uffizzi_core/deployment_not_found_error.rb +10 -0
  46. data/app/forms/uffizzi_core/api/cli/v1/account/credential/check_credential_form.rb +16 -0
  47. data/app/forms/uffizzi_core/api/cli/v1/account/credential/create_form.rb +26 -0
  48. data/app/forms/uffizzi_core/api/cli/v1/compose_file/check_credentials_form.rb +21 -0
  49. data/app/forms/uffizzi_core/api/cli/v1/compose_file/cli_form.rb +22 -0
  50. data/app/forms/uffizzi_core/api/cli/v1/compose_file/create_form.rb +13 -0
  51. data/app/forms/uffizzi_core/api/cli/v1/compose_file/template_form.rb +44 -0
  52. data/app/forms/uffizzi_core/api/cli/v1/compose_file/update_form.rb +9 -0
  53. data/app/forms/uffizzi_core/api/cli/v1/config_file/create_form.rb +11 -0
  54. data/app/forms/uffizzi_core/api/cli/v1/deployment/create_form.rb +92 -0
  55. data/app/forms/uffizzi_core/api/cli/v1/deployment/update_form.rb +90 -0
  56. data/app/forms/uffizzi_core/api/cli/v1/project/create_form.rb +7 -0
  57. data/app/forms/uffizzi_core/api/cli/v1/project/update_form.rb +10 -0
  58. data/app/forms/uffizzi_core/api/cli/v1/secret/bulk_assign_form.rb +39 -0
  59. data/app/forms/uffizzi_core/api/cli/v1/session_create_form.rb +29 -0
  60. data/app/forms/uffizzi_core/api/cli/v1/template/create_form.rb +65 -0
  61. data/app/forms/uffizzi_core/application_form.rb +11 -0
  62. data/app/forms/uffizzi_core/application_form_without_active_record.rb +17 -0
  63. data/app/forms/uffizzi_core/mass_assignment_control_concern.rb +22 -0
  64. data/app/helpers/uffizzi_core/application_helper.rb +6 -0
  65. data/app/jobs/uffizzi_core/account/create_credential_job.rb +10 -0
  66. data/app/jobs/uffizzi_core/activity_item/docker/update_digest_job.rb +11 -0
  67. data/app/jobs/uffizzi_core/application_job.rb +7 -0
  68. data/app/jobs/uffizzi_core/config_file/apply_job.rb +31 -0
  69. data/app/jobs/uffizzi_core/credential/docker_hub/create_webhook_job.rb +15 -0
  70. data/app/jobs/uffizzi_core/deployment/create_credential_job.rb +32 -0
  71. data/app/jobs/uffizzi_core/deployment/create_credentials_job.rb +17 -0
  72. data/app/jobs/uffizzi_core/deployment/create_job.rb +15 -0
  73. data/app/jobs/uffizzi_core/deployment/create_webhooks_job.rb +13 -0
  74. data/app/jobs/uffizzi_core/deployment/delete_credential_job.rb +13 -0
  75. data/app/jobs/uffizzi_core/deployment/delete_job.rb +11 -0
  76. data/app/jobs/uffizzi_core/deployment/deploy_containers_job.rb +27 -0
  77. data/app/jobs/uffizzi_core/deployment/manage_deploy_activity_item_job.rb +38 -0
  78. data/app/lib/uffizzi_core/concerns/models/activity_item.rb +39 -0
  79. data/app/lib/uffizzi_core/concerns/models/credential.rb +65 -0
  80. data/app/lib/uffizzi_core/concerns/models/repo.rb +33 -0
  81. data/app/lib/uffizzi_core/rbac/user_access_service.rb +45 -0
  82. data/app/mailers/uffizzi_core/application_mailer.rb +8 -0
  83. data/app/models/concerns/uffizzi_core/hashid_concern.rb +25 -0
  84. data/app/models/concerns/uffizzi_core/state_machine_concern.rb +16 -0
  85. data/app/models/uffizzi_core/account.rb +83 -0
  86. data/app/models/uffizzi_core/activity_item/docker.rb +4 -0
  87. data/app/models/uffizzi_core/activity_item/github.rb +4 -0
  88. data/app/models/uffizzi_core/activity_item/memory_limit.rb +4 -0
  89. data/app/models/uffizzi_core/activity_item.rb +53 -0
  90. data/app/models/uffizzi_core/application_record.rb +7 -0
  91. data/app/models/uffizzi_core/build.rb +39 -0
  92. data/app/models/uffizzi_core/comment.rb +16 -0
  93. data/app/models/uffizzi_core/compose_file.rb +57 -0
  94. data/app/models/uffizzi_core/config_file.rb +24 -0
  95. data/app/models/uffizzi_core/container.rb +100 -0
  96. data/app/models/uffizzi_core/container_config_file.rb +8 -0
  97. data/app/models/uffizzi_core/continuous_preview.rb +4 -0
  98. data/app/models/uffizzi_core/coupon.rb +5 -0
  99. data/app/models/uffizzi_core/credential/amazon.rb +4 -0
  100. data/app/models/uffizzi_core/credential/azure.rb +4 -0
  101. data/app/models/uffizzi_core/credential/docker_hub.rb +4 -0
  102. data/app/models/uffizzi_core/credential/github.rb +4 -0
  103. data/app/models/uffizzi_core/credential/github_container_registry.rb +4 -0
  104. data/app/models/uffizzi_core/credential/google.rb +4 -0
  105. data/app/models/uffizzi_core/credential.rb +61 -0
  106. data/app/models/uffizzi_core/database.rb +4 -0
  107. data/app/models/uffizzi_core/database_offering.rb +4 -0
  108. data/app/models/uffizzi_core/deployment.rb +86 -0
  109. data/app/models/uffizzi_core/event.rb +13 -0
  110. data/app/models/uffizzi_core/invitation.rb +27 -0
  111. data/app/models/uffizzi_core/membership.rb +16 -0
  112. data/app/models/uffizzi_core/payment.rb +11 -0
  113. data/app/models/uffizzi_core/price.rb +9 -0
  114. data/app/models/uffizzi_core/product.rb +11 -0
  115. data/app/models/uffizzi_core/project.rb +67 -0
  116. data/app/models/uffizzi_core/rating.rb +20 -0
  117. data/app/models/uffizzi_core/repo/amazon.rb +4 -0
  118. data/app/models/uffizzi_core/repo/azure.rb +4 -0
  119. data/app/models/uffizzi_core/repo/docker_hub.rb +4 -0
  120. data/app/models/uffizzi_core/repo/github.rb +4 -0
  121. data/app/models/uffizzi_core/repo/github_container_registry.rb +4 -0
  122. data/app/models/uffizzi_core/repo/google.rb +4 -0
  123. data/app/models/uffizzi_core/repo.rb +29 -0
  124. data/app/models/uffizzi_core/role.rb +17 -0
  125. data/app/models/uffizzi_core/secret.rb +9 -0
  126. data/app/models/uffizzi_core/template.rb +19 -0
  127. data/app/models/uffizzi_core/user.rb +62 -0
  128. data/app/models/uffizzi_core/user_project.rb +14 -0
  129. data/app/policies/uffizzi_core/api/cli/v1/account/credentials_policy.rb +19 -0
  130. data/app/policies/uffizzi_core/api/cli/v1/projects/compose_files_policy.rb +15 -0
  131. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/activity_items_policy.rb +7 -0
  132. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/containers_policy.rb +7 -0
  133. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/events_policy.rb +7 -0
  134. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments_policy.rb +27 -0
  135. data/app/policies/uffizzi_core/api/cli/v1/projects/secrets_policy.rb +15 -0
  136. data/app/policies/uffizzi_core/api/cli/v1/projects_policy.rb +19 -0
  137. data/app/policies/uffizzi_core/application_policy.rb +12 -0
  138. data/app/repositories/uffizzi_core/activity_item_repo.rb +9 -0
  139. data/app/repositories/uffizzi_core/basic_order_repo.rb +11 -0
  140. data/app/repositories/uffizzi_core/build_repo.rb +23 -0
  141. data/app/repositories/uffizzi_core/comment_repo.rb +11 -0
  142. data/app/repositories/uffizzi_core/compose_file_repo.rb +11 -0
  143. data/app/repositories/uffizzi_core/config_file_repo.rb +40 -0
  144. data/app/repositories/uffizzi_core/container_repo.rb +25 -0
  145. data/app/repositories/uffizzi_core/credential_repo.rb +31 -0
  146. data/app/repositories/uffizzi_core/deployment_repo.rb +24 -0
  147. data/app/repositories/uffizzi_core/event_repo.rb +9 -0
  148. data/app/repositories/uffizzi_core/membership_repo.rb +10 -0
  149. data/app/repositories/uffizzi_core/price_repo.rb +11 -0
  150. data/app/repositories/uffizzi_core/product_repo.rb +11 -0
  151. data/app/repositories/uffizzi_core/project_repo.rb +10 -0
  152. data/app/repositories/uffizzi_core/repo_repo.rb +10 -0
  153. data/app/repositories/uffizzi_core/template_repo.rb +87 -0
  154. data/app/repositories/uffizzi_core/usage_repo.rb +9 -0
  155. data/app/repositories/uffizzi_core/user_repo.rb +11 -0
  156. data/app/responders/uffizzi_core/json_responder.rb +13 -0
  157. data/app/serializers/uffizzi_core/api/cli/v1/account/credential_serializer.rb +9 -0
  158. data/app/serializers/uffizzi_core/api/cli/v1/project_serializer/compose_file_serializer.rb +7 -0
  159. data/app/serializers/uffizzi_core/api/cli/v1/project_serializer/deployment_serializer.rb +13 -0
  160. data/app/serializers/uffizzi_core/api/cli/v1/project_serializer.rb +30 -0
  161. data/app/serializers/uffizzi_core/api/cli/v1/projects/compose_file_serializer.rb +7 -0
  162. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/container_serializer.rb +32 -0
  163. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/user_serializer.rb +11 -0
  164. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer.rb +74 -0
  165. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/activity_item_serializer.rb +24 -0
  166. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer/container_config_file_serializer/config_file_serializer.rb +6 -0
  167. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer/container_config_file_serializer.rb +7 -0
  168. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer.rb +30 -0
  169. data/app/serializers/uffizzi_core/api/cli/v1/projects/secret_serializer.rb +5 -0
  170. data/app/serializers/uffizzi_core/api/cli/v1/short_project_serializer.rb +7 -0
  171. data/app/serializers/uffizzi_core/api/cli/v1/user_serializer/account_serializer.rb +5 -0
  172. data/app/serializers/uffizzi_core/api/cli/v1/user_serializer.rb +7 -0
  173. data/app/serializers/uffizzi_core/base_serializer.rb +7 -0
  174. data/app/serializers/uffizzi_core/controller/apply_config_file/config_file_serializer.rb +5 -0
  175. data/app/serializers/uffizzi_core/controller/create_credential/credential_serializer.rb +19 -0
  176. data/app/serializers/uffizzi_core/controller/create_deployment/deployment_serializer.rb +5 -0
  177. data/app/serializers/uffizzi_core/controller/deploy_containers/container_serializer/container_config_file_serializer/config_file_serializer.rb +8 -0
  178. data/app/serializers/uffizzi_core/controller/deploy_containers/container_serializer/container_config_file_serializer.rb +7 -0
  179. data/app/serializers/uffizzi_core/controller/deploy_containers/container_serializer.rb +70 -0
  180. data/app/serializers/uffizzi_core/controller/deploy_containers/credential_serializer.rb +5 -0
  181. data/app/services/uffizzi_core/account_service.rb +21 -0
  182. data/app/services/uffizzi_core/activity_item_service.rb +88 -0
  183. data/app/services/uffizzi_core/amazon/credential_service.rb +31 -0
  184. data/app/services/uffizzi_core/amazon_service.rb +45 -0
  185. data/app/services/uffizzi_core/azure/credential_service.rb +18 -0
  186. data/app/services/uffizzi_core/compose_file/builders/config_files_builder_service.rb +31 -0
  187. data/app/services/uffizzi_core/compose_file/builders/container_builder_service.rb +222 -0
  188. data/app/services/uffizzi_core/compose_file/builders/docker_repo_builder_service.rb +25 -0
  189. data/app/services/uffizzi_core/compose_file/builders/template_builder_service.rb +45 -0
  190. data/app/services/uffizzi_core/compose_file/builders/variables_builder_service.rb +58 -0
  191. data/app/services/uffizzi_core/compose_file/config_files_service.rb +52 -0
  192. data/app/services/uffizzi_core/compose_file/config_option_service.rb +41 -0
  193. data/app/services/uffizzi_core/compose_file/configs_options_service.rb +26 -0
  194. data/app/services/uffizzi_core/compose_file/container_service.rb +68 -0
  195. data/app/services/uffizzi_core/compose_file/continuous_preview_options_service.rb +57 -0
  196. data/app/services/uffizzi_core/compose_file/dependencies_service.rb +56 -0
  197. data/app/services/uffizzi_core/compose_file/errors_service.rb +46 -0
  198. data/app/services/uffizzi_core/compose_file/github_dependencies_service.rb +38 -0
  199. data/app/services/uffizzi_core/compose_file/ingress_options_service.rb +51 -0
  200. data/app/services/uffizzi_core/compose_file/parsers/services/healthcheck_parser_service.rb +73 -0
  201. data/app/services/uffizzi_core/compose_file/secrets_options_service.rb +28 -0
  202. data/app/services/uffizzi_core/compose_file/services_options/command_service.rb +18 -0
  203. data/app/services/uffizzi_core/compose_file/services_options/configs_service.rb +51 -0
  204. data/app/services/uffizzi_core/compose_file/services_options/deploy_service.rb +44 -0
  205. data/app/services/uffizzi_core/compose_file/services_options/entrypoint_service.rb +18 -0
  206. data/app/services/uffizzi_core/compose_file/services_options/env_file_service.rb +34 -0
  207. data/app/services/uffizzi_core/compose_file/services_options/environment_service.rb +20 -0
  208. data/app/services/uffizzi_core/compose_file/services_options/image_service.rb +89 -0
  209. data/app/services/uffizzi_core/compose_file/services_options/secrets_service.rb +35 -0
  210. data/app/services/uffizzi_core/compose_file/services_options_service.rb +57 -0
  211. data/app/services/uffizzi_core/compose_file/template_service.rb +55 -0
  212. data/app/services/uffizzi_core/compose_file/variables_service.rb +25 -0
  213. data/app/services/uffizzi_core/compose_file_service.rb +181 -0
  214. data/app/services/uffizzi_core/container_service.rb +42 -0
  215. data/app/services/uffizzi_core/controller_service.rb +86 -0
  216. data/app/services/uffizzi_core/credential_service.rb +44 -0
  217. data/app/services/uffizzi_core/deployment_service.rb +307 -0
  218. data/app/services/uffizzi_core/docker_hub/credential_service.rb +15 -0
  219. data/app/services/uffizzi_core/docker_hub_service.rb +77 -0
  220. data/app/services/uffizzi_core/github_container_registry/credential_service.rb +24 -0
  221. data/app/services/uffizzi_core/google/credential_service.rb +18 -0
  222. data/app/services/uffizzi_core/logs_service.rb +33 -0
  223. data/app/services/uffizzi_core/manage_activity_items_service.rb +159 -0
  224. data/app/services/uffizzi_core/project_service.rb +48 -0
  225. data/app/services/uffizzi_core/repo_service.rb +43 -0
  226. data/app/services/uffizzi_core/response_service.rb +13 -0
  227. data/app/services/uffizzi_core/starter_template_service.rb +200 -0
  228. data/app/services/uffizzi_core/template_service.rb +21 -0
  229. data/app/services/uffizzi_core/token_service.rb +19 -0
  230. data/app/services/uffizzi_core/user_access_service.rb +14 -0
  231. data/app/services/uffizzi_core/user_generator_service.rb +84 -0
  232. data/app/utils/uffizzi_core/converters.rb +33 -0
  233. data/app/validators/uffizzi_core/email_validator.rb +9 -0
  234. data/app/validators/uffizzi_core/environment_variable_list_validator.rb +15 -0
  235. data/app/validators/uffizzi_core/image_command_args_validator.rb +21 -0
  236. data/config/initializers/rswag_api.rb +15 -0
  237. data/config/initializers/rswag_ui.rb +15 -0
  238. data/config/initializers/swagger_yard.rb +17 -0
  239. data/config/locales/en.activerecord.yml +23 -0
  240. data/config/locales/en.yml +66 -0
  241. data/config/routes.rb +69 -0
  242. data/db/migrate/20220218121438_create_uffizzi_core_tables.rb +375 -0
  243. data/db/migrate/20220309110201_remove_secrets_from_projects.rb +7 -0
  244. data/db/migrate/20220310110150_create_project_secrets.rb +14 -0
  245. data/db/migrate/20220325113342_add_name_to_uffizzi_containers.rb +7 -0
  246. data/db/migrate/20220329123323_rename_project_secrets_to_secrets.rb +7 -0
  247. data/db/migrate/20220329124542_add_resource_to_secrets.rb +7 -0
  248. data/db/migrate/20220329143241_remove_project_ref_from_secrets.rb +7 -0
  249. data/db/migrate/20220419074956_add_health_check_to_containers.rb +7 -0
  250. data/db/migrate/20220525113412_rename_name_to_uffizzi_containers.rb +7 -0
  251. data/db/seeds.rb +16 -0
  252. data/lib/tasks/uffizzi_core_tasks.rake +19 -0
  253. data/lib/uffizzi_core/engine.rb +15 -0
  254. data/lib/uffizzi_core/version.rb +5 -0
  255. data/lib/uffizzi_core.rb +61 -0
  256. data/swagger/v1/swagger.json +1659 -0
  257. metadata +966 -0
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::ConfigsService
4
+ class << self
5
+ def parse(configs, global_configs_data)
6
+ return [] if configs.nil?
7
+
8
+ configs.map do |config|
9
+ config_data = case config
10
+ when String
11
+ process_short_syntax(config, global_configs_data)
12
+ when Hash
13
+ process_long_syntax(config, global_configs_data)
14
+ else
15
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :configs)
16
+ end
17
+
18
+ config_data
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def process_short_syntax(config_name, global_configs_data)
25
+ global_config = find_global_config!(config_name, global_configs_data)
26
+
27
+ {
28
+ source: UffizziCore::ComposeFile::ConfigOptionService.prepare_file_path_value(global_config[:config_file]),
29
+ target: global_config[:config_file],
30
+ }
31
+ end
32
+
33
+ def process_long_syntax(config_data, global_configs_data)
34
+ global_config = find_global_config!(config_data['source'], global_configs_data)
35
+ target = config_data['target'].blank? ? global_config[:config_file] : config_data['target']
36
+
37
+ {
38
+ source: UffizziCore::ComposeFile::ConfigOptionService.prepare_file_path_value(global_config[:config_file]),
39
+ target: target,
40
+ }
41
+ end
42
+
43
+ def find_global_config!(config_name, global_configs_data)
44
+ detected_config = global_configs_data.detect { |global_config_data| global_config_data[:config_name] == config_name }
45
+
46
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.global_config_not_found', config: config_name) if detected_config.nil?
47
+
48
+ detected_config
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::DeployService
4
+ class << self
5
+ def parse(deploy_data)
6
+ return {} if deploy_data.blank?
7
+
8
+ auto = prepare_deploy_auto(deploy_data)
9
+ memory = prepare_memory(deploy_data)
10
+
11
+ {
12
+ auto: auto,
13
+ memory: memory,
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ def prepare_deploy_auto(deploy_data)
20
+ auto = deploy_data['x-uffizzi-auto-deploy-updates']
21
+ return auto if auto.nil? || auto.in?([true, false])
22
+
23
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_bool_value', field: :auto, value: auto)
24
+ end
25
+
26
+ def prepare_memory(deploy_data)
27
+ memory = deploy_data.dig('resources', 'limits', 'memory')
28
+ return nil if memory.blank?
29
+
30
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_memory_type', value: memory) unless memory.is_a?(String)
31
+
32
+ value, postfix = memory.scan(/^([0-9]+)([a-zA-Z]+)$/).flatten
33
+
34
+ if postfix.nil? || !Settings.compose.memory_postfixes.include?(postfix.downcase)
35
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_memory_postfix', value: memory)
36
+ end
37
+
38
+ {
39
+ value: value.to_i,
40
+ postfix: postfix.downcase,
41
+ }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::EntrypointService
4
+ class << self
5
+ def parse(entrypoint_data)
6
+ return nil if entrypoint_data.blank?
7
+
8
+ case entrypoint_data
9
+ when String
10
+ [entrypoint_data]
11
+ when Array
12
+ entrypoint_data
13
+ else
14
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :entrypoint)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::EnvFileService
4
+ class << self
5
+ def parse(env_file)
6
+ env_files = case env_file
7
+ when String
8
+ [prepare_file_path(env_file)]
9
+ when Array
10
+ env_file.map { |env_file_path| prepare_file_path(env_file_path) }
11
+ else
12
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :env_file)
13
+ end
14
+
15
+ check_duplicates(env_files)
16
+
17
+ env_files
18
+ end
19
+
20
+ private
21
+
22
+ def prepare_file_path(env_file_path)
23
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.empty_env_file') if env_file_path.blank?
24
+
25
+ UffizziCore::ComposeFile::ConfigOptionService.prepare_file_path_value(env_file_path)
26
+ end
27
+
28
+ def check_duplicates(env_files)
29
+ return if env_files.uniq.length == env_files.length
30
+
31
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.env_file_duplicates', values: env_files)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::EnvironmentService
4
+ extend UffizziCore::ComposeFile::VariablesService
5
+
6
+ class << self
7
+ def parse(environment)
8
+ return [] if environment.blank?
9
+
10
+ case environment
11
+ when Array
12
+ environment.map { |variable| parse_variable_from_string(variable) }
13
+ when Hash
14
+ environment.to_a.map { |variable| parse_variable_from_array(variable) }
15
+ else
16
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :environment)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::ImageService
4
+ class << self
5
+ def parse(image)
6
+ return {} if image.blank?
7
+
8
+ image_parts = image.downcase.split(':')
9
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_image_value', value: image) if image_parts.count > 2
10
+
11
+ image_name, tag = image_parts
12
+ tag = Settings.compose.default_tag if tag.blank?
13
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_image_value', value: image) if image_name.blank?
14
+
15
+ if valid_image_url?(image_name)
16
+ url, namespace, name = parse_image_url(image_name)
17
+ else
18
+ namespace, name = parse_docker_hub_image(image_name)
19
+ end
20
+
21
+ {
22
+ registry_url: url,
23
+ namespace: namespace,
24
+ name: name,
25
+ tag: tag,
26
+ }
27
+ end
28
+
29
+ private
30
+
31
+ def valid_image_url?(image_name)
32
+ url = prepare_image_url(image_name)
33
+
34
+ URI(url).host.present? && URI(url).host =~ /\w+\.\w+/ && URI(url).path.present?
35
+ end
36
+
37
+ def prepare_image_url(image_name)
38
+ if image_name.start_with?('https://')
39
+ image_name
40
+ else
41
+ "https://#{image_name}"
42
+ end
43
+ end
44
+
45
+ def parse_image_url(image_name)
46
+ prepared_url = prepare_image_url(image_name)
47
+
48
+ uri = URI(prepared_url)
49
+ url = uri.host
50
+ path = uri.path.delete_suffix('/').delete_prefix('/')
51
+
52
+ namespace, name = parse_image_path(path)
53
+
54
+ [url, namespace, name]
55
+ end
56
+
57
+ def parse_image_path(path)
58
+ path_parts = path.split('/', 2)
59
+
60
+ if path_parts.count == 1
61
+ namespace = nil
62
+ name = path_parts.first
63
+ else
64
+ namespace = path_parts.first
65
+ name = path_parts.last
66
+ end
67
+
68
+ [namespace, name]
69
+ end
70
+
71
+ def parse_docker_hub_image(image_name)
72
+ if contains_account_name?(image_name)
73
+ namespace = image_name.split('/').first
74
+ name = image_name.split('/', 2).last.delete_suffix('/')
75
+ else
76
+ namespace = Settings.docker_hub.public_namespace
77
+ name = image_name
78
+ end
79
+
80
+ [namespace, name]
81
+ end
82
+
83
+ def contains_account_name?(image_name)
84
+ image_name_parts = image_name.split('/')
85
+
86
+ image_name_parts.count > 1
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::SecretsService
4
+ class << self
5
+ def parse(secrets, global_secrets_data)
6
+ return [] if secrets.nil?
7
+
8
+ secrets.map do |secret|
9
+ variable_name = if secret.is_a?(String)
10
+ process_short_syntax(secret, global_secrets_data)
11
+ else
12
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :secrets)
13
+ end
14
+
15
+ variable_name
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def process_short_syntax(secret_name, global_secrets_data)
22
+ global_secret = find_global_secret!(secret_name, global_secrets_data)
23
+
24
+ global_secret[:secret_variable]
25
+ end
26
+
27
+ def find_global_secret!(secret_name, global_secrets_data)
28
+ detected_secret = global_secrets_data.detect { |global_secret_data| global_secret_data[:secret_name] == secret_name }
29
+ error_message = I18n.t('compose.global_secret_not_found', secret: secret_name)
30
+ raise UffizziCore::ComposeFile::ParseError, error_message if detected_secret.nil?
31
+
32
+ detected_secret
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptionsService
4
+ class << self
5
+ def parse(services, global_configs_data, global_secrets_data, compose_payload)
6
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.no_services') if services.nil? || services.keys.empty?
7
+
8
+ services.keys.map do |service|
9
+ service_data = prepare_service_data(service, services.fetch(service), global_configs_data, global_secrets_data, compose_payload)
10
+
11
+ if service_data[:image].blank? && service_data[:build].blank?
12
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.image_build_no_specified', value: service)
13
+ end
14
+
15
+ service_data
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def prepare_service_data(service_name, service_data, global_configs_data, global_secrets_data, _compose_payload)
22
+ options_data = {}
23
+ service_data.each_pair do |key, value|
24
+ service_key = key.to_sym
25
+
26
+ options_data[service_key] = case service_key
27
+ when :image
28
+ UffizziCore::ComposeFile::ServicesOptions::ImageService.parse(value)
29
+ when :build
30
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.not_implemented', option: :build)
31
+ when :env_file
32
+ UffizziCore::ComposeFile::ServicesOptions::EnvFileService.parse(value)
33
+ when :environment
34
+ UffizziCore::ComposeFile::ServicesOptions::EnvironmentService.parse(value)
35
+ when :configs
36
+ UffizziCore::ComposeFile::ServicesOptions::ConfigsService.parse(value, global_configs_data)
37
+ when :secrets
38
+ UffizziCore::ComposeFile::ServicesOptions::SecretsService.parse(value, global_secrets_data)
39
+ when :deploy
40
+ UffizziCore::ComposeFile::ServicesOptions::DeployService.parse(value)
41
+ when :entrypoint
42
+ UffizziCore::ComposeFile::ServicesOptions::EntrypointService.parse(value)
43
+ when :command
44
+ UffizziCore::ComposeFile::ServicesOptions::CommandService.parse(value)
45
+ when :healthcheck
46
+ UffizziCore::ComposeFile::Parsers::Services::HealthcheckParserService.parse(value)
47
+ when :'x-uffizzi-continuous-preview', :'x-uffizzi-continuous-previews'
48
+ UffizziCore::ComposeFile::ContinuousPreviewOptionsService.parse(value)
49
+ end
50
+ end
51
+
52
+ options_data[:container_name] = service_name
53
+
54
+ options_data
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::TemplateService
4
+ def initialize(cli_form, project, user)
5
+ @project = project
6
+ @user = user
7
+ @compose_dependencies = cli_form.compose_dependencies
8
+ @compose_data = cli_form.compose_data
9
+ @compose_repositories = cli_form.compose_repositories
10
+ end
11
+
12
+ def create_template(compose_file_form)
13
+ compose_file_template_form = build_compose_file_template_form(compose_file_form)
14
+ return compose_file_template_form.errors if compose_file_template_form.invalid?
15
+
16
+ template_form = build_template_form(compose_file_form, compose_file_template_form)
17
+ return template_form.errors if template_form.invalid?
18
+
19
+ template_form.save
20
+
21
+ nil
22
+ end
23
+
24
+ private
25
+
26
+ def build_compose_file_template_form(compose_file_form)
27
+ credentials = @project.account.credentials
28
+ compose_file_template_form = UffizziCore::Api::Cli::V1::ComposeFile::TemplateForm.new
29
+ compose_file_template_form.compose_data = @compose_data
30
+ compose_file_template_form.source = compose_file_form.source
31
+ compose_file_template_form.credentials = credentials
32
+ compose_file_template_form.project = @project
33
+ compose_file_template_form.user = @user
34
+ compose_file_template_form.compose_dependencies = @compose_dependencies
35
+ compose_file_template_form.compose_repositories = @compose_repositories
36
+ compose_file_template_form.assign_template_attributes!
37
+
38
+ compose_file_template_form
39
+ end
40
+
41
+ def build_template_form(compose_file_form, compose_file_template_form)
42
+ attributes = compose_file_template_form.template_attributes
43
+ source = compose_file_template_form.source
44
+ template = compose_file_form.template
45
+ template = @project.templates.find_or_initialize_by(name: source) if !template.present?
46
+ template.assign_attributes(attributes)
47
+ template_form = template.becomes(UffizziCore::Api::Cli::V1::Template::CreateForm)
48
+ template_form.project = @project
49
+ template_form.added_by = @user
50
+ template_form.compose_file = compose_file_form
51
+ template_form.creation_source = UffizziCore::Template.creation_source.compose_file
52
+
53
+ template_form
54
+ end
55
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::ComposeFile::VariablesService
4
+ def parse_variable_from_string(str)
5
+ variable_parts = str.split('=', 2)
6
+
7
+ parse_variable_from_array(variable_parts)
8
+ end
9
+
10
+ def parse_variable_from_array(arr)
11
+ name = arr.first.to_s
12
+ value = arr.last.to_s
13
+
14
+ build_variable(name, value)
15
+ end
16
+
17
+ def build_variable(name, value)
18
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.no_variable_name', name: name, value: value) if name.blank?
19
+
20
+ {
21
+ name: name,
22
+ value: value,
23
+ }
24
+ end
25
+ end
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::ComposeFileService
4
+ class << self
5
+ def create(params, kind)
6
+ compose_file_form = create_compose_form(params, kind)
7
+
8
+ process_compose_file(compose_file_form, params)
9
+ end
10
+
11
+ def update(compose_file, params)
12
+ compose_file_form = create_update_compose_form(compose_file, params)
13
+
14
+ process_compose_file(compose_file_form, params)
15
+ end
16
+
17
+ def parse(compose_content, compose_payload = {})
18
+ compose_data = load_compose_data(compose_content)
19
+ check_config_options_format(compose_data)
20
+ configs_data = UffizziCore::ComposeFile::ConfigsOptionsService.parse(compose_data['configs'])
21
+ secrets_data = UffizziCore::ComposeFile::SecretsOptionsService.parse(compose_data['secrets'])
22
+ containers_data = UffizziCore::ComposeFile::ServicesOptionsService.parse(compose_data['services'], configs_data, secrets_data,
23
+ compose_payload)
24
+
25
+ continuous_preview_option = UffizziCore::ComposeFile::ConfigOptionService.continuous_preview_option(compose_data)
26
+ continuous_preview_data = UffizziCore::ComposeFile::ContinuousPreviewOptionsService.parse(continuous_preview_option)
27
+
28
+ ingress_option = UffizziCore::ComposeFile::ConfigOptionService.ingress_option(compose_data)
29
+ ingress_data = UffizziCore::ComposeFile::IngressOptionsService.parse(ingress_option, compose_data['services'])
30
+
31
+ {
32
+ containers: containers_data,
33
+ ingress: ingress_data,
34
+ continuous_preview: continuous_preview_data,
35
+ }
36
+ end
37
+
38
+ def build_template_attributes(compose_data, source, credentials, project, compose_dependencies = [], compose_repositories = [])
39
+ builder = UffizziCore::ComposeFile::Builders::TemplateBuilderService.new(credentials, project, compose_repositories)
40
+
41
+ builder.build_attributes(compose_data, compose_dependencies, source)
42
+ end
43
+
44
+ def containers_credentials(compose_data, credentials)
45
+ containers = compose_data[:containers]
46
+ detected_credentials = containers.map do |container|
47
+ UffizziCore::ComposeFile::ContainerService.credential_for_container(container, credentials)
48
+ end
49
+
50
+ result = []
51
+ detected_credentials.compact
52
+ .group_by { |credential| credential[:id] }
53
+ .each_pair { |_id, value| result << value.first }
54
+ result
55
+ end
56
+
57
+ def has_secret?(compose_file, secret)
58
+ containers = compose_file.template.payload['containers_attributes']
59
+
60
+ containers.any? { |container| UffizziCore::ComposeFile::ContainerService.has_secret?(container, secret) }
61
+ end
62
+
63
+ def update_secret!(compose_file, secret)
64
+ compose_file.template.payload['containers_attributes'].map do |container|
65
+ if UffizziCore::ComposeFile::ContainerService.has_secret?(container, secret)
66
+ container = UffizziCore::ComposeFile::ContainerService.update_secret(container, secret)
67
+ end
68
+
69
+ container
70
+ end
71
+
72
+ compose_file.template.save!
73
+
74
+ compose_file
75
+ end
76
+
77
+ def secrets_valid?(compose_file, secrets)
78
+ secret_names = secrets.pluck('name')
79
+
80
+ compose_file.template.payload['containers_attributes'].all? do |container|
81
+ container['secret_variables'].all? { |secret| secret_names.include?(secret['name']) }
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def process_compose_file(compose_file_form, params)
88
+ cli_form = UffizziCore::Api::Cli::V1::ComposeFile::CliForm.new
89
+ cli_form.content = compose_file_form.content
90
+ return [compose_file_form, cli_form.errors] if cli_form.invalid?
91
+
92
+ dependencies = params[:dependencies].to_a
93
+ compose_data = cli_form.compose_data
94
+ compose_dependencies = build_compose_dependecies(compose_data, compose_file_form.path, dependencies)
95
+ cli_form.compose_dependencies = compose_dependencies
96
+
97
+ persist!(compose_file_form, cli_form)
98
+ end
99
+
100
+ def create_compose_form(params, kind)
101
+ compose_file_params = params[:compose_file_params]
102
+ compose_file_form = UffizziCore::Api::Cli::V1::ComposeFile::CreateForm.new(compose_file_params)
103
+ compose_file_form.project = params[:project]
104
+ compose_file_form.added_by = params[:user]
105
+ compose_file_form.content = compose_file_params[:content]
106
+ compose_file_form.kind = kind
107
+ payload_dependencies = prepare_compose_file_dependencies(params[:dependencies])
108
+ compose_file_form.payload['dependencies'] = payload_dependencies
109
+
110
+ compose_file_form
111
+ end
112
+
113
+ def create_update_compose_form(compose_file, params)
114
+ compose_file_form = compose_file.becomes(UffizziCore::Api::Cli::V1::ComposeFile::UpdateForm)
115
+ compose_file_params = params[:compose_file_params]
116
+ compose_file_form.assign_attributes(compose_file_params)
117
+ payload_dependencies = prepare_compose_file_dependencies(params[:dependencies])
118
+ compose_file_form.payload['dependencies'] = payload_dependencies
119
+
120
+ compose_file_form
121
+ end
122
+
123
+ def build_compose_dependecies(compose_data, compose_path, dependencies)
124
+ return [] if dependencies.empty?
125
+
126
+ UffizziCore::ComposeFile::DependenciesService.build_dependencies(compose_data, compose_path, dependencies)
127
+ end
128
+
129
+ def prepare_compose_file_dependencies(compose_dependencies)
130
+ compose_dependencies.map do |dependency|
131
+ {
132
+ path: dependency[:path],
133
+ }
134
+ end
135
+ end
136
+
137
+ def persist!(compose_file_form, cli_form)
138
+ errors = []
139
+ ActiveRecord::Base.transaction do
140
+ if !compose_file_form.save
141
+ errors = compose_file_form.errors
142
+ raise ActiveRecord::Rollback
143
+ end
144
+
145
+ config_files_service = UffizziCore::ComposeFile::ConfigFilesService.new(compose_file_form)
146
+ errors = config_files_service.create_config_files(cli_form.compose_dependencies)
147
+ raise ActiveRecord::Rollback if errors.present?
148
+
149
+ project = compose_file_form.project
150
+ user = compose_file_form.added_by
151
+ template_service = UffizziCore::ComposeFile::TemplateService.new(cli_form, project, user)
152
+ errors = template_service.create_template(compose_file_form)
153
+
154
+ raise ActiveRecord::Rollback if errors.present?
155
+ end
156
+ [compose_file_form, errors]
157
+ end
158
+
159
+ def load_compose_data(compose_content)
160
+ begin
161
+ compose_data = YAML.safe_load(compose_content, aliases: true)
162
+ rescue Psych::SyntaxError
163
+ raise UffizziCore::ComposeFile::ParseError, 'Invalid compose file'
164
+ end
165
+
166
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.unsupported_file') if compose_data.nil?
167
+
168
+ compose_data
169
+ end
170
+
171
+ def check_config_options_format(compose_data)
172
+ options = UffizziCore::ComposeFile::ConfigOptionService.config_options(compose_data)
173
+
174
+ options.each do |option|
175
+ next if UffizziCore::ComposeFile::ConfigOptionService.valid_option_format?(option)
176
+
177
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_config_option', value: option)
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ContainerService
4
+ class << self
5
+ def pod_name(container)
6
+ return container.controller_name if container.controller_name.present?
7
+
8
+ formatted_name = container.image_name
9
+ formatted_name.parameterize.gsub('_', '-')
10
+ end
11
+
12
+ def target_port_value(container)
13
+ container.port
14
+ end
15
+
16
+ def defines_env?(container, name)
17
+ return false if container.variables.nil?
18
+
19
+ container.variables.select { |v| v['name'].downcase.to_sym == name.to_sym }.any?
20
+ end
21
+
22
+ def continuously_deploy_enabled?(container)
23
+ container.aasm(:continuously_deploy).current_state == UffizziCore::Container::STATE_ENABLED
24
+ end
25
+
26
+ def valid_memory_limit?(container)
27
+ max_memory_limit = container.deployment.project.account.container_memory_limit
28
+ container_memory_limit = container.memory_limit
29
+ return true if max_memory_limit.nil? || container_memory_limit.nil?
30
+
31
+ container_memory_limit <= max_memory_limit
32
+ end
33
+
34
+ def valid_memory_request?(container)
35
+ max_memory_limit = container.deployment.project.account.container_memory_limit
36
+ container_memory_request = container.memory_request
37
+ return true if max_memory_limit.nil? || container_memory_request.nil?
38
+
39
+ container_memory_request <= max_memory_limit
40
+ end
41
+ end
42
+ end