uffizzi-core 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::ControllerService
4
+ class << self
5
+ def apply_config_file(deployment, config_file)
6
+ body = {
7
+ config_file: UffizziCore::Controller::ApplyConfigFile::ConfigFileSerializer.new(config_file).as_json,
8
+ }
9
+
10
+ controller_client.apply_config_file(deployment_id: deployment.id, config_file_id: config_file.id, body: body)
11
+ end
12
+
13
+ def create_deployment(deployment)
14
+ body = UffizziCore::Controller::CreateDeployment::DeploymentSerializer.new(deployment).as_json
15
+ controller_client.create_deployment(deployment_id: deployment.id, body: body)
16
+ end
17
+
18
+ def update_deployment(deployment)
19
+ body = UffizziCore::Controller::UpdateDeployment::DeploymentSerializer.new(deployment).as_json
20
+ controller_client.update_deployment(deployment_id: deployment.id, body: body)
21
+ end
22
+
23
+ def delete_deployment(deployment_id)
24
+ controller_client.delete_deployment(deployment_id: deployment_id)
25
+ end
26
+
27
+ def apply_credential(deployment, credential)
28
+ image = if credential.github_container_registry?
29
+ deployment.containers.by_repo_type(UffizziCore::Repo::GithubContainerRegistry.name).first&.image
30
+ end
31
+
32
+ options = { image: image }
33
+
34
+ body = UffizziCore::Controller::CreateCredential::CredentialSerializer.new(credential, options).as_json
35
+ controller_client.apply_credential(deployment_id: deployment.id, body: body)
36
+ end
37
+
38
+ def delete_credential(deployment, credential)
39
+ controller_client.delete_credential(deployment_id: deployment.id, credential_id: credential.id)
40
+ end
41
+
42
+ def deploy_containers(deployment, containers)
43
+ containers = containers.map do |container|
44
+ UffizziCore::Controller::DeployContainers::ContainerSerializer.new(container).as_json(include: '**')
45
+ end
46
+ credentials = deployment.credentials.deployable.map do |credential|
47
+ UffizziCore::Controller::DeployContainers::CredentialSerializer.new(credential).as_json
48
+ end
49
+
50
+ body = {
51
+ containers: containers,
52
+ credentials: credentials,
53
+ deployment_url: UffizziCore::DeploymentService.build_preview_url(deployment),
54
+ }
55
+
56
+ controller_client.deploy_containers(deployment_id: deployment.id, body: body)
57
+ end
58
+
59
+ def deployment_exists?(deployment)
60
+ controller_client.deployment(deployment_id: deployment.id).code == 200
61
+ end
62
+
63
+ def fetch_deployment_events(deployment)
64
+ request_events(deployment) || []
65
+ end
66
+
67
+ def fetch_pods(deployment)
68
+ pods = controller_client.deployment_containers(deployment_id: deployment.id).result || []
69
+ pods.filter { |pod| pod.metadata.name.start_with?(Settings.controller.namespace_prefix) }
70
+ end
71
+
72
+ def fetch_namespace(deployment)
73
+ controller_client.deployment(deployment_id: deployment.id).result || nil
74
+ end
75
+
76
+ private
77
+
78
+ def request_events(deployment)
79
+ controller_client.deployment_containers_events(deployment_id: deployment.id)
80
+ end
81
+
82
+ def controller_client
83
+ UffizziCore::ControllerClient.new
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::CredentialService
4
+ class << self
5
+ def correct_credentials?(credential)
6
+ status = case credential.type
7
+ when UffizziCore::Credential::DockerHub.name
8
+ UffizziCore::DockerHub::CredentialService.credential_correct?(credential)
9
+ when UffizziCore::Credential::GithubContainerRegistry.name
10
+ UffizziCore::GithubContainerRegistry::CredentialService.credential_correct?(credential)
11
+ when UffizziCore::Credential::Azure.name
12
+ UffizziCore::Azure::CredentialService.credential_correct?(credential)
13
+ when UffizziCore::Credential::Google.name
14
+ UffizziCore::Google::CredentialService.credential_correct?(credential)
15
+ when UffizziCore::Credential::Amazon.name
16
+ UffizziCore::Amazon::CredentialService.credential_correct?(credential)
17
+ else
18
+ false
19
+ end
20
+
21
+ if credential.persisted? && credential.active? && !status
22
+ Rails.logger.warn("broken credentials, credential_correct? credential_id=#{credential.id}")
23
+ credential.unauthorize!
24
+ end
25
+
26
+ status
27
+ end
28
+
29
+ def update_expired_credentials
30
+ currect_date = DateTime.now
31
+ credentials = UffizziCore::Credential::Amazon.active.where('updated_at < ?', currect_date - 10.hours)
32
+
33
+ credentials.each do |credential|
34
+ deployments = UffizziCore::Deployment.where(project_id: credential.account.projects.select(:id)).with_amazon_repos
35
+
36
+ deployments.each do |deployment|
37
+ UffizziCore::Deployment::CreateCredentialJob.perform_async(deployment.id, credential.id)
38
+ end
39
+
40
+ credential.update(updated_at: currect_date)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,307 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::DeploymentService
4
+ MIN_TARGET_PORT_RANGE = 37_000
5
+ MAX_TARGET_PORT_RANGE = 39_999
6
+
7
+ DEPLOYMENT_PROCESS_STATUSES = {
8
+ building: :building,
9
+ deploying: :deploying,
10
+ failed: :failed,
11
+ queued: :queued,
12
+ }.freeze
13
+
14
+ class << self
15
+ def create_from_compose(compose_file, project, user)
16
+ deployment_attributes = ActionController::Parameters.new(compose_file.template.payload)
17
+ deployment_form = UffizziCore::Api::Cli::V1::Deployment::CreateForm.new(deployment_attributes)
18
+ deployment_form.assign_dependences!(project, user)
19
+ deployment_form.compose_file = compose_file
20
+ deployment_form.creation_source = UffizziCore::Deployment.creation_source.compose_file_manual
21
+
22
+ if deployment_form.save
23
+ update_subdomain!(deployment_form)
24
+
25
+ UffizziCore::Deployment::CreateJob.perform_async(deployment_form.id)
26
+ UffizziCore::Deployment::CreateWebhooksJob.perform_async(deployment_form.id)
27
+ end
28
+
29
+ deployment_form
30
+ end
31
+
32
+ def update_from_compose(compose_file, project, user, deployment_id)
33
+ deployment_attributes = ActionController::Parameters.new(compose_file.template.payload)
34
+
35
+ deployment_form = UffizziCore::Api::Cli::V1::Deployment::UpdateForm.new(deployment_attributes)
36
+ deployment_form.assign_dependences!(project, user)
37
+ deployment_form.compose_file = compose_file
38
+
39
+ if deployment_form.valid?
40
+ deployment = UffizziCore::Deployment.find(deployment_id)
41
+ deployment.containers.destroy_all
42
+ deployment.compose_file.destroy if deployment.compose_file.kind.temporary?
43
+ deployment.update!(containers: deployment_form.containers, compose_file_id: compose_file.id)
44
+
45
+ return deployment
46
+ end
47
+
48
+ deployment_form
49
+ end
50
+
51
+ def deploy_containers(deployment, repeated = false)
52
+ if !repeated
53
+ create_activity_items(deployment)
54
+ update_controller_container_names(deployment)
55
+ end
56
+
57
+ case deployment_process_status(deployment)
58
+ when DEPLOYMENT_PROCESS_STATUSES[:building]
59
+ Rails.logger.info("DEPLOYMENT_PROCESS deployment_id=#{deployment.id} repeat deploy_containers")
60
+ UffizziCore::Deployment::DeployContainersJob.perform_in(1.minute, deployment.id, true)
61
+ when DEPLOYMENT_PROCESS_STATUSES[:deploying]
62
+ Rails.logger.info("DEPLOYMENT_PROCESS deployment_id=#{deployment.id} start deploying into controller")
63
+
64
+ containers = deployment.active_containers
65
+ containers = add_default_deployment_variables!(containers)
66
+
67
+ UffizziCore::ControllerService.deploy_containers(deployment, containers)
68
+ else
69
+ Rails.logger.info("DEPLOYMENT_PROCESS deployment_id=#{deployment.id} deployment has builds errors, stopping")
70
+ end
71
+ end
72
+
73
+ def disable!(deployment)
74
+ deployment.disable!
75
+ compose_file = deployment.compose_file || deployment.template&.compose_file
76
+ return unless compose_file&.kind&.temporary?
77
+
78
+ compose_file.destroy!
79
+ end
80
+
81
+ def fail!(deployment)
82
+ deployment.fail!
83
+ compose_file = deployment.compose_file || deployment.template&.compose_file
84
+ return unless compose_file&.kind&.temporary?
85
+
86
+ compose_file.destroy!
87
+ end
88
+
89
+ def build_subdomain(deployment)
90
+ if deployment.continuous_preview_payload.present?
91
+ continuous_preview_payload = deployment.continuous_preview_payload
92
+
93
+ return build_pull_request_subdomain(deployment) if continuous_preview_payload['pull_request'].present?
94
+ return build_docker_continuous_preview_subdomain(deployment) if continuous_preview_payload['docker'].present?
95
+ end
96
+
97
+ build_default_subdomain(deployment)
98
+ end
99
+
100
+ def build_pull_request_subdomain(deployment)
101
+ project = deployment.project
102
+ continuous_preview_payload = deployment.continuous_preview_payload
103
+ pull_request_payload = continuous_preview_payload['pull_request']
104
+ repo_name = pull_request_payload['repository_full_name'].split('/').last
105
+ deployment_name = name(deployment)
106
+ subdomain = "pr#{pull_request_payload['id']}-#{deployment_name}-#{repo_name}-#{project.slug}"
107
+
108
+ format_subdomain(subdomain)
109
+ end
110
+
111
+ def build_docker_continuous_preview_subdomain(deployment)
112
+ project = deployment.project
113
+ continuous_preview_payload = deployment.continuous_preview_payload
114
+ docker_payload = continuous_preview_payload['docker']
115
+ repo_name = docker_payload['image'].split('/').last.gsub('_', '-')
116
+ image_tag = docker_payload['tag'].gsub('_', '-')
117
+ deployment_name = name(deployment)
118
+ subdomain = "#{image_tag}-#{deployment_name}-#{repo_name}-#{project.slug}"
119
+
120
+ format_subdomain(subdomain)
121
+ end
122
+
123
+ def build_default_subdomain(deployment)
124
+ deployment_name = name(deployment)
125
+ slug = deployment.project.slug.to_s
126
+ subdomain = "#{deployment_name}-#{slug}"
127
+
128
+ format_subdomain(subdomain)
129
+ end
130
+
131
+ def build_preview_url(deployment)
132
+ "#{deployment.subdomain}.#{Settings.app.managed_dns_zone}"
133
+ end
134
+
135
+ def build_deployment_url(deployment)
136
+ "#{Settings.app.managed_dns_zone}/projects/#{deployment.project_id}/deployments"
137
+ end
138
+
139
+ def all_containers_have_unique_ports?(containers)
140
+ ports = containers.map(&:port).compact
141
+ containers.empty? || ports.size == ports.uniq.size
142
+ end
143
+
144
+ def valid_containers_memory_limit?(deployment)
145
+ containers = deployment.containers
146
+ container_memory_limit = deployment.project.account.container_memory_limit
147
+ return true if container_memory_limit.nil?
148
+
149
+ containers.all? { |container| container.memory_limit <= container_memory_limit }
150
+ end
151
+
152
+ def valid_containers_memory_request?(deployment)
153
+ containers = deployment.containers
154
+ container_memory_limit = deployment.project.account.container_memory_limit
155
+ return true if container_memory_limit.nil?
156
+
157
+ containers.all? { |container| container.memory_request <= container_memory_limit }
158
+ end
159
+
160
+ def ingress_container?(containers)
161
+ containers.empty? || containers.map(&:receive_incoming_requests).count(true) == 1
162
+ end
163
+
164
+ def find_unused_port(deployment)
165
+ selected_port = nil
166
+
167
+ Timeout.timeout(20) do
168
+ loop do
169
+ selected_port = rand(MIN_TARGET_PORT_RANGE..MAX_TARGET_PORT_RANGE)
170
+
171
+ break if !deployment.containers.exists?(target_port: selected_port)
172
+ end
173
+ end
174
+
175
+ selected_port
176
+ end
177
+
178
+ def setup_ingress_container(deployment, ingress_container, port)
179
+ old_deployment_subdomain = deployment.subdomain
180
+
181
+ containers = deployment.containers.active
182
+
183
+ UffizziCore::Container.transaction do
184
+ containers.update_all(receive_incoming_requests: false, port: nil, public: false)
185
+ containers.find(ingress_container.id).update!(port: port, public: true, receive_incoming_requests: true)
186
+ end
187
+
188
+ deployment.reload
189
+
190
+ new_deployment_subdomain = build_subdomain(deployment)
191
+
192
+ if new_deployment_subdomain != old_deployment_subdomain
193
+ deployment.update(subdomain: new_deployment_subdomain)
194
+ end
195
+
196
+ UffizziCore::Deployment::DeployContainersJob.perform_async(deployment.id)
197
+ end
198
+
199
+ def name(deployment)
200
+ "deployment-#{deployment.id}"
201
+ end
202
+
203
+ def update_subdomain!(deployment)
204
+ deployment.subdomain = build_subdomain(deployment)
205
+
206
+ deployment.save!
207
+ end
208
+
209
+ def create_webhooks(deployment)
210
+ credential = deployment.project.account.credentials.docker_hub.active.first
211
+
212
+ if !deployment.containers.with_docker_hub_repo.exists? || !credential.present?
213
+ Rails.logger.info("DEPLOYMENT_PROCESS deployment_id=#{deployment.id} create_webhooks no dockerhub containers or credential")
214
+ return
215
+ end
216
+
217
+ accounts = UffizziCore::DockerHubService.accounts(credential)
218
+
219
+ deployment.containers.with_docker_hub_repo.find_each do |container|
220
+ if !accounts.include?(container.repo.namespace)
221
+ logger_message = "DEPLOYMENT_PROCESS deployment_id=#{deployment.id} no namespace(#{container.repo.namespace})
222
+ in accounts(#{accounts.inspect})"
223
+ Rails.logger.info(logger_message)
224
+ next
225
+ end
226
+
227
+ UffizziCore::Credential::DockerHub::CreateWebhookJob.perform_async(credential.id, container.image, deployment.id)
228
+ end
229
+ end
230
+
231
+ def pull_request_payload_present?(deployment)
232
+ deployment.continuous_preview_payload.present? && deployment.continuous_preview_payload['pull_request'].present?
233
+ end
234
+
235
+ def failed?(deployment)
236
+ deployment_status = deployment_process_status(deployment)
237
+
238
+ deployment_status == DEPLOYMENT_PROCESS_STATUSES[:failed]
239
+ end
240
+
241
+ private
242
+
243
+ def deployment_process_status(deployment)
244
+ containers = deployment.active_containers
245
+ activity_items = containers.map { |container| container.activity_items.order_by_id.last }.compact
246
+ events = activity_items.map { |activity_item| activity_item.events.order_by_id.last&.state }
247
+ events = events.flatten.uniq
248
+
249
+ return DEPLOYMENT_PROCESS_STATUSES[:queued] if containers.present? && events.empty?
250
+ return DEPLOYMENT_PROCESS_STATUSES[:failed] if events.include?(UffizziCore::Event.state.failed)
251
+ return DEPLOYMENT_PROCESS_STATUSES[:building] if events.include?(UffizziCore::Event.state.building)
252
+
253
+ DEPLOYMENT_PROCESS_STATUSES[:deploying]
254
+ end
255
+
256
+ def create_activity_items(deployment)
257
+ deployment.active_containers.each do |container|
258
+ repo = container.repo
259
+ activity_item = UffizziCore::ActivityItemService.create_docker_item!(repo, container)
260
+
261
+ create_default_activity_item_event(activity_item)
262
+
263
+ if UffizziCore::RepoService.credential(repo).present? && activity_item.docker?
264
+ UffizziCore::ActivityItem::Docker::UpdateDigestJob.perform_async(activity_item.id)
265
+ end
266
+ UffizziCore::Deployment::ManageDeployActivityItemJob.perform_in(5.seconds, activity_item.id)
267
+ end
268
+ end
269
+
270
+ def create_default_activity_item_event(activity_item)
271
+ activity_item.events.create(state: UffizziCore::Event.state.deploying) if activity_item.docker?
272
+ end
273
+
274
+ def update_controller_container_names(deployment)
275
+ deployment.active_containers.each do |container|
276
+ next if container.controller_name.present?
277
+
278
+ controller_name = generate_controller_container_name(container)
279
+ container.update!(controller_name: controller_name)
280
+ end
281
+ end
282
+
283
+ def generate_controller_container_name(container)
284
+ Digest::SHA256.hexdigest("#{container.id}:#{container.image}")[0, 10]
285
+ end
286
+
287
+ def add_default_deployment_variables!(containers)
288
+ containers.each do |container|
289
+ envs = []
290
+ if container.port.present? && !UffizziCore::ContainerService.defines_env?(container, 'PORT')
291
+ envs.push('name' => 'PORT', 'value' => container.target_port.to_s)
292
+ end
293
+
294
+ container.variables = [] if container.variables.nil?
295
+
296
+ container.variables.push(*envs)
297
+ end
298
+ end
299
+
300
+ def format_subdomain(full_subdomain_name)
301
+ subdomain_length_limit = Settings.deployment.subdomain.length_limit
302
+ return full_subdomain_name if full_subdomain_name.length <= subdomain_length_limit
303
+
304
+ full_subdomain_name.slice(0, subdomain_length_limit)
305
+ end
306
+ end
307
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::DockerHub::CredentialService
4
+ class << self
5
+ def credential_correct?(credential)
6
+ client(credential).authentificated?
7
+ end
8
+
9
+ private
10
+
11
+ def client(credential)
12
+ UffizziCore::DockerHubClient.new(credential)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::DockerHubService
4
+ HOOK_NAME = 'Uffizzi OpenSource Deploy Webhook'
5
+ HOOK_URL = "#{Settings.app.host}api/cli/v1/webhooks/docker_hub"
6
+ REGISTRY = 'registry-1.docker.io'
7
+
8
+ class << self
9
+ def create_webhook(credential, image)
10
+ client = user_client(credential)
11
+
12
+ webhooks_response = client.get_webhooks(slug: image, registry: REGISTRY)
13
+ Rails.logger.info("DockerHubService create_webhook get_webhooks_response=#{webhooks_response.inspect}")
14
+
15
+ return false if webhooks_response.status != 200
16
+
17
+ webhooks = webhooks_response.result['results']
18
+
19
+ webhook = webhooks.detect { |hook| hook['name'] == HOOK_NAME }
20
+
21
+ return true if !webhook.nil?
22
+
23
+ params = {
24
+ slug: image,
25
+ name: HOOK_NAME,
26
+ expect_final_callback: false,
27
+ webhooks: [{ name: HOOK_NAME, hook_url: HOOK_URL, registry: REGISTRY }],
28
+ }
29
+
30
+ response = client.create_webhook(params)
31
+
32
+ Rails.logger.info("DockerHubService create_webhook create_webhook_response=#{response.inspect} params=#{params.inspect}")
33
+
34
+ response.status == 201
35
+ end
36
+
37
+ def send_webhook_answer(callback_url)
38
+ params = { state: 'success', description: 'Successfully deployed to Uffizzi' }
39
+ public_docker_hub_client.send_webhook_answer(callback_url, params)
40
+ end
41
+
42
+ def accounts(credential)
43
+ client = user_client(credential)
44
+ response = client.accounts
45
+ Rails.logger.info("DockerHubService accounts response=#{response.inspect} credential_id=#{credential.id}")
46
+
47
+ accounts_response = response.result
48
+ accounts_response.nil? ? [] : accounts_response.namespaces
49
+ end
50
+
51
+ def user_client(credential)
52
+ if @client.nil?
53
+ @client = UffizziCore::DockerHubClient.new(credential)
54
+
55
+ unless @client.authentificated?
56
+ Rails.logger.warn("broken credentials, DockerHubService credential_id=#{credential.id}")
57
+ credential.unauthorize! unless credential.unauthorized?
58
+ end
59
+ end
60
+
61
+ @client
62
+ end
63
+
64
+ def digest(credential, image, tag)
65
+ docker_hub_client = UffizziCore::DockerHubClient.new(credential)
66
+ token = docker_hub_client.get_token(image).result.token
67
+ response = docker_hub_client.digest(image: image, tag: tag, token: token)
68
+ response.headers['docker-content-digest']
69
+ end
70
+
71
+ private
72
+
73
+ def public_docker_hub_client
74
+ @public_docker_hub_client ||= UffizziCore::DockerHubClient.new
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::GithubContainerRegistry::CredentialService
4
+ class << self
5
+ def credential_correct?(credential)
6
+ client(credential).authentificated?
7
+ rescue URI::InvalidURIError, Faraday::ConnectionFailed
8
+ false
9
+ end
10
+
11
+ def access_token(credential)
12
+ client(credential).token
13
+ rescue URI::InvalidURIError, Faraday::ConnectionFailed
14
+ false
15
+ end
16
+
17
+ private
18
+
19
+ def client(credential)
20
+ UffizziCore::GithubContainerRegistryClient.new(registry_url: credential.registry_url, username: credential.username,
21
+ password: credential.password)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Google::CredentialService
4
+ class << self
5
+ def credential_correct?(credential)
6
+ client(credential).authentificated?
7
+ rescue URI::InvalidURIError, Faraday::ConnectionFailed
8
+ false
9
+ end
10
+
11
+ private
12
+
13
+ def client(credential)
14
+ UffizziCore::GoogleRegistryClient.new(registry_url: credential.registry_url, username: credential.username,
15
+ password: credential.password)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::LogsService
4
+ NOT_ALLOWED_SYMBOLS_IN_NAME_REGEX = /[^a-zA-Z0-9-]/.freeze
5
+
6
+ class << self
7
+ def fetch_container_logs(container, query = {})
8
+ response = request_logs(container, query).result || {}
9
+ response = Hashie::Mash.new(response)
10
+ logs = response.logs || []
11
+
12
+ {
13
+ logs: logs,
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ def request_logs(container, query)
20
+ deployment = container.deployment
21
+
22
+ controller_client.deployment_container_logs(
23
+ deployment_id: deployment.id,
24
+ container_name: UffizziCore::ContainerService.pod_name(container),
25
+ limit: query[:limit],
26
+ )
27
+ end
28
+
29
+ def controller_client
30
+ UffizziCore::ControllerClient.new
31
+ end
32
+ end
33
+ end