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,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,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Github::AppService
4
+ class << self
5
+ def create_preview_message_into_pull_request(deployment)
6
+ project = deployment.project
7
+ credential = project.credentials.github.last
8
+ return if credential.nil?
9
+
10
+ pull_request_payload = deployment.continuous_preview_payload['pull_request']
11
+ installation_id = credential.provider_ref
12
+ message = UffizziCore::Github::MessageService.build_preview_message(deployment)
13
+
14
+ create_comment(installation_id, pull_request_payload['repository_full_name'], pull_request_payload['id'], message)
15
+ end
16
+
17
+ private
18
+
19
+ def create_comment(installation_id, repository, issue_id, message)
20
+ access_token = create_installation_access_token(installation_id)
21
+
22
+ installation_client = UffizziCore::Github::InstallationClient.new(access_token)
23
+
24
+ installation_client.add_comment(repository, issue_id, message)
25
+ end
26
+
27
+ def create_installation_access_token(installation_id)
28
+ access_token_response = app_client.create_app_installation_access_token(installation_id)
29
+ access_token_response[:token]
30
+ end
31
+
32
+ def app_client
33
+ UffizziCore::Github::AppClient.new(generate_jwt_token)
34
+ end
35
+
36
+ def generate_jwt_token
37
+ rsa_armor = '-----'
38
+ parts = Settings.github.private_key.split(rsa_armor)
39
+ parts[2].gsub!(/\s/, "\n")
40
+ private_key = OpenSSL::PKey::RSA.new(parts.join(rsa_armor))
41
+
42
+ payload = {}.tap do |opts|
43
+ opts[:iat] = Time.now.to_i
44
+ opts[:exp] = opts[:iat] + 60
45
+ opts[:iss] = Settings.github.app_id
46
+ end
47
+
48
+ JWT.encode(payload, private_key, 'RS256')
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Github::CredentialService
4
+ class << self
5
+ def repository_contains_file?(credential, repository_id, branch, path)
6
+ client(credential).contents?(repository_id, ref: branch, path: path)
7
+ rescue Octokit::Unauthorized
8
+ Rails.logger.warn("broken credentials, repository_contains_file? credential_id=#{credential.id}")
9
+ credential.unauthorize! unless credential.unauthorized?
10
+ raise
11
+ end
12
+
13
+ def credential_correct?(credential)
14
+ valid_installation?(credential)
15
+ rescue Octokit::Unauthorized
16
+ false
17
+ end
18
+
19
+ def search_repositories(credential, search_query)
20
+ result = client(credential).search_repositories(search_query)
21
+
22
+ result[:items]
23
+ rescue Octokit::UnprocessableEntity
24
+ []
25
+ end
26
+
27
+ def repositories(credential, query = '', page = 1)
28
+ repo_attributes = {
29
+ sort: :updated,
30
+ page: page,
31
+ }
32
+
33
+ repos = client(credential).installation_repositories(credential.provider_ref, repo_attributes)
34
+ filter_repos(repos, query)
35
+ rescue Octokit::Unauthorized
36
+ Rails.logger.warn("broken credentials, repositories credential_id=#{credential.id}")
37
+ credential.unauthorize! unless credential.unauthorized?
38
+ raise
39
+ end
40
+
41
+ def branches(credential, repository_id)
42
+ client(credential).branches(repository_id)
43
+ rescue Octokit::Unauthorized
44
+ Rails.logger.warn("broken credentials, branches credential_id=#{credential.id}")
45
+ credential.unauthorize! unless credential.unauthorized?
46
+ raise
47
+ end
48
+
49
+ def branch(credential, repository_id, branch)
50
+ client(credential).branch(repository_id, branch)
51
+ rescue Octokit::Unauthorized
52
+ Rails.logger.warn("broken credentials, branch credential_id=#{credential.id}")
53
+ credential.unauthorize! unless credential.unauthorized?
54
+ raise
55
+ end
56
+
57
+ def commit(credential, repository_id, commit_sha)
58
+ commit = client(credential).commit(repository_id, commit_sha)
59
+
60
+ {
61
+ message: commit[:message],
62
+ committer: commit[:committer][:name],
63
+ commit: commit_sha,
64
+ }
65
+ rescue Octokit::Unauthorized
66
+ Rails.logger.warn("broken credentials, commit credential_id=#{credential.id}")
67
+ credential.unauthorize! unless credential.unauthorized?
68
+ raise
69
+ end
70
+
71
+ def contents(credential, repository_id, options)
72
+ client(credential).contents(repository_id, options)
73
+ rescue Octokit::Unauthorized
74
+ Rails.logger.warn("broken credentials, contents credential_id=#{credential.id}")
75
+ credential.unauthorize! unless credential.unauthorized?
76
+ raise
77
+ end
78
+
79
+ def repo(credential, repository_id)
80
+ client(credential).repo(repository_id)
81
+ rescue Octokit::Unauthorized
82
+ Rails.logger.warn("broken credentials, repo credential_id=#{credential.id}")
83
+ credential.unauthorize! unless credential.unauthorized?
84
+ raise
85
+ end
86
+
87
+ def repo_url(credential, repository_id)
88
+ repo = repo(credential, repository_id)
89
+ repo[:clone_url].split(%r{https://}).last
90
+ end
91
+
92
+ def file_content(credential, repository_id, branch, file_path)
93
+ file = contents(credential, repository_id, ref: branch, path: file_path)
94
+ Base64.decode64(file[:content])
95
+ rescue Octokit::Unauthorized
96
+ Rails.logger.warn("broken credentials, file_content credential_id=#{credential.id}")
97
+ credential.unauthorize! unless credential.unauthorized?
98
+ raise
99
+ end
100
+
101
+ private
102
+
103
+ def client(credential)
104
+ UffizziCore::Github::UserClient.new(credential.password)
105
+ end
106
+
107
+ def valid_installation?(credential)
108
+ user_installations = client(credential).user_installations
109
+
110
+ installation = user_installations.detect do |user_installation|
111
+ user_installation[:id].to_s == credential.provider_ref
112
+ end
113
+
114
+ installation.present?
115
+ end
116
+
117
+ def filter_repos(repos, query)
118
+ return repos if query.blank?
119
+
120
+ prepared_query = query.downcase
121
+ repos.select { |repo| repo.full_name.downcase.include?(prepared_query) || repo.description&.downcase&.include?(prepared_query) }
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Github::MessageService
4
+ class << self
5
+ def build_preview_message(deployment)
6
+ preview_url = UffizziCore::DeploymentService.build_preview_url(deployment)
7
+ deployment_url = UffizziCore::DeploymentService.build_deployment_url(deployment)
8
+
9
+ "**This branch has been deployed using Uffizzi.**
10
+
11
+ Preview URL:
12
+ https://#{preview_url}
13
+
14
+ View deployment details here:
15
+ https://#{deployment_url}
16
+
17
+ This is an automated comment. To turn off commenting, visit uffizzi.com."
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::GithubService
4
+ class << self
5
+ def send_preview_message(deployment)
6
+ image = deployment.continuous_preview_payload['pull_request']['repository_full_name']
7
+ containers = deployment.containers.where(image: image)
8
+ repo = UffizziCore::Repo.find_by(id: containers.select(:repo_id))
9
+
10
+ preview_message_is_enabled = !!repo.share_to_github
11
+
12
+ return if !preview_message_is_enabled
13
+
14
+ continuous_preview_payload = deployment.continuous_preview_payload
15
+ pull_request_payload = continuous_preview_payload['pull_request']
16
+ new_preview_message = UffizziCore::Github::MessageService.build_preview_message(deployment)
17
+
18
+ return if new_preview_message == pull_request_payload['message']
19
+
20
+ pull_request_payload['message'] = new_preview_message
21
+ continuous_preview_payload['pull_request'] = pull_request_payload
22
+
23
+ deployment.update(continuous_preview_payload: continuous_preview_payload)
24
+
25
+ UffizziCore::Github::AppService.create_preview_message_into_pull_request(deployment)
26
+ end
27
+ end
28
+ 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
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ManageActivityItemsService
4
+ attr_accessor :deployment, :containers, :pods, :namespace_data
5
+
6
+ def initialize(deployment)
7
+ @deployment = deployment
8
+ @containers = deployment.active_containers
9
+ @namespace_data = UffizziCore::ControllerService.fetch_namespace(deployment)
10
+ @pods = UffizziCore::ControllerService.fetch_pods(deployment)
11
+ end
12
+
13
+ def container_status_item(container)
14
+ container_status_items.detect { |container_statuses| container_statuses[:id] == container.id }
15
+ end
16
+
17
+ def container_status_items
18
+ network_connectivities = build_network_connectivities
19
+ containers_replicas = build_containers_replicas
20
+
21
+ build_container_status_items(network_connectivities, containers_replicas)
22
+ end
23
+
24
+ private
25
+
26
+ def build_network_connectivities
27
+ containers.with_public_access.map do |container|
28
+ { id: container.id, items: build_container_network_connectivity_items(container) }
29
+ end
30
+ end
31
+
32
+ def build_container_network_connectivity_items(container)
33
+ network_connectivities = container_network_connectivities(container)
34
+ return [] if network_connectivities.nil?
35
+
36
+ network_connectivities.map do |network_connectivity|
37
+ type, value = network_connectivity
38
+
39
+ { type: type, status: value.status }
40
+ end
41
+ end
42
+
43
+ def build_containers_replicas
44
+ containers.map do |container|
45
+ repo = container.repo
46
+
47
+ if repo.github?
48
+ build = container.repo.builds.deployed.last
49
+
50
+ if build.nil? || build.building?
51
+ return [{ id: container.id,
52
+ items: [{ name: container.image_name, status: UffizziCore::Event.state.building }] }]
53
+ end
54
+ if !build.successful?
55
+ return [{ id: container.id,
56
+ items: [{ name: container.image_name, status: UffizziCore::Event.state.failed }] }]
57
+ end
58
+ end
59
+
60
+ items = pods.map do |pod|
61
+ {
62
+ name: item_name(pod, container),
63
+ status: get_status(pod, container),
64
+ }
65
+ end
66
+
67
+ { id: container.id, items: items }
68
+ end
69
+ end
70
+
71
+ def build_container_status_items(network_connectivities, containers_replicas)
72
+ containers.map do |container|
73
+ network_connectivity = network_connectivities.detect { |item| item[:id] == container.id }
74
+ any_container_is_building = containers_replicas.any? do |container_replicas|
75
+ container_replicas[:items].any? do |item|
76
+ item[:status] == UffizziCore::Event.state.building
77
+ end
78
+ end
79
+ container_replicas = containers_replicas.detect { |item| item[:id] == container.id }
80
+
81
+ {
82
+ id: container.id,
83
+ status: build_container_status(container, network_connectivity, container_replicas, any_container_is_building),
84
+ }
85
+ end
86
+ end
87
+
88
+ def replicas_contains_status?(replicas, status)
89
+ replicas.any? { |replica| replica[:status] == status }
90
+ end
91
+
92
+ def build_container_status(container, network_connectivity, container_replicas, any_container_is_building)
93
+ return building_container_status(container) if any_container_is_building
94
+
95
+ error = replicas_contains_status?(container_replicas[:items], UffizziCore::Event.state.failed)
96
+ container_is_running = replicas_contains_status?(container_replicas[:items], UffizziCore::Event.state.deployed)
97
+ deployed = !error && container_is_running
98
+ return container_status(error, deployed) unless container.public?
99
+
100
+ network_connectivity[:items].each do |item|
101
+ status = item[:status].to_sym
102
+ error ||= status == :failed
103
+ deployed &&= status == :success
104
+ end
105
+
106
+ container_status(error, deployed)
107
+ end
108
+
109
+ def building_container_status(container)
110
+ return UffizziCore::Event.state.building if container.repo.github?
111
+
112
+ UffizziCore::Event.state.deploying
113
+ end
114
+
115
+ def container_status(error, deployed)
116
+ return UffizziCore::Event.state.failed if error
117
+ return UffizziCore::Event.state.deployed if deployed
118
+
119
+ UffizziCore::Event.state.deploying
120
+ end
121
+
122
+ def item_name(pod, container)
123
+ hash = pod.metadata.name.split('-').last
124
+ "#{container.image_name}-#{hash}"
125
+ end
126
+
127
+ def get_status(pod, container)
128
+ pod_container = pod_container(pod, container)
129
+
130
+ return UffizziCore::Event.state.deploying if pod_container.nil? || pod_container[:state].to_h.empty?
131
+
132
+ pod_container_status = pod_container[:state].keys.first
133
+ state = pod_container[:state][pod_container_status]
134
+ reason = state&.reason
135
+
136
+ case pod_container_status.to_sym
137
+ when :running
138
+ UffizziCore::Event.state.deployed
139
+ when :terminated
140
+ UffizziCore::Event.state.failed
141
+ when :waiting
142
+ return Event.state.failed if ['ErrImagePull', 'ImagePullBackOff', 'CrashLoopBackOff'].include?(reason)
143
+
144
+ UffizziCore::Event.state.deploying
145
+ else
146
+ UffizziCore::Event.state.deploying
147
+ end
148
+ end
149
+
150
+ def pod_container(pod, container)
151
+ pod_name = UffizziCore::ContainerService.pod_name(container)
152
+
153
+ pod&.status&.container_statuses&.detect { |cs| cs.name.include?(pod_name) }
154
+ end
155
+
156
+ def container_network_connectivities(container)
157
+ network_connectivity = Hashie::Mash.new(JSON.parse(deployment_network_connectivity))
158
+ containers_network_connectivity = network_connectivity&.containers
159
+
160
+ containers_network_connectivity[container.id.to_s] if !containers_network_connectivity.nil?
161
+ end
162
+
163
+ def deployment_network_connectivity
164
+ namespace_data&.metadata&.annotations&.network_connectivity || '{}'
165
+ end
166
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::ProjectService
4
+ class << self
5
+ def update_compose_secrets(project)
6
+ compose_file = project.compose_file
7
+ return if compose_file&.template.nil?
8
+
9
+ project.secrets.each do |secret|
10
+ if UffizziCore::ComposeFileService.has_secret?(compose_file, secret)
11
+ UffizziCore::ComposeFileService.update_secret!(compose_file, secret)
12
+ end
13
+ end
14
+
15
+ return unless UffizziCore::ComposeFileService.secrets_valid?(compose_file, project.secrets)
16
+
17
+ secrets_error_key = UffizziCore::ComposeFile::ErrorsService::SECRETS_ERROR_KEY
18
+ return unless UffizziCore::ComposeFile::ErrorsService.has_error?(compose_file, secrets_error_key)
19
+
20
+ UffizziCore::ComposeFile::ErrorsService.reset_error!(compose_file, secrets_error_key)
21
+ compose_file.set_valid! unless UffizziCore::ComposeFile::ErrorsService.has_errors?(compose_file)
22
+ end
23
+
24
+ def update_compose_secret_errors(project, secret)
25
+ compose_file = project.compose_file
26
+ return if compose_file.nil?
27
+ return unless UffizziCore::ComposeFileService.has_secret?(compose_file, secret)
28
+
29
+ error_message = I18n.t('compose.project_secret_not_found', secret: secret['name'])
30
+ error = { UffizziCore::ComposeFile::ErrorsService::SECRETS_ERROR_KEY => [error_message] }
31
+
32
+ existing_errors = compose_file.payload['errors'].presence || {}
33
+ new_errors = existing_errors.merge(error)
34
+
35
+ UffizziCore::ComposeFile::ErrorsService.update_compose_errors!(compose_file, new_errors, compose_file.content)
36
+ end
37
+ end
38
+ end