uffizzi_core 0.1.3

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 (240) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +46 -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 +139 -0
  14. data/app/clients/uffizzi_core/github/app_client.rb +19 -0
  15. data/app/clients/uffizzi_core/github/installation_client.rb +11 -0
  16. data/app/clients/uffizzi_core/github/user_client.rb +51 -0
  17. data/app/clients/uffizzi_core/google_registry_client/request_result.rb +5 -0
  18. data/app/clients/uffizzi_core/google_registry_client.rb +42 -0
  19. data/app/contexts/uffizzi_core/base_context.rb +12 -0
  20. data/app/contexts/uffizzi_core/project_context.rb +13 -0
  21. data/app/contexts/uffizzi_core/webhooks_context.rb +9 -0
  22. data/app/controllers/concerns/uffizzi_core/auth_management.rb +23 -0
  23. data/app/controllers/concerns/uffizzi_core/authorization_concern.rb +38 -0
  24. data/app/controllers/concerns/uffizzi_core/dependency_injection_concern.rb +19 -0
  25. data/app/controllers/uffizzi_core/api/cli/v1/account/application_controller.rb +7 -0
  26. data/app/controllers/uffizzi_core/api/cli/v1/account/credentials_controller.rb +55 -0
  27. data/app/controllers/uffizzi_core/api/cli/v1/application_controller.rb +5 -0
  28. data/app/controllers/uffizzi_core/api/cli/v1/projects/application_controller.rb +11 -0
  29. data/app/controllers/uffizzi_core/api/cli/v1/projects/compose_files_controller.rb +93 -0
  30. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/activity_items_controller.rb +36 -0
  31. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/application_controller.rb +7 -0
  32. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers/application_controller.rb +8 -0
  33. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers/logs_controller.rb +27 -0
  34. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers_controller.rb +24 -0
  35. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/events_controller.rb +29 -0
  36. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments_controller.rb +148 -0
  37. data/app/controllers/uffizzi_core/api/cli/v1/projects/secrets_controller.rb +69 -0
  38. data/app/controllers/uffizzi_core/api/cli/v1/projects_controller.rb +19 -0
  39. data/app/controllers/uffizzi_core/api/cli/v1/sessions_controller.rb +43 -0
  40. data/app/controllers/uffizzi_core/application_controller.rb +51 -0
  41. data/app/errors/uffizzi_core/compose_file/build_error.rb +4 -0
  42. data/app/errors/uffizzi_core/compose_file/credential_error.rb +4 -0
  43. data/app/errors/uffizzi_core/compose_file/not_found_error.rb +4 -0
  44. data/app/errors/uffizzi_core/compose_file/parse_error.rb +4 -0
  45. data/app/errors/uffizzi_core/compose_file/secrets_error.rb +4 -0
  46. data/app/errors/uffizzi_core/deployment_not_found_error.rb +10 -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 +39 -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 +91 -0
  55. data/app/forms/uffizzi_core/api/cli/v1/project/delete_secret_form.rb +27 -0
  56. data/app/forms/uffizzi_core/api/cli/v1/project/update_form.rb +40 -0
  57. data/app/forms/uffizzi_core/api/cli/v1/session_create_form.rb +29 -0
  58. data/app/forms/uffizzi_core/api/cli/v1/template/create_form.rb +65 -0
  59. data/app/forms/uffizzi_core/application_form.rb +11 -0
  60. data/app/forms/uffizzi_core/application_form_without_active_record.rb +17 -0
  61. data/app/forms/uffizzi_core/mass_assignment_control_concern.rb +22 -0
  62. data/app/helpers/uffizzi_core/application_helper.rb +6 -0
  63. data/app/jobs/uffizzi_core/account/create_credential_job.rb +10 -0
  64. data/app/jobs/uffizzi_core/activity_item/docker/update_digest_job.rb +11 -0
  65. data/app/jobs/uffizzi_core/application_job.rb +7 -0
  66. data/app/jobs/uffizzi_core/config_file/apply_job.rb +31 -0
  67. data/app/jobs/uffizzi_core/credential/docker_hub/create_webhook_job.rb +15 -0
  68. data/app/jobs/uffizzi_core/deployment/create_credential_job.rb +32 -0
  69. data/app/jobs/uffizzi_core/deployment/create_credentials_job.rb +17 -0
  70. data/app/jobs/uffizzi_core/deployment/create_job.rb +15 -0
  71. data/app/jobs/uffizzi_core/deployment/create_webhooks_job.rb +13 -0
  72. data/app/jobs/uffizzi_core/deployment/delete_credential_job.rb +13 -0
  73. data/app/jobs/uffizzi_core/deployment/delete_job.rb +11 -0
  74. data/app/jobs/uffizzi_core/deployment/deploy_containers_job.rb +27 -0
  75. data/app/jobs/uffizzi_core/deployment/manage_deploy_activity_item_job.rb +19 -0
  76. data/app/jobs/uffizzi_core/deployment/send_github_preview_message_job.rb +13 -0
  77. data/app/lib/uffizzi_core/rbac/user_access_service.rb +21 -0
  78. data/app/mailers/uffizzi_core/application_mailer.rb +8 -0
  79. data/app/models/concerns/uffizzi_core/hashid_concern.rb +25 -0
  80. data/app/models/concerns/uffizzi_core/state_machine_concern.rb +16 -0
  81. data/app/models/uffizzi_core/account.rb +101 -0
  82. data/app/models/uffizzi_core/activity_item/docker.rb +4 -0
  83. data/app/models/uffizzi_core/activity_item/github.rb +4 -0
  84. data/app/models/uffizzi_core/activity_item/memory_limit.rb +4 -0
  85. data/app/models/uffizzi_core/activity_item.rb +58 -0
  86. data/app/models/uffizzi_core/application_record.rb +7 -0
  87. data/app/models/uffizzi_core/build.rb +39 -0
  88. data/app/models/uffizzi_core/comment.rb +16 -0
  89. data/app/models/uffizzi_core/compose_file.rb +57 -0
  90. data/app/models/uffizzi_core/config_file.rb +24 -0
  91. data/app/models/uffizzi_core/container.rb +100 -0
  92. data/app/models/uffizzi_core/container_config_file.rb +8 -0
  93. data/app/models/uffizzi_core/continuous_preview.rb +4 -0
  94. data/app/models/uffizzi_core/coupon.rb +5 -0
  95. data/app/models/uffizzi_core/credential/amazon.rb +4 -0
  96. data/app/models/uffizzi_core/credential/azure.rb +4 -0
  97. data/app/models/uffizzi_core/credential/docker_hub.rb +4 -0
  98. data/app/models/uffizzi_core/credential/github.rb +4 -0
  99. data/app/models/uffizzi_core/credential/google.rb +4 -0
  100. data/app/models/uffizzi_core/credential.rb +64 -0
  101. data/app/models/uffizzi_core/database.rb +4 -0
  102. data/app/models/uffizzi_core/database_offering.rb +4 -0
  103. data/app/models/uffizzi_core/deployment.rb +77 -0
  104. data/app/models/uffizzi_core/event.rb +13 -0
  105. data/app/models/uffizzi_core/invitation.rb +27 -0
  106. data/app/models/uffizzi_core/membership.rb +16 -0
  107. data/app/models/uffizzi_core/payment.rb +11 -0
  108. data/app/models/uffizzi_core/price.rb +9 -0
  109. data/app/models/uffizzi_core/product.rb +11 -0
  110. data/app/models/uffizzi_core/project.rb +66 -0
  111. data/app/models/uffizzi_core/rating.rb +20 -0
  112. data/app/models/uffizzi_core/repo/amazon.rb +4 -0
  113. data/app/models/uffizzi_core/repo/azure.rb +4 -0
  114. data/app/models/uffizzi_core/repo/docker_hub.rb +4 -0
  115. data/app/models/uffizzi_core/repo/github.rb +4 -0
  116. data/app/models/uffizzi_core/repo/google.rb +4 -0
  117. data/app/models/uffizzi_core/repo.rb +39 -0
  118. data/app/models/uffizzi_core/role.rb +17 -0
  119. data/app/models/uffizzi_core/template.rb +19 -0
  120. data/app/models/uffizzi_core/user.rb +62 -0
  121. data/app/models/uffizzi_core/user_project.rb +14 -0
  122. data/app/policies/uffizzi_core/api/cli/v1/account/credentials_policy.rb +11 -0
  123. data/app/policies/uffizzi_core/api/cli/v1/projects/compose_files_policy.rb +15 -0
  124. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/activity_items_policy.rb +7 -0
  125. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/containers_policy.rb +7 -0
  126. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/events_policy.rb +7 -0
  127. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments_policy.rb +23 -0
  128. data/app/policies/uffizzi_core/api/cli/v1/projects/secrets_policy.rb +15 -0
  129. data/app/policies/uffizzi_core/api/cli/v1/projects_policy.rb +7 -0
  130. data/app/policies/uffizzi_core/application_policy.rb +12 -0
  131. data/app/repositories/uffizzi_core/activity_item_repo.rb +9 -0
  132. data/app/repositories/uffizzi_core/basic_order_repo.rb +11 -0
  133. data/app/repositories/uffizzi_core/build_repo.rb +23 -0
  134. data/app/repositories/uffizzi_core/comment_repo.rb +11 -0
  135. data/app/repositories/uffizzi_core/compose_file_repo.rb +11 -0
  136. data/app/repositories/uffizzi_core/config_file_repo.rb +40 -0
  137. data/app/repositories/uffizzi_core/container_repo.rb +25 -0
  138. data/app/repositories/uffizzi_core/credential_repo.rb +36 -0
  139. data/app/repositories/uffizzi_core/deployment_repo.rb +23 -0
  140. data/app/repositories/uffizzi_core/event_repo.rb +9 -0
  141. data/app/repositories/uffizzi_core/membership_repo.rb +10 -0
  142. data/app/repositories/uffizzi_core/price_repo.rb +11 -0
  143. data/app/repositories/uffizzi_core/product_repo.rb +11 -0
  144. data/app/repositories/uffizzi_core/project_repo.rb +10 -0
  145. data/app/repositories/uffizzi_core/repo_repo.rb +10 -0
  146. data/app/repositories/uffizzi_core/template_repo.rb +87 -0
  147. data/app/repositories/uffizzi_core/usage_repo.rb +9 -0
  148. data/app/repositories/uffizzi_core/user_repo.rb +11 -0
  149. data/app/responders/uffizzi_core/json_responder.rb +13 -0
  150. data/app/serializers/uffizzi_core/api/cli/v1/account/credential_serializer.rb +9 -0
  151. data/app/serializers/uffizzi_core/api/cli/v1/project_serializer.rb +7 -0
  152. data/app/serializers/uffizzi_core/api/cli/v1/projects/compose_file_serializer.rb +7 -0
  153. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/container_serializer.rb +23 -0
  154. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/user_serializer.rb +11 -0
  155. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer.rb +74 -0
  156. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/activity_item_serializer.rb +24 -0
  157. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer/container_config_file_serializer/config_file_serializer.rb +6 -0
  158. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer/container_config_file_serializer.rb +7 -0
  159. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer.rb +30 -0
  160. data/app/serializers/uffizzi_core/api/cli/v1/user_serializer/account_serializer.rb +5 -0
  161. data/app/serializers/uffizzi_core/api/cli/v1/user_serializer.rb +7 -0
  162. data/app/serializers/uffizzi_core/base_serializer.rb +7 -0
  163. data/app/serializers/uffizzi_core/controller/create_credential/credential_serializer.rb +17 -0
  164. data/app/serializers/uffizzi_core/controller/create_deployment/deployment_serializer.rb +5 -0
  165. data/app/serializers/uffizzi_core/controller/deploy_containers/container_serializer.rb +53 -0
  166. data/app/serializers/uffizzi_core/controller/deploy_containers/credential_serializer.rb +5 -0
  167. data/app/services/uffizzi_core/account_service.rb +21 -0
  168. data/app/services/uffizzi_core/activity_item_service.rb +98 -0
  169. data/app/services/uffizzi_core/amazon/credential_service.rb +31 -0
  170. data/app/services/uffizzi_core/amazon_service.rb +45 -0
  171. data/app/services/uffizzi_core/azure/credential_service.rb +18 -0
  172. data/app/services/uffizzi_core/cli/compose_file_service.rb +203 -0
  173. data/app/services/uffizzi_core/compose_file/builders/config_files_builder_service.rb +31 -0
  174. data/app/services/uffizzi_core/compose_file/builders/container_builder_service.rb +225 -0
  175. data/app/services/uffizzi_core/compose_file/builders/docker_repo_builder_service.rb +25 -0
  176. data/app/services/uffizzi_core/compose_file/builders/github_repo_builder_service.rb +59 -0
  177. data/app/services/uffizzi_core/compose_file/builders/template_builder_service.rb +45 -0
  178. data/app/services/uffizzi_core/compose_file/builders/variables_builder_service.rb +58 -0
  179. data/app/services/uffizzi_core/compose_file/config_files_service.rb +52 -0
  180. data/app/services/uffizzi_core/compose_file/config_option_service.rb +37 -0
  181. data/app/services/uffizzi_core/compose_file/configs_options_service.rb +26 -0
  182. data/app/services/uffizzi_core/compose_file/container_service.rb +64 -0
  183. data/app/services/uffizzi_core/compose_file/continuous_preview_options_service.rb +57 -0
  184. data/app/services/uffizzi_core/compose_file/dependencies_service.rb +55 -0
  185. data/app/services/uffizzi_core/compose_file/errors_service.rb +46 -0
  186. data/app/services/uffizzi_core/compose_file/github_dependencies_service.rb +38 -0
  187. data/app/services/uffizzi_core/compose_file/ingress_options_service.rb +49 -0
  188. data/app/services/uffizzi_core/compose_file/secrets_options_service.rb +28 -0
  189. data/app/services/uffizzi_core/compose_file/services_options/build_service.rb +93 -0
  190. data/app/services/uffizzi_core/compose_file/services_options/command_service.rb +18 -0
  191. data/app/services/uffizzi_core/compose_file/services_options/configs_service.rb +51 -0
  192. data/app/services/uffizzi_core/compose_file/services_options/deploy_service.rb +44 -0
  193. data/app/services/uffizzi_core/compose_file/services_options/entrypoint_service.rb +18 -0
  194. data/app/services/uffizzi_core/compose_file/services_options/env_file_service.rb +34 -0
  195. data/app/services/uffizzi_core/compose_file/services_options/environment_service.rb +20 -0
  196. data/app/services/uffizzi_core/compose_file/services_options/image_service.rb +89 -0
  197. data/app/services/uffizzi_core/compose_file/services_options/secrets_service.rb +35 -0
  198. data/app/services/uffizzi_core/compose_file/services_options_service.rb +55 -0
  199. data/app/services/uffizzi_core/compose_file/template_service.rb +55 -0
  200. data/app/services/uffizzi_core/compose_file/update_service.rb +29 -0
  201. data/app/services/uffizzi_core/compose_file/variables_service.rb +25 -0
  202. data/app/services/uffizzi_core/compose_file_service.rb +33 -0
  203. data/app/services/uffizzi_core/container_service.rb +57 -0
  204. data/app/services/uffizzi_core/controller_service.rb +80 -0
  205. data/app/services/uffizzi_core/credential_service.rb +44 -0
  206. data/app/services/uffizzi_core/deployment_service.rb +274 -0
  207. data/app/services/uffizzi_core/docker_hub/credential_service.rb +15 -0
  208. data/app/services/uffizzi_core/docker_hub_service.rb +77 -0
  209. data/app/services/uffizzi_core/github/app_service.rb +51 -0
  210. data/app/services/uffizzi_core/github/credential_service.rb +124 -0
  211. data/app/services/uffizzi_core/github/message_service.rb +20 -0
  212. data/app/services/uffizzi_core/github_service.rb +28 -0
  213. data/app/services/uffizzi_core/google/credential_service.rb +18 -0
  214. data/app/services/uffizzi_core/logs_service.rb +33 -0
  215. data/app/services/uffizzi_core/manage_activity_items_service.rb +166 -0
  216. data/app/services/uffizzi_core/project_service.rb +38 -0
  217. data/app/services/uffizzi_core/repo_service.rb +178 -0
  218. data/app/services/uffizzi_core/response_service.rb +13 -0
  219. data/app/services/uffizzi_core/template_service.rb +21 -0
  220. data/app/services/uffizzi_core/token_service.rb +19 -0
  221. data/app/services/uffizzi_core/user_access_service.rb +14 -0
  222. data/app/utils/uffizzi_core/converters.rb +33 -0
  223. data/app/validators/uffizzi_core/email_validator.rb +9 -0
  224. data/app/validators/uffizzi_core/environment_variable_list_validator.rb +15 -0
  225. data/app/validators/uffizzi_core/image_command_args_validator.rb +21 -0
  226. data/config/initializers/rswag_api.rb +15 -0
  227. data/config/initializers/rswag_ui.rb +15 -0
  228. data/config/initializers/swagger_yard.rb +17 -0
  229. data/config/locales/en.activerecord.yml +18 -0
  230. data/config/locales/en.yml +61 -0
  231. data/config/routes.rb +55 -0
  232. data/db/migrate/20220218121438_create_uffizzi_core_tables.rb +375 -0
  233. data/db/migrate/20220325113342_add_name_to_uffizzi_containers.rb +7 -0
  234. data/db/seeds.rb +16 -0
  235. data/lib/tasks/uffizzi_core_tasks.rake +14 -0
  236. data/lib/uffizzi_core/engine.rb +15 -0
  237. data/lib/uffizzi_core/version.rb +5 -0
  238. data/lib/uffizzi_core.rb +60 -0
  239. data/swagger/v1/swagger.json +1278 -0
  240. metadata +935 -0
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Projects::DeploymentSerializer < UffizziCore::BaseSerializer
4
+ type :deployment
5
+
6
+ attributes :id,
7
+ :kind,
8
+ :project_id,
9
+ :created_at,
10
+ :updated_at,
11
+ :state,
12
+ :preview_url,
13
+ :tag,
14
+ :branch,
15
+ :commit,
16
+ :image_id,
17
+ :ingress_container_ready,
18
+ :ingress_container_state,
19
+ :creation_source
20
+
21
+ has_many :containers
22
+
23
+ belongs_to :deployed_by
24
+
25
+ def deployed_by
26
+ object.deployed_by
27
+ end
28
+
29
+ def containers
30
+ object.containers.active
31
+ end
32
+
33
+ def preview_url
34
+ UffizziCore::DeploymentService.build_preview_url(object)
35
+ end
36
+
37
+ def tag
38
+ object.ingress_container&.tag
39
+ end
40
+
41
+ def branch
42
+ object.ingress_container&.repo&.branch
43
+ end
44
+
45
+ def commit
46
+ object.ingress_container&.repo&.builds&.deployed&.last&.commit.to_s.slice(0..5)
47
+ end
48
+
49
+ def image_id
50
+ object.ingress_container&.repo&.name
51
+ end
52
+
53
+ def ingress_container_ready
54
+ !!object.ingress_container&.activity_items&.last&.events&.last&.deployed?
55
+ end
56
+
57
+ def ingress_container_state
58
+ last_event = object.ingress_container&.activity_items&.last&.events&.last
59
+
60
+ case last_event&.state
61
+ when UffizziCore::Event.state.deployed
62
+ :deployed
63
+ when UffizziCore::Event.state.failed, UffizziCore::Event.state.timeout, UffizziCore::Event.state.cancelled
64
+ :failed
65
+ else
66
+ state_from_activity_items
67
+ end
68
+ end
69
+
70
+ def state_from_activity_items
71
+ activity_items_count = object.ingress_container&.activity_items&.count
72
+ activity_items_count.to_i > 1 ? :updating : :pending
73
+ end
74
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Projects::Deployments::ActivityItemSerializer < UffizziCore::BaseSerializer
4
+ type :activity_item
5
+
6
+ attributes :id, :namespace, :name, :tag, :type, :branch, :commit, :commit_message, :state, :created_at,
7
+ :updated_at, :build_id, :data, :container_id, :digest
8
+
9
+ def type
10
+ return :github if object.type == UffizziCore::ActivityItem::Github.name
11
+ return :docker if object.type == UffizziCore::ActivityItem::Docker.name
12
+ return :memory_limit if object.type == UffizziCore::ActivityItem::MemoryLimit.name
13
+
14
+ nil
15
+ end
16
+
17
+ def commit
18
+ object.commit.to_s.slice(0..6)
19
+ end
20
+
21
+ def state
22
+ object.events.order_by_id.last&.state
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Projects::Deployments::ContainerSerializer::ContainerConfigFileSerializer::ConfigFileSerializer <
4
+ UffizziCore::BaseSerializer
5
+ attributes :id, :filename, :kind, :payload
6
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Projects::Deployments::ContainerSerializer::ContainerConfigFileSerializer < UffizziCore::BaseSerializer
4
+ attributes :id, :mount_path
5
+
6
+ belongs_to :config_file
7
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Projects::Deployments::ContainerSerializer < UffizziCore::BaseSerializer
4
+ attributes :id, :name, :memory_limit, :memory_request, :continuously_deploy, :variables, :secret_variables
5
+
6
+ has_many :container_config_files
7
+
8
+ type :container
9
+
10
+ def name
11
+ image_name = object.image.split('/').pop
12
+ commit = object&.repo&.builds&.deployed&.last&.commit
13
+ container_name = "#{image_name}:#{object.tag}"
14
+
15
+ if !commit.nil?
16
+ short_commit_hash = commit.slice(0..5)
17
+ container_name = "#{container_name}@#{short_commit_hash}"
18
+ end
19
+
20
+ container_name
21
+ end
22
+
23
+ def secret_variables
24
+ return unless object.secret_variables.present?
25
+
26
+ object.secret_variables.map do |var|
27
+ { name: var['name'], value: anonymize(var['value']) }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::UserSerializer::AccountSerializer < UffizziCore::BaseSerializer
4
+ attributes :id, :state
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::UserSerializer < UffizziCore::BaseSerializer
4
+ type :user
5
+
6
+ has_many :accounts
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::BaseSerializer < ActiveModel::Serializer
4
+ def anonymize(field)
5
+ '*' * field.length
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Controller::CreateCredential::CredentialSerializer < UffizziCore::BaseSerializer
4
+ attributes :id, :registry_url, :username, :password
5
+
6
+ def username
7
+ return 'AWS' if object.amazon?
8
+
9
+ object.username
10
+ end
11
+
12
+ def password
13
+ return UffizziCore::Amazon::CredentialService.access_token(object) if object.amazon?
14
+
15
+ object.password
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Controller::CreateDeployment::DeploymentSerializer < UffizziCore::BaseSerializer
4
+ attributes :kind
5
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Controller::DeployContainers::ContainerSerializer < UffizziCore::BaseSerializer
4
+ attributes :id,
5
+ :kind,
6
+ :image,
7
+ :tag,
8
+ :variables,
9
+ :secret_variables,
10
+ :memory_limit,
11
+ :memory_request,
12
+ :entrypoint,
13
+ :command,
14
+ :port,
15
+ :target_port,
16
+ :public,
17
+ :controller_name,
18
+ :receive_incoming_requests
19
+
20
+ has_many :container_config_files
21
+
22
+ def image
23
+ credential = UffizziCore::RepoService.credential(object.repo)
24
+
25
+ case object.repo.type
26
+ when UffizziCore::Repo::Github.name
27
+ UffizziCore::RepoService.image(object.repo)
28
+ when UffizziCore::Repo::Google.name, UffizziCore::Repo::Amazon.name, UffizziCore::Repo::Azure.name
29
+ registry_host = URI.parse(credential.registry_url).host
30
+
31
+ "#{registry_host}/#{object.image}"
32
+ else
33
+ object.image
34
+ end
35
+ end
36
+
37
+ def tag
38
+ case object.repo.type
39
+ when UffizziCore::Repo::Github.name
40
+ UffizziCore::RepoService.tag(object.repo)
41
+ else
42
+ object.tag
43
+ end
44
+ end
45
+
46
+ def entrypoint
47
+ object.entrypoint.blank? ? nil : JSON.parse(object.entrypoint)
48
+ end
49
+
50
+ def command
51
+ object.command.blank? ? nil : JSON.parse(object.command)
52
+ end
53
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Controller::DeployContainers::CredentialSerializer < UffizziCore::BaseSerializer
4
+ attributes :id
5
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::AccountService
4
+ class << self
5
+ def create_credential(credential)
6
+ credential.account.projects.active.each do |project|
7
+ project.deployments.active.each do |deployment|
8
+ UffizziCore::Deployment::CreateCredentialJob.perform_async(deployment.id, credential.id)
9
+ end
10
+ end
11
+ end
12
+
13
+ def delete_credential(credential)
14
+ credential.account.projects.active.each do |project|
15
+ project.deployments.active.each do |deployment|
16
+ UffizziCore::Deployment::DeleteCredentialJob.perform_async(deployment.id, credential.id)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ActivityItemService
4
+ COMPLETED_STATES = ['deployed', 'failed', 'cancelled'].freeze
5
+
6
+ class << self
7
+ def create_github_item!(repo, container)
8
+ activity_item_attributes = {
9
+ namespace: repo.namespace,
10
+ name: repo.name,
11
+ container: container,
12
+ deployment_id: container.deployment_id,
13
+ branch: repo.branch,
14
+ type: UffizziCore::ActivityItem::Github.name,
15
+ }
16
+
17
+ create_item!(activity_item_attributes)
18
+ end
19
+
20
+ def create_docker_item!(repo, container)
21
+ activity_item_attributes = {
22
+ namespace: repo.namespace,
23
+ name: repo.name,
24
+ container: container,
25
+ deployment_id: container.deployment_id,
26
+ type: UffizziCore::ActivityItem::Docker.name,
27
+ tag: container.tag,
28
+ }
29
+
30
+ create_item!(activity_item_attributes)
31
+ end
32
+
33
+ def update_docker_digest!(activity_item)
34
+ container = activity_item.container
35
+ repo = container.repo
36
+ credential = UffizziCore::RepoService.credential(repo)
37
+
38
+ digest = case repo.type
39
+ when UffizziCore::Repo::DockerHub.name
40
+ UffizziCore::DockerHubService.digest(credential, activity_item.image, activity_item.tag)
41
+ when UffizziCore::Repo::Azure.name
42
+ UffizziCore::AzureService.digest(credential, activity_item.image, activity_item.tag)
43
+ when UffizziCore::Repo::Google.name
44
+ UffizziCore::GoogleService.digest(credential, activity_item.image, activity_item.tag)
45
+ when UffizziCore::Repo::Amazon.name
46
+ UffizziCore::AmazonService.digest(credential, activity_item.image, activity_item.tag)
47
+ end
48
+
49
+ activity_item.update!(digest: digest)
50
+
51
+ activity_item
52
+ end
53
+
54
+ def manage_deploy_activity_item(activity_item)
55
+ container = activity_item.container
56
+ deployment = container.deployment
57
+ service = UffizziCore::ManageActivityItemsService.new(deployment)
58
+ container_status_item = service.container_status_item(container)
59
+ status = container_status_item[:status]
60
+ last_event = activity_item.events.order_by_id.last
61
+
62
+ activity_item.events.create(state: status) if last_event&.state != status
63
+
64
+ update_build_data(activity_item) if activity_item.github?
65
+
66
+ if status == UffizziCore::Event.state.deployed && UffizziCore::DeploymentService.pull_request_payload_present?(deployment)
67
+ UffizziCore::Deployment::SendGithubPreviewMessageJob.perform_async(deployment.id)
68
+ end
69
+ return unless [UffizziCore::Event.state.building, UffizziCore::Event.state.deploying].include?(status)
70
+
71
+ UffizziCore::Deployment::ManageDeployActivityItemJob.perform_in(5.seconds, activity_item.id)
72
+ end
73
+
74
+ private
75
+
76
+ def update_build_data(activity_item)
77
+ build = activity_item.container.repo.builds.deployed.last
78
+
79
+ return if !build.present? || !activity_item.build_id.nil?
80
+
81
+ activity_item.update(build_id: build.id, commit: build.commit, commit_message: build.message)
82
+ end
83
+
84
+ def create_item!(activity_item_attributes)
85
+ activity_item = UffizziCore::ActivityItem.find_by(activity_item_attributes)
86
+ return activity_item unless completed?(activity_item)
87
+
88
+ UffizziCore::ActivityItem.create!(activity_item_attributes)
89
+ end
90
+
91
+ def completed?(activity_item)
92
+ return true if activity_item.nil?
93
+
94
+ last_event = activity_item.events.last
95
+ COMPLETED_STATES.include?(last_event.state)
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Amazon::CredentialService
4
+ class << self
5
+ def credential_correct?(credential)
6
+ access_token(credential).present?
7
+ end
8
+
9
+ def access_token(credential)
10
+ response = client(credential).authorization_token
11
+ base64_data = response.authorization_data[0].authorization_token
12
+ token_string = Base64.decode64(base64_data)
13
+ token_items = token_string.split(':')
14
+ token_items.pop
15
+ rescue Aws::ECR::Errors::UnrecognizedClientException, Aws::ECR::Errors::InvalidSignatureException
16
+ ''
17
+ end
18
+
19
+ private
20
+
21
+ def client(credential)
22
+ region = UffizziCore::AmazonService.get_region_from_registry_url(credential.registry_url)
23
+
24
+ UffizziCore::AmazonRegistryClient.new(
25
+ region: region,
26
+ access_key_id: credential.username,
27
+ secret_access_key: credential.password,
28
+ )
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::AmazonService
4
+ class << self
5
+ def digest(credential, image, tag)
6
+ response = client(credential).batch_get_image(image: image, tag: tag)
7
+ response.images[0].image_id.image_digest
8
+ rescue StandardError
9
+ nil
10
+ end
11
+
12
+ def get_region_from_registry_url(url)
13
+ parsed_url = URI.parse(url)
14
+ host = parsed_url.host
15
+ parsed_host = host.split('.')
16
+ parsed_host[3]
17
+ end
18
+
19
+ def process_webhook(event, event_data)
20
+ case event
21
+ when 'PUSH'
22
+ source = UffizziCore::Repo::Amazon.name
23
+ image = event_data['repository-name']
24
+ tag = event_data['image-tag']
25
+
26
+ UffizziCore::ContinuouslyDeployService.run_docker_registry_process(source, image, tag)
27
+ UffizziCore::ContinuousPreviewService.run_docker_registry_process(source, image, tag)
28
+ else
29
+ Rails.logger.warn("Amazon #{event} event doesn't support")
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def client(credential)
36
+ region = get_region_from_registry_url(credential.registry_url)
37
+
38
+ UffizziCore::AmazonRegistryClient.new(
39
+ region: region,
40
+ access_key_id: credential.username,
41
+ secret_access_key: credential.password,
42
+ )
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Azure::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::AzureRegistryClient.new(registry_url: credential.registry_url, username: credential.username,
15
+ password: credential.password)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Cli::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 load_repositories(compose_data, credential)
39
+ containers = github_containers(compose_data)
40
+ return [] if containers.empty?
41
+
42
+ search_query = 'fork:true '
43
+ search_query += containers.reduce('') do |query, container|
44
+ query += "repo:#{credential.username}/#{container[:build][:repository_name]} "
45
+ query
46
+ end
47
+
48
+ UffizziCore::Github::CredentialService.search_repositories(credential, search_query)
49
+ end
50
+
51
+ def check_github_branches(compose_data, repositories, credential)
52
+ containers = github_containers_with_branches(compose_data)
53
+ return [] if containers.empty?
54
+
55
+ containers.map do |container|
56
+ repository = repositories.detect { |item| item[:clone_url].to_s.start_with?(container[:build][:repository_url]) }
57
+ error_message = I18n.t('compose.repository_not_found', repository_url: container[:build][:repository_url])
58
+ raise UffizziCore::ComposeFile::NotFoundError, error_message if repository.nil?
59
+
60
+ branch = begin
61
+ UffizziCore::Github::CredentialService.branch(credential, repository[:id], container[:build][:branch])
62
+ rescue Octokit::NotFound
63
+ nil
64
+ end
65
+
66
+ error_message = I18n.t('compose.invalid_branch', branch: container[:build][:branch],
67
+ repository_url: container[:build][:repository_url])
68
+ raise UffizziCore::ComposeFile::NotFoundError, error_message if branch.nil?
69
+ end
70
+ end
71
+
72
+ def build_template_attributes(compose_data, source, credentials, project, compose_dependencies = [], compose_repositories = [])
73
+ builder = UffizziCore::ComposeFile::Builders::TemplateBuilderService.new(credentials, project, compose_repositories)
74
+
75
+ builder.build_attributes(compose_data, compose_dependencies, source)
76
+ end
77
+
78
+ def containers_credentials(compose_data, credentials)
79
+ containers = compose_data[:containers]
80
+ detected_credentials = containers.map do |container|
81
+ UffizziCore::ComposeFile::ContainerService.credential_for_container(container, credentials)
82
+ end
83
+
84
+ result = []
85
+ detected_credentials.compact
86
+ .group_by { |credential| credential[:id] }
87
+ .each_pair { |_id, value| result << value.first }
88
+ result
89
+ end
90
+
91
+ private
92
+
93
+ def process_compose_file(compose_file_form, params)
94
+ credential = compose_file_form.project.account.credentials.github.last
95
+ cli_form = create_cli_form(compose_file_form.content, credential)
96
+ return [compose_file_form, cli_form.errors] if cli_form.invalid?
97
+
98
+ dependencies = params[:dependencies].to_a
99
+ compose_data = cli_form.compose_data
100
+ compose_dependencies = build_compose_dependecies(compose_data, compose_file_form.path, dependencies)
101
+ cli_form.compose_dependencies = compose_dependencies
102
+
103
+ persist!(compose_file_form, cli_form)
104
+ end
105
+
106
+ def create_compose_form(params, kind)
107
+ compose_file_params = params[:compose_file_params]
108
+ compose_file_form = UffizziCore::Api::Cli::V1::ComposeFile::CreateForm.new(compose_file_params)
109
+ compose_file_form.project = params[:project]
110
+ compose_file_form.added_by = params[:user]
111
+ compose_file_form.content = compose_file_params[:content]
112
+ compose_file_form.kind = kind
113
+ payload_dependencies = prepare_compose_file_dependencies(params[:dependencies])
114
+ compose_file_form.payload['dependencies'] = payload_dependencies
115
+
116
+ compose_file_form
117
+ end
118
+
119
+ def create_update_compose_form(compose_file, params)
120
+ compose_file_form = compose_file.becomes(UffizziCore::Api::Cli::V1::ComposeFile::UpdateForm)
121
+ compose_file_params = params[:compose_file_params]
122
+ compose_file_form.assign_attributes(compose_file_params)
123
+ payload_dependencies = prepare_compose_file_dependencies(params[:dependencies])
124
+ compose_file_form.payload['dependencies'] = payload_dependencies
125
+
126
+ compose_file_form
127
+ end
128
+
129
+ def create_cli_form(content, credential)
130
+ cli_form = UffizziCore::Api::Cli::V1::ComposeFile::CliForm.new
131
+ cli_form.content = content
132
+ cli_form.credential = credential
133
+
134
+ cli_form
135
+ end
136
+
137
+ def build_compose_dependecies(compose_data, compose_path, dependencies)
138
+ return [] if dependencies.empty?
139
+
140
+ UffizziCore::ComposeFile::DependenciesService.build_dependencies(compose_data, compose_path, dependencies)
141
+ end
142
+
143
+ def prepare_compose_file_dependencies(compose_dependencies)
144
+ compose_dependencies.map do |dependency|
145
+ {
146
+ path: dependency[:path],
147
+ }
148
+ end
149
+ end
150
+
151
+ def persist!(compose_file_form, cli_form)
152
+ errors = []
153
+ ActiveRecord::Base.transaction do
154
+ if !compose_file_form.save
155
+ errors = compose_file_form.errors
156
+ raise ActiveRecord::Rollback
157
+ end
158
+
159
+ config_files_service = UffizziCore::ComposeFile::ConfigFilesService.new(compose_file_form)
160
+ errors = config_files_service.create_config_files(cli_form.compose_dependencies)
161
+ raise ActiveRecord::Rollback if errors.present?
162
+
163
+ project = compose_file_form.project
164
+ user = compose_file_form.added_by
165
+ template_service = UffizziCore::ComposeFile::TemplateService.new(cli_form, project, user)
166
+ errors = template_service.create_template(compose_file_form)
167
+
168
+ raise ActiveRecord::Rollback if errors.present?
169
+ end
170
+ [compose_file_form, errors]
171
+ end
172
+
173
+ def load_compose_data(compose_content)
174
+ begin
175
+ compose_data = YAML.safe_load(compose_content)
176
+ rescue Psych::SyntaxError
177
+ raise UffizziCore::ComposeFile::ParseError, 'Invalid compose file'
178
+ end
179
+
180
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.unsupported_file') if compose_data.nil?
181
+
182
+ compose_data
183
+ end
184
+
185
+ def check_config_options_format(compose_data)
186
+ options = UffizziCore::ComposeFile::ConfigOptionService.config_options(compose_data)
187
+
188
+ options.each do |option|
189
+ next if UffizziCore::ComposeFile::ConfigOptionService.valid_option_format?(option)
190
+
191
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_config_option', value: option)
192
+ end
193
+ end
194
+
195
+ def github_containers(compose_data)
196
+ compose_data[:containers].select { |container| UffizziCore::ComposeFile::ContainerService.github?(container) }
197
+ end
198
+
199
+ def github_containers_with_branches(compose_data)
200
+ github_containers(compose_data).reject { |container| container[:build][:branch].nil? }
201
+ end
202
+ end
203
+ end