katello 4.10.0 → 4.11.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of katello might be problematic. Click here for more details.

Files changed (449) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/locale/bn/katello.js +254 -215
  3. data/app/assets/javascripts/katello/locale/bn_IN/katello.js +254 -215
  4. data/app/assets/javascripts/katello/locale/ca/katello.js +254 -215
  5. data/app/assets/javascripts/katello/locale/cs/katello.js +254 -215
  6. data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +254 -215
  7. data/app/assets/javascripts/katello/locale/de/katello.js +260 -245
  8. data/app/assets/javascripts/katello/locale/de_AT/katello.js +254 -215
  9. data/app/assets/javascripts/katello/locale/de_DE/katello.js +254 -215
  10. data/app/assets/javascripts/katello/locale/el/katello.js +254 -215
  11. data/app/assets/javascripts/katello/locale/en/katello.js +254 -215
  12. data/app/assets/javascripts/katello/locale/en_GB/katello.js +254 -215
  13. data/app/assets/javascripts/katello/locale/en_US/katello.js +254 -215
  14. data/app/assets/javascripts/katello/locale/es/katello.js +257 -233
  15. data/app/assets/javascripts/katello/locale/et_EE/katello.js +254 -215
  16. data/app/assets/javascripts/katello/locale/fr/katello.js +268 -268
  17. data/app/assets/javascripts/katello/locale/gl/katello.js +254 -215
  18. data/app/assets/javascripts/katello/locale/gu/katello.js +254 -215
  19. data/app/assets/javascripts/katello/locale/he_IL/katello.js +254 -215
  20. data/app/assets/javascripts/katello/locale/hi/katello.js +254 -215
  21. data/app/assets/javascripts/katello/locale/id/katello.js +254 -215
  22. data/app/assets/javascripts/katello/locale/it/katello.js +254 -221
  23. data/app/assets/javascripts/katello/locale/ja/katello.js +268 -268
  24. data/app/assets/javascripts/katello/locale/ka/katello.js +261 -231
  25. data/app/assets/javascripts/katello/locale/kn/katello.js +254 -215
  26. data/app/assets/javascripts/katello/locale/ko/katello.js +255 -222
  27. data/app/assets/javascripts/katello/locale/locale/katello.js +1049 -1012
  28. data/app/assets/javascripts/katello/locale/ml_IN/katello.js +254 -215
  29. data/app/assets/javascripts/katello/locale/mr/katello.js +254 -215
  30. data/app/assets/javascripts/katello/locale/nl_NL/katello.js +254 -215
  31. data/app/assets/javascripts/katello/locale/or/katello.js +254 -215
  32. data/app/assets/javascripts/katello/locale/pa/katello.js +254 -215
  33. data/app/assets/javascripts/katello/locale/pl/katello.js +254 -215
  34. data/app/assets/javascripts/katello/locale/pl_PL/katello.js +254 -215
  35. data/app/assets/javascripts/katello/locale/pt/katello.js +254 -215
  36. data/app/assets/javascripts/katello/locale/pt_BR/katello.js +257 -233
  37. data/app/assets/javascripts/katello/locale/ro/katello.js +254 -215
  38. data/app/assets/javascripts/katello/locale/ro_RO/katello.js +254 -215
  39. data/app/assets/javascripts/katello/locale/ru/katello.js +255 -222
  40. data/app/assets/javascripts/katello/locale/sl/katello.js +254 -215
  41. data/app/assets/javascripts/katello/locale/sv_SE/katello.js +254 -215
  42. data/app/assets/javascripts/katello/locale/ta/katello.js +254 -215
  43. data/app/assets/javascripts/katello/locale/ta_IN/katello.js +254 -215
  44. data/app/assets/javascripts/katello/locale/te/katello.js +254 -215
  45. data/app/assets/javascripts/katello/locale/tr/katello.js +254 -215
  46. data/app/assets/javascripts/katello/locale/vi/katello.js +254 -215
  47. data/app/assets/javascripts/katello/locale/vi_VN/katello.js +254 -215
  48. data/app/assets/javascripts/katello/locale/zh/katello.js +254 -215
  49. data/app/assets/javascripts/katello/locale/zh_CN/katello.js +268 -268
  50. data/app/assets/javascripts/katello/locale/zh_TW/katello.js +255 -222
  51. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +15 -2
  52. data/app/controllers/katello/api/v2/capsule_content_controller.rb +21 -4
  53. data/app/controllers/katello/api/v2/capsules_controller.rb +11 -1
  54. data/app/controllers/katello/api/v2/content_view_versions_controller.rb +1 -1
  55. data/app/controllers/katello/api/v2/docker_tags_controller.rb +2 -0
  56. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +2 -1
  57. data/app/controllers/katello/api/v2/organizations_controller.rb +2 -2
  58. data/app/controllers/katello/api/v2/repositories_controller.rb +1 -0
  59. data/app/controllers/katello/api/v2/simple_content_access_controller.rb +5 -5
  60. data/app/controllers/katello/api/v2/sync_plans_controller.rb +11 -3
  61. data/app/controllers/katello/concerns/api/api_controller.rb +6 -0
  62. data/app/controllers/katello/concerns/api/v2/hosts_bulk_actions_controller_extensions.rb +23 -0
  63. data/app/controllers/katello/concerns/filtered_auto_complete_search.rb +1 -1
  64. data/app/controllers/katello/concerns/organizations_controller_extensions.rb +2 -0
  65. data/app/controllers/katello/remote_execution_controller.rb +1 -1
  66. data/app/jobs/create_host_lifecycle_expire_soon_notifications.rb +11 -0
  67. data/app/lib/actions/katello/applicability/hosts/bulk_generate.rb +10 -0
  68. data/app/lib/actions/katello/capsule_content/refresh_repos.rb +8 -2
  69. data/app/lib/actions/katello/capsule_content/sync.rb +30 -10
  70. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +13 -0
  71. data/app/lib/actions/katello/capsule_content/update_content_counts.rb +24 -0
  72. data/app/lib/actions/katello/content_view/promote.rb +9 -0
  73. data/app/lib/actions/katello/content_view/publish.rb +9 -0
  74. data/app/lib/actions/katello/orphan_cleanup/remove_orphans.rb +8 -0
  75. data/app/lib/actions/katello/repository/sync.rb +11 -0
  76. data/app/lib/actions/pulp3/capsule_content/reclaim_space.rb +5 -0
  77. data/app/lib/actions/pulp3/content_view_version/create_export_history.rb +6 -1
  78. data/app/lib/actions/pulp3/content_view_version/export.rb +8 -0
  79. data/app/lib/actions/pulp3/orchestration/content_view_version/export_repository.rb +1 -1
  80. data/app/lib/katello/concerns/base_template_scope_extensions.rb +14 -1
  81. data/app/lib/katello/errors.rb +1 -0
  82. data/app/lib/katello/repo_discovery.rb +2 -2
  83. data/app/lib/katello/validators/content_view_environment_coherent_default_validator.rb +22 -0
  84. data/app/lib/katello/validators/content_view_environment_validator.rb +1 -0
  85. data/app/mailers/katello/task_mailer.rb +54 -0
  86. data/app/models/katello/concerns/host_managed_extensions.rb +41 -1
  87. data/app/models/katello/concerns/organization_extensions.rb +1 -1
  88. data/app/models/katello/concerns/smart_proxy_extensions.rb +75 -3
  89. data/app/models/katello/concerns/subscription_facet_host_extensions.rb +6 -0
  90. data/app/models/katello/content_view.rb +21 -0
  91. data/app/models/katello/content_view_environment.rb +6 -1
  92. data/app/models/katello/docker_meta_tag.rb +1 -1
  93. data/app/models/katello/docker_tag.rb +1 -1
  94. data/app/models/katello/erratum.rb +1 -1
  95. data/app/models/katello/host/content_facet.rb +10 -7
  96. data/app/models/katello/product.rb +8 -0
  97. data/app/models/katello/repository.rb +31 -6
  98. data/app/models/katello/rhel_lifecycle_status.rb +214 -0
  99. data/app/models/katello/sync_plan.rb +19 -1
  100. data/app/models/katello/yum_metadata_file.rb +1 -1
  101. data/app/services/katello/applicability/applicable_content_helper.rb +1 -1
  102. data/app/services/katello/event_queue.rb +10 -2
  103. data/app/services/katello/host_status_manager.rb +1 -0
  104. data/app/services/katello/product_content_importer.rb +45 -3
  105. data/app/services/katello/pulp3/ansible_collection.rb +1 -0
  106. data/app/services/katello/pulp3/api/core.rb +1 -1
  107. data/app/services/katello/pulp3/deb.rb +1 -0
  108. data/app/services/katello/pulp3/docker_manifest.rb +1 -0
  109. data/app/services/katello/pulp3/docker_manifest_list.rb +9 -4
  110. data/app/services/katello/pulp3/docker_tag.rb +1 -0
  111. data/app/services/katello/pulp3/erratum.rb +1 -0
  112. data/app/services/katello/pulp3/file_unit.rb +1 -0
  113. data/app/services/katello/pulp3/module_stream.rb +1 -0
  114. data/app/services/katello/pulp3/package_group.rb +1 -0
  115. data/app/services/katello/pulp3/pulp_content_unit.rb +39 -0
  116. data/app/services/katello/pulp3/repository_mirror.rb +21 -2
  117. data/app/services/katello/pulp3/rpm.rb +1 -0
  118. data/app/services/katello/pulp3/smart_proxy_mirror_repository.rb +1 -1
  119. data/app/services/katello/pulp3/srpm.rb +3 -2
  120. data/app/services/katello/registration_manager.rb +6 -3
  121. data/app/services/katello/repository_type.rb +2 -1
  122. data/app/services/katello/ui_notifications/hosts/lifecycle_expire_soon.rb +58 -0
  123. data/app/views/foreman/job_templates/resolve_traces.erb +1 -1
  124. data/app/views/foreman/smart_proxies/_content_tab.html.erb +1 -3
  125. data/app/views/katello/api/v2/capsule_content/sync_status.json.rabl +39 -1
  126. data/app/views/katello/api/v2/content_facet/show.json.rabl +4 -0
  127. data/app/views/katello/api/v2/content_views/base.json.rabl +1 -1
  128. data/app/views/katello/api/v2/docker_tags/_base.json.rabl +28 -6
  129. data/app/views/katello/hosts/_errata_counts.html.erb +2 -2
  130. data/app/views/katello/task_mailer/cv_promote_failure.html.erb +31 -0
  131. data/app/views/katello/task_mailer/cv_promote_failure.text.erb +13 -0
  132. data/app/views/katello/task_mailer/cv_publish_failure.html.erb +31 -0
  133. data/app/views/katello/task_mailer/cv_publish_failure.text.erb +13 -0
  134. data/app/views/katello/task_mailer/proxy_sync_failure.html.erb +45 -0
  135. data/app/views/katello/task_mailer/proxy_sync_failure.text.erb +25 -0
  136. data/app/views/katello/task_mailer/repo_sync_failure.html.erb +35 -0
  137. data/app/views/katello/task_mailer/repo_sync_failure.text.erb +15 -0
  138. data/app/views/overrides/organizations/_edit_override.html.erb +4 -0
  139. data/config/routes/api/v2.rb +2 -0
  140. data/db/migrate/20230825180856_add_content_counts_to_smart_proxy.rb +7 -0
  141. data/db/migrate/20231020153017_create_indexes_for_nvra_and_epoch.rb +6 -0
  142. data/db/seeds.d/106-mail_notifications.rb +32 -0
  143. data/db/seeds.d/109-katello-notification-blueprints.rb +6 -0
  144. data/engines/bastion/app/assets/javascripts/bastion/components/views/bst-alert.html +1 -1
  145. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/activation-keys.controller.js +4 -0
  146. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-add-host-collections.controller.js +3 -0
  147. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-add-subscriptions.controller.js +3 -0
  148. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-associations.controller.js +4 -0
  149. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-copy.controller.js +7 -2
  150. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-host-collections.controller.js +3 -0
  151. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-repository-sets.controller.js +3 -0
  152. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-subscriptions.controller.js +3 -0
  153. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/new/new-activation-key.controller.js +6 -2
  154. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/capsule-content/capsule-content.controller.js +16 -1
  155. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/rhel-lifecycle-notice.html +5 -0
  156. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/content-credentials.controller.js +7 -2
  157. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/details/content-credential-acs.controller.js +7 -2
  158. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/details/content-credential-products.controller.js +7 -2
  159. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/details/content-credential-repositories.controller.js +7 -2
  160. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/new/new-content-credential.controller.js +3 -0
  161. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-errata-modal.controller.js +5 -1
  162. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-debs-actions.controller.js +5 -1
  163. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-debs-applicable.controller.js +3 -0
  164. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-debs-installed.controller.js +3 -0
  165. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-errata.controller.js +4 -0
  166. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-module-streams.controller.js +3 -0
  167. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-packages-applicable.controller.js +3 -0
  168. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-packages-installed.controller.js +3 -0
  169. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-packages.controller.js +3 -0
  170. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-traces.controller.js +4 -0
  171. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-debs-actions.html +1 -1
  172. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-debs-applicable.html +1 -1
  173. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-debs-installed.html +1 -1
  174. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-errata.html +3 -3
  175. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-module-streams.html +1 -1
  176. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-actions.html +1 -1
  177. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-applicable.html +1 -1
  178. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-installed.html +1 -1
  179. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-traces.html +3 -3
  180. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-hosts.controller.js +5 -0
  181. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-hosts.routes.js +1 -1
  182. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-add-host-collections.controller.js +4 -1
  183. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-add-subscriptions.controller.js +3 -0
  184. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-host-collections.controller.js +4 -1
  185. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-repository-sets.controller.js +3 -0
  186. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-subscriptions.controller.js +3 -0
  187. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-add-subscriptions.html +1 -1
  188. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-details.html +4 -3
  189. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-host-collections.html +1 -1
  190. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +3 -3
  191. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-provisioning-info.html +2 -2
  192. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-subscriptions-list.html +1 -1
  193. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-subscriptions.html +1 -1
  194. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +3 -3
  195. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/debs.controller.js +7 -0
  196. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/details/deb-content-views.controller.js +8 -1
  197. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/details/deb-repositories.controller.js +10 -2
  198. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/docker-tags/details/docker-tag-environments.controller.js +5 -2
  199. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/docker-tags/details/docker-tag-repositories.controller.js +6 -2
  200. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/docker-tags/docker-tags.controller.js +6 -3
  201. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/environment-content.controller.js +13 -0
  202. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/environment.controller.js +6 -0
  203. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/new-environment.controller.js +8 -2
  204. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/apply-errata.controller.js +4 -0
  205. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/details/erratum-content-hosts.controller.js +7 -2
  206. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/details/erratum-repositories.controller.js +7 -2
  207. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/details/erratum.controller.js +6 -2
  208. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/details/views/erratum-info.html +2 -2
  209. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/errata.controller.js +5 -0
  210. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/views/errata.html +1 -1
  211. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/files/details/file-content-views.controller.js +10 -2
  212. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/files/details/file-repositories.controller.js +8 -1
  213. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/files/files.controller.js +9 -2
  214. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/host-collections/details/host-collection-add-hosts.controller.js +3 -0
  215. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/host-collections/details/host-collection-copy.controller.js +7 -2
  216. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/host-collections/details/host-collection-hosts.controller.js +3 -0
  217. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/host-collections/host-collections.controller.js +4 -0
  218. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/host-collections/new/new-host-collection.controller.js +6 -2
  219. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/hosts/host.factory.js +4 -0
  220. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +166 -43
  221. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +4 -0
  222. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/translations.js +1 -1
  223. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/packages/packages.controller.js +7 -0
  224. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/product-repositories.controller.js +5 -0
  225. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-advanced-sync.controller.js +6 -2
  226. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-manage-content.controller.js +11 -0
  227. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/new-repository.controller.js +3 -0
  228. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/views/product-repositories.html +2 -2
  229. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/discovery-create.controller.js +3 -0
  230. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/discovery.controller.js +3 -0
  231. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/new/product-form.controller.js +6 -2
  232. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/products.controller.js +4 -0
  233. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/content-access-mode-banner.html +1 -1
  234. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/details/sync-plan-add-products.controller.js +5 -1
  235. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/details/sync-plan-products.controller.js +4 -0
  236. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/new/new-sync-plan.controller.js +3 -0
  237. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/sync-plans.controller.js +4 -0
  238. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/tasks/task-details.controller.js +6 -2
  239. data/lib/katello/engine.rb +2 -3
  240. data/lib/katello/permission_creator.rb +2 -2
  241. data/lib/katello/plugin.rb +4 -0
  242. data/lib/katello/repository_types/ostree.rb +1 -0
  243. data/lib/katello/repository_types/python.rb +1 -0
  244. data/lib/katello/scheduled_jobs.rb +1 -1
  245. data/lib/katello/version.rb +1 -1
  246. data/locale/action_names.rb +1 -3
  247. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  248. data/locale/bn/katello.po +236 -197
  249. data/locale/bn_IN/LC_MESSAGES/katello.mo +0 -0
  250. data/locale/bn_IN/katello.po +236 -197
  251. data/locale/ca/LC_MESSAGES/katello.mo +0 -0
  252. data/locale/ca/katello.po +236 -197
  253. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  254. data/locale/cs/katello.po +236 -206
  255. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  256. data/locale/cs_CZ/katello.po +236 -197
  257. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  258. data/locale/de/katello.po +241 -202
  259. data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
  260. data/locale/de_AT/katello.po +236 -197
  261. data/locale/de_DE/LC_MESSAGES/katello.mo +0 -0
  262. data/locale/de_DE/katello.po +236 -197
  263. data/locale/el/LC_MESSAGES/katello.mo +0 -0
  264. data/locale/el/katello.po +236 -197
  265. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  266. data/locale/en/katello.po +236 -197
  267. data/locale/en_GB/LC_MESSAGES/katello.mo +0 -0
  268. data/locale/en_GB/katello.po +236 -197
  269. data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
  270. data/locale/en_US/katello.po +236 -197
  271. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  272. data/locale/es/katello.po +238 -199
  273. data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
  274. data/locale/et_EE/katello.po +236 -197
  275. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  276. data/locale/fr/katello.po +247 -208
  277. data/locale/gl/LC_MESSAGES/katello.mo +0 -0
  278. data/locale/gl/katello.po +236 -197
  279. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  280. data/locale/gu/katello.po +236 -197
  281. data/locale/he_IL/LC_MESSAGES/katello.mo +0 -0
  282. data/locale/he_IL/katello.po +236 -197
  283. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  284. data/locale/hi/katello.po +236 -197
  285. data/locale/id/LC_MESSAGES/katello.mo +0 -0
  286. data/locale/id/katello.po +236 -197
  287. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  288. data/locale/it/katello.po +236 -197
  289. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  290. data/locale/ja/katello.po +247 -208
  291. data/locale/ka/LC_MESSAGES/katello.mo +0 -0
  292. data/locale/ka/katello.po +241 -202
  293. data/locale/katello.pot +1427 -1296
  294. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  295. data/locale/kn/katello.po +236 -197
  296. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  297. data/locale/ko/katello.po +236 -197
  298. data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
  299. data/locale/ml_IN/katello.po +236 -197
  300. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  301. data/locale/mr/katello.po +236 -197
  302. data/locale/nl_NL/LC_MESSAGES/katello.mo +0 -0
  303. data/locale/nl_NL/katello.po +236 -197
  304. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  305. data/locale/or/katello.po +236 -197
  306. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  307. data/locale/pa/katello.po +236 -197
  308. data/locale/pl/LC_MESSAGES/katello.mo +0 -0
  309. data/locale/pl/katello.po +236 -197
  310. data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
  311. data/locale/pl_PL/katello.po +236 -197
  312. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  313. data/locale/pt/katello.po +236 -197
  314. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  315. data/locale/pt_BR/katello.po +238 -199
  316. data/locale/ro/LC_MESSAGES/katello.mo +0 -0
  317. data/locale/ro/katello.po +236 -197
  318. data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
  319. data/locale/ro_RO/katello.po +236 -197
  320. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  321. data/locale/ru/katello.po +236 -197
  322. data/locale/sl/LC_MESSAGES/katello.mo +0 -0
  323. data/locale/sl/katello.po +236 -197
  324. data/locale/sv_SE/LC_MESSAGES/katello.mo +0 -0
  325. data/locale/sv_SE/katello.po +236 -197
  326. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  327. data/locale/ta/katello.po +236 -197
  328. data/locale/ta_IN/LC_MESSAGES/katello.mo +0 -0
  329. data/locale/ta_IN/katello.po +236 -197
  330. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  331. data/locale/te/katello.po +236 -197
  332. data/locale/tr/LC_MESSAGES/katello.mo +0 -0
  333. data/locale/tr/katello.po +236 -197
  334. data/locale/vi/LC_MESSAGES/katello.mo +0 -0
  335. data/locale/vi/katello.po +236 -197
  336. data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
  337. data/locale/vi_VN/katello.po +236 -197
  338. data/locale/zh/LC_MESSAGES/katello.mo +0 -0
  339. data/locale/zh/katello.po +236 -197
  340. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  341. data/locale/zh_CN/katello.po +247 -208
  342. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  343. data/locale/zh_TW/katello.po +236 -197
  344. data/webpack/components/Table/EmptyStateMessage.js +7 -4
  345. data/webpack/components/Table/MainTable.scss +18 -17
  346. data/webpack/components/Table/TableWrapper.js +4 -1
  347. data/webpack/components/extensions/HostDetails/ActionsBar/index.js +45 -4
  348. data/webpack/components/extensions/HostDetails/Cards/ErrataOverviewCard.scss +9 -7
  349. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsCard.js +1 -1
  350. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsModal.js +1 -1
  351. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeActions.js +29 -7
  352. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeCard.js +106 -66
  353. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeCard.scss +6 -0
  354. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeConstants.js +2 -0
  355. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeEditModal.js +53 -29
  356. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeSelectors.js +7 -6
  357. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/__tests__/SystemPurposeCard.test.js +24 -5
  358. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/__tests__/SystemPurposeEditModal.test.js +137 -7
  359. data/webpack/components/extensions/HostDetails/DetailsTabCards/HwPropertiesCard.js +11 -10
  360. data/webpack/components/extensions/HostDetails/DetailsTabCards/RegistrationCard.js +8 -2
  361. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/ErrataTab.js +27 -10
  362. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/HostErrataActions.js +3 -22
  363. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/HostErrataConstants.js +0 -1
  364. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/ModuleStreamsTab.js +3 -2
  365. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackageInstallModal.js +2 -2
  366. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackagesTab.js +48 -12
  367. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionActions.js +22 -10
  368. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionHooks.js +1 -1
  369. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js +2 -2
  370. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/EnableTracerModal.js +71 -5
  371. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/EnableTracerModal.scss +16 -0
  372. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/TracesEnabler.js +4 -1
  373. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/TracesTab.js +6 -2
  374. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packagesTab.test.js +2 -1
  375. data/webpack/components/extensions/HostDetails/Tabs/__tests__/tracesTab.test.js +25 -0
  376. data/webpack/components/extensions/Hosts/ActionsBar/index.js +36 -0
  377. data/webpack/components/extensions/Hosts/constants.js +2 -0
  378. data/webpack/components/extensions/RegistrationCommands/RegistrationCommandsPageHelpers.js +13 -7
  379. data/webpack/components/extensions/RegistrationCommands/__tests__/__snapshots__/ActivationKeys.test.js.snap +9 -1
  380. data/webpack/components/extensions/RegistrationCommands/fields/ActivationKeys.js +87 -22
  381. data/webpack/components/extensions/RegistrationCommands/index.js +17 -41
  382. data/webpack/global_index.js +11 -2
  383. data/webpack/redux/reducers/RedHatRepositories/enabled.fixtures.js +4 -0
  384. data/webpack/redux/reducers/RedHatRepositories/enabled.js +1 -0
  385. data/webpack/scenes/ActivationKeys/Details/ActivationKeyDetails.js +10 -1
  386. data/webpack/scenes/ActivationKeys/Details/ActivationKeyDetails.scss +33 -31
  387. data/webpack/scenes/AlternateContentSources/MainTable/ACSTable.js +3 -1
  388. data/webpack/scenes/Content/ContentConfig.js +3 -0
  389. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +6 -4
  390. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.scss +8 -6
  391. data/webpack/scenes/ContentViews/Delete/ContentViewDeleteWizard.js +1 -0
  392. data/webpack/scenes/ContentViews/Delete/Steps/CVEnvironmentSelectionForm.scss +4 -2
  393. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js +3 -4
  394. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js +2 -2
  395. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ContentViewComponents.js +5 -5
  396. data/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/compositeCVDetails.fixtures.json +393 -0
  397. data/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.test.js +30 -4
  398. data/webpack/scenes/ContentViews/Details/Filters/CVErrataDateFilterContent.js +3 -1
  399. data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +3 -3
  400. data/webpack/scenes/ContentViews/Details/Repositories/RepoIcon.js +2 -1
  401. data/webpack/scenes/ContentViews/Details/Versions/Compare/CVVersionCompareTable.js +1 -1
  402. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersions.js +1 -1
  403. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveCVVersionWizard.js +1 -1
  404. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailsTable.js +1 -1
  405. data/webpack/scenes/ContentViews/Publish/CVPublishForm.js +24 -1
  406. data/webpack/scenes/ContentViews/Publish/PublishContentViewWizard.js +1 -0
  407. data/webpack/scenes/ContentViews/Publish/__tests__/publishContentView.test.js +42 -0
  408. data/webpack/scenes/ContentViews/Publish/cvPublishForm.scss +13 -11
  409. data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +2 -1
  410. data/webpack/scenes/ContentViews/__tests__/mockDetails.fixtures.json +2 -1
  411. data/webpack/scenes/Hosts/ChangeContentSource/index.js +4 -3
  412. data/webpack/scenes/ModuleStreams/Details/ModuleStreamDetails.js +1 -2
  413. data/webpack/scenes/ModuleStreams/Details/__tests__/__snapshots__/ModuleStreamDetails.test.js.snap +1 -1
  414. data/webpack/scenes/RedHatRepositories/RedHatRepositoriesPage.js +2 -1
  415. data/webpack/scenes/RedHatRepositories/__tests__/__snapshots__/RedHatRepositoriesPage.test.js.snap +6 -0
  416. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/EnabledRepository.js +4 -1
  417. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/EnabledRepositoryContent.js +13 -4
  418. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/__tests__/EnabledRepositoryContent.test.js +1 -0
  419. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/__tests__/__snapshots__/EnabledRepository.test.js.snap +1 -0
  420. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/__tests__/__snapshots__/EnabledRepositoryContent.test.js.snap +3 -2
  421. data/webpack/scenes/SmartProxy/AdditionalCapsuleContent.js +93 -0
  422. data/webpack/scenes/SmartProxy/Content.js +12 -4
  423. data/webpack/scenes/SmartProxy/ExpandableCvDetails.js +107 -0
  424. data/webpack/scenes/SmartProxy/ExpandedSmartProxyRepositories.js +139 -0
  425. data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +17 -4
  426. data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +1 -0
  427. data/webpack/scenes/SmartProxy/SmartProxyExpandableTable.js +150 -0
  428. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.fixtures.json +799 -0
  429. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js +29 -17
  430. data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.js +16 -19
  431. data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.scss +12 -8
  432. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +21 -18
  433. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CdnConfigurationForm.scss +4 -2
  434. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.scss +38 -19
  435. data/webpack/scenes/Subscriptions/Manifest/index.js +0 -2
  436. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +38 -12
  437. data/webpack/scenes/Subscriptions/SubscriptionsPage.scss +38 -36
  438. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +16 -13
  439. data/webpack/utils/helpers.js +0 -1
  440. metadata +99 -33
  441. data/app/controllers/katello/concerns/api/v2/bulk_hosts_extensions.rb +0 -47
  442. data/webpack/components/Table/TableHooks.js +0 -315
  443. data/webpack/components/Table/__test__/useBulkSelect.test.js +0 -99
  444. data/webpack/components/extensions/RegistrationCommands/__tests__/LifeCycleEnvironment.test.js +0 -11
  445. data/webpack/components/extensions/RegistrationCommands/__tests__/__snapshots__/LifeCycleEnvironment.test.js.snap +0 -29
  446. data/webpack/components/extensions/RegistrationCommands/fields/LifecycleEnvironment.js +0 -57
  447. data/webpack/scenes/SmartProxy/SmartProxyContentTable.js +0 -164
  448. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentResult.fixtures.json +0 -140
  449. data/webpack/scenes/Subscriptions/Manifest/Manifest.scss +0 -16
@@ -134,7 +134,7 @@ module Katello
134
134
 
135
135
  def token
136
136
  if !require_user_authorization?
137
- personal_token = OpenStruct.new(token: 'unauthenticated', issued_at: Time.now, expires_at: Time.now + 3)
137
+ personal_token = OpenStruct.new(token: 'unauthenticated', issued_at: Time.now, expires_at: 3.minutes.from_now)
138
138
  else
139
139
  personal_token = PersonalAccessToken.where(user_id: User.current.id, name: 'registry').first
140
140
  if personal_token.nil?
@@ -147,8 +147,21 @@ module Katello
147
147
  end
148
148
  end
149
149
 
150
+ create_time = (personal_token.created_at || personal_token.issued_at).to_time
151
+ expiry_time = personal_token.expires_at.to_time
152
+ expiration_seconds = (expiry_time - create_time).to_int # result already in seconds
153
+
150
154
  response.headers['Docker-Distribution-API-Version'] = 'registry/2.0'
151
- render json: { token: personal_token.token, expires_at: personal_token.expires_at, issued_at: personal_token.created_at }
155
+ render json: {
156
+ token: personal_token.token,
157
+ expires_in: expiration_seconds,
158
+ issued_at: create_time.rfc3339,
159
+
160
+ # We're keeping the 'expires_at' field for now to maintain compatibility with existing
161
+ # smart-proxies during 4.11 upgrades. This is not a part of OAuth2 spec.
162
+ # TODO - Remove 'expires_at' in Katello 4.13 or later.
163
+ expires_at: expiry_time.rfc3339
164
+ }
152
165
  end
153
166
 
154
167
  def pull_manifest
@@ -20,6 +20,19 @@ module Katello
20
20
  param :environment_id, Integer, :desc => N_('Id of the lifecycle environment'), :required => true
21
21
  end
22
22
 
23
+ api :GET, '/capsules/:id/content/counts', N_('List content counts for the smart proxy')
24
+ param :id, Integer, :desc => N_('Id of the smart proxy'), :required => true
25
+ def counts
26
+ render json: @capsule.content_counts.to_json
27
+ end
28
+
29
+ api :POST, '/capsules/:id/content/update_counts', N_('Update content counts for the smart proxy')
30
+ param :id, Integer, :desc => N_('Id of the smart proxy'), :required => true
31
+ def update_counts
32
+ task = async_task(::Actions::Katello::CapsuleContent::UpdateContentCounts, @capsule)
33
+ respond_for_async :resource => task
34
+ end
35
+
23
36
  api :GET, '/capsules/:id/content/lifecycle_environments', N_('List the lifecycle environments attached to the smart proxy')
24
37
  param_group :lifecycle_environments
25
38
  def lifecycle_environments
@@ -60,12 +73,16 @@ module Katello
60
73
  find_content_view if params[:content_view_id]
61
74
  find_repository if params[:repository_id]
62
75
  skip_metadata_check = ::Foreman::Cast.to_bool(params[:skip_metadata_check])
76
+ sync_options = {
77
+ :environment_id => @environment.try(:id),
78
+ :content_view_id => @content_view.try(:id),
79
+ :repository_id => @repository.try(:id),
80
+ :skip_metadata_check => skip_metadata_check
81
+ }
82
+ sync_options[:environment_ids] = @capsule.lifecycle_environments&.pluck(:id) unless (@environment || @content_view || @repository)
63
83
  task = async_task(::Actions::Katello::CapsuleContent::Sync,
64
84
  @capsule,
65
- :environment_id => @environment.try(:id),
66
- :content_view_id => @content_view.try(:id),
67
- :repository_id => @repository.try(:id),
68
- :skip_metadata_check => skip_metadata_check)
85
+ sync_options)
69
86
  respond_for_async :resource => task
70
87
  end
71
88
 
@@ -4,6 +4,9 @@ module Katello
4
4
  api_base_url "/katello/api"
5
5
  end
6
6
 
7
+ skip_before_action :find_resource, only: [:show]
8
+ before_action :find_smart_proxy, :only => [:show]
9
+
7
10
  api :GET, '/capsules', 'List all smart proxies that have content'
8
11
  param_group :search, Api::V2::ApiController
9
12
  def index
@@ -15,7 +18,6 @@ module Katello
15
18
  api :GET, '/capsules/:id', 'Show the smart proxy details'
16
19
  param :id, Integer, :desc => 'Id of the smart proxy', :required => true
17
20
  def show
18
- super
19
21
  end
20
22
 
21
23
  def resource_name
@@ -31,5 +33,13 @@ module Katello
31
33
  def authorized
32
34
  User.current.allowed_to?(params.slice(:action, :id).merge(controller: 'api/v2/smart_proxies'))
33
35
  end
36
+
37
+ # Without this method, Foreman requires non-admin users to be admin or have a
38
+ # non-existent "view_capsule" permission. By replacing the find_resource
39
+ # before action, we check the user for "view_smart_proxies" permission instead.
40
+ def find_smart_proxy
41
+ resource_scope = SmartProxy.authorized("view_smart_proxies", SmartProxy)
42
+ instance_variable_set("@smart_proxy", resource_finder(resource_scope, params[:id]))
43
+ end
34
44
  end
35
45
  end
@@ -1,6 +1,6 @@
1
1
  module Katello
2
2
  class Api::V2::ContentViewVersionsController < Api::V2::ApiController
3
- include Concerns::Api::V2::BulkHostsExtensions
3
+ include ::Api::V2::BulkHostsExtension
4
4
  include Katello::Concerns::FilteredAutoCompleteSearch
5
5
 
6
6
  before_action :find_authorized_katello_resource, :only => [:show, :update, :promote, :destroy, :republish_repositories]
@@ -4,6 +4,7 @@ module Katello
4
4
  include Katello::Concerns::Api::V2::RepositoryContentController
5
5
 
6
6
  before_action :find_repositories, :only => [:auto_complete_name]
7
+ before_action :find_optional_organization, :only => [:repositories, :index, :show, :auto_complete_search]
7
8
 
8
9
  def auto_complete_name
9
10
  page_size = Katello::Concerns::FilteredAutoCompleteSearch::PAGE_SIZE
@@ -31,6 +32,7 @@ module Katello
31
32
 
32
33
  if tag.repositories.size > 1 #pulp3
33
34
  repos = tag.repositories.non_archived
35
+ repos = repos.in_organization(@organization) if @organization
34
36
  else
35
37
  repos = []
36
38
  tag.related_tags.each do |related|
@@ -1,6 +1,7 @@
1
1
  module Katello
2
+ # this is Katello's host bulk actions controller, not to be confused with Foreman's
2
3
  class Api::V2::HostsBulkActionsController < Api::V2::ApiController
3
- include Concerns::Api::V2::BulkHostsExtensions
4
+ include ::Api::V2::BulkHostsExtension
4
5
  include Katello::Concerns::Api::V2::ContentOverridesController
5
6
  include Katello::ContentSourceHelper
6
7
  include ::Foreman::Renderer::Scope::Macros::Base
@@ -56,7 +56,7 @@ module Katello
56
56
  api :PUT, '/organizations/:id', N_('Update organization')
57
57
  param :id, :number, :desc => N_("organization ID"), :required => true
58
58
  param :redhat_repository_url, String, :desc => N_("Red Hat CDN URL"), deprecated: true
59
- param :simple_content_access, :bool, :desc => N_('Whether Simple Content Access should be enabled for the organization.'), :required => false, :default => true
59
+ param :simple_content_access, :bool, :desc => N_('Whether Simple Content Access should be enabled for the organization.'), :required => false, :default => true, deprecated: true
60
60
  param_group :resource
61
61
  def update
62
62
  if params[:redhat_repository_url]
@@ -80,7 +80,7 @@ module Katello
80
80
  param :organization, Hash do
81
81
  param :label, String, :required => false
82
82
  end
83
- param :simple_content_access, :bool, :desc => N_('Whether to turn on Simple Content Access for the organization.'), :required => false, :default => true
83
+ param :simple_content_access, :bool, :desc => N_('Whether to turn on Simple Content Access for the organization.'), :required => false, :default => true, deprecated: true
84
84
  def create
85
85
  @organization = Organization.new(resource_params)
86
86
  sca = params.key?(:simple_content_access) ? ::Foreman::Cast.to_bool(params[:simple_content_access]) : true
@@ -348,6 +348,7 @@ Alternatively, use the 'force' parameter to regenerate metadata locally. On the
348
348
  param :skip_metadata_check, :bool, :desc => N_("Force sync even if no upstream changes are detected. Only used with yum or deb repositories."), :required => false
349
349
  param :validate_contents, :bool, :desc => N_("Force a sync and validate the checksums of all content. Only used with yum repositories."), :required => false
350
350
  def sync
351
+ fail HttpErrors::BadRequest, _("attempted to sync a non-library repository.") unless @repository.library_instance?
351
352
  sync_options = {
352
353
  :skip_metadata_check => ::Foreman::Cast.to_bool(params[:skip_metadata_check]),
353
354
  :validate_contents => ::Foreman::Cast.to_bool(params[:validate_contents]),
@@ -8,15 +8,15 @@ module Katello
8
8
  end
9
9
 
10
10
  api :GET, "/organizations/:organization_id/simple_content_access/eligible",
11
- N_("Check if the specified organization is eligible for Simple Content Access")
11
+ N_("Check if the specified organization is eligible for Simple Content Access. %s") % sca_only_deprecation_text, deprecated: true
12
12
  def eligible
13
- ::Foreman::Deprecation.api_deprecation_warning("This endpoint is deprecated and will be removed in a future release. All organizations are now eligible for Simple Content Access.")
13
+ ::Foreman::Deprecation.api_deprecation_warning("This endpoint is deprecated and will be removed in Katello 4.12. All organizations are now eligible for Simple Content Access.")
14
14
  eligible = @organization.simple_content_access_eligible?
15
15
  render json: { simple_content_access_eligible: eligible }
16
16
  end
17
17
 
18
18
  api :GET, "/organizations/:organization_id/simple_content_access/status",
19
- N_("Check if the specified organization has Simple Content Access enabled")
19
+ N_("Check if the specified organization has Simple Content Access enabled. %s") % sca_only_deprecation_text, deprecated: true
20
20
  param :organization_id, :number, :desc => N_("Organization ID"), :required => true
21
21
  def status
22
22
  status = @organization.simple_content_access?
@@ -24,7 +24,7 @@ module Katello
24
24
  end
25
25
 
26
26
  api :PUT, "/organizations/:organization_id/simple_content_access/enable",
27
- N_("Enable simple content access for a manifest")
27
+ N_("Enable simple content access for a manifest"), deprecated: true
28
28
  param :organization_id, :number, :desc => N_("Organization ID"), :required => true
29
29
  def enable
30
30
  task = async_task(::Actions::Katello::Organization::SimpleContentAccess::Enable, params[:organization_id])
@@ -32,7 +32,7 @@ module Katello
32
32
  end
33
33
 
34
34
  api :PUT, "/organizations/:organization_id/simple_content_access/disable",
35
- N_("Disable simple content access for a manifest")
35
+ N_("Disable simple content access for a manifest. %s") % sca_only_deprecation_text, deprecated: true
36
36
  param :organization_id, :number, :desc => N_("Organization ID"), :required => true
37
37
  def disable
38
38
  task = async_task(::Actions::Katello::Organization::SimpleContentAccess::Disable, params[:organization_id])
@@ -8,6 +8,7 @@ module Katello
8
8
  :add_products, :remove_products]
9
9
  before_action :set_organization, :only => [:update, :show, :destroy, :sync,
10
10
  :add_products, :remove_products]
11
+ before_action :validate_sync_plan_products, :only => [:update, :add_products, :remove_products]
11
12
 
12
13
  def_param_group :sync_plan do
13
14
  param :name, String, :desc => N_("sync plan name"), :required => true, :action_aware => true
@@ -93,8 +94,9 @@ module Katello
93
94
  param :product_ids, Array, :desc => N_("List of product ids to add to the sync plan"), :required => true
94
95
  def add_products
95
96
  products = ::Katello::Product.where(:id => params[:product_ids]).editable
97
+ disabled_products = products.select { |p| p.redhat? && !p.enabled? }
98
+ fail _("Cannot add disabled products to sync plan!") if disabled_products.present?
96
99
  @sync_plan.product_ids = (@sync_plan.product_ids + products.collect { |p| p.id }).uniq
97
- @sync_plan.save!
98
100
  respond_for_show
99
101
  end
100
102
 
@@ -104,8 +106,10 @@ module Katello
104
106
  param :product_ids, Array, :desc => N_("List of product ids to remove from the sync plan"), :required => true
105
107
  def remove_products
106
108
  products = ::Katello::Product.where(:id => params[:product_ids]).editable
107
- @sync_plan.product_ids = (@sync_plan.product_ids - products.collect { |p| p.id }).uniq
108
- @sync_plan.save!
109
+ begin
110
+ @sync_plan.product_ids = (@sync_plan.product_ids - products.collect { |p| p.id }).uniq
111
+ end
112
+
109
113
  respond_for_show
110
114
  end
111
115
 
@@ -127,5 +131,9 @@ module Katello
127
131
  def set_organization
128
132
  @organization ||= @sync_plan.try(:organization)
129
133
  end
134
+
135
+ def validate_sync_plan_products
136
+ @sync_plan.validate_and_update_products force_update: true
137
+ end
130
138
  end
131
139
  end
@@ -17,6 +17,12 @@ module Katello
17
17
  User.current
18
18
  end
19
19
 
20
+ class_methods do
21
+ def sca_only_deprecation_text
22
+ N_("WARNING: Simple Content Access will be required for all organizations in Katello 4.12.")
23
+ end
24
+ end
25
+
20
26
  protected
21
27
 
22
28
  def request_from_katello_cli?
@@ -0,0 +1,23 @@
1
+ module Katello
2
+ module Concerns
3
+ # overrides Foreman Api::V2::HostsBulkActionsController
4
+ module Api::V2::HostsBulkActionsControllerExtensions
5
+ extend ActiveSupport::Concern
6
+ require 'active_support/core_ext/string/inflections'
7
+
8
+ module Overrides
9
+ def bulk_destroy
10
+ destroyed_count = @hosts.count
11
+ @hosts.in_batches.each_record do |host|
12
+ Katello::RegistrationManager.unregister_host(host, :unregistering => false)
13
+ end
14
+ process_response(true, { :message => _("Deleted %{host_count} %{hosts}") % { :host_count => destroyed_count, :hosts => 'host'.pluralize(destroyed_count) }})
15
+ end
16
+ end
17
+
18
+ included do
19
+ prepend Overrides
20
+ end
21
+ end
22
+ end
23
+ end
@@ -7,7 +7,7 @@ module Katello
7
7
 
8
8
  def auto_complete_search
9
9
  begin
10
- options = resource_class.respond_to?(:completer_scope_options) ? resource_class.completer_scope_options : {}
10
+ options = resource_class.respond_to?(:completer_scope_options) ? resource_class.completer_scope_options(params[:search]) : {}
11
11
  items = resource_class.where(:id => self.index_relation).complete_for(params[:search], options)
12
12
  items = items.map do |item|
13
13
  category = ['and', 'or', 'not', 'has'].include?(item.to_s.sub(/^.*\s+/, '')) ? _('Operators') : ''
@@ -25,6 +25,7 @@ module Katello
25
25
  begin
26
26
  @taxonomy = Organization.new(resource_params)
27
27
  sca = ::Foreman::Cast.to_bool(params[:simple_content_access])
28
+ ::Foreman::Deprecation.api_deprecation_warning("Simple Content Access will be required for all organizations in Katello 4.12.")
28
29
  ::Katello::OrganizationCreator.new(@taxonomy, sca: sca).create!
29
30
  @taxonomy.reload
30
31
  switch_taxonomy
@@ -47,6 +48,7 @@ module Katello
47
48
  def update
48
49
  return if params[:simple_content_access].nil?
49
50
  sca_param = ::Foreman::Cast.to_bool(params[:simple_content_access])
51
+ ::Foreman::Deprecation.api_deprecation_warning("Simple Content Access will be required for all organizations in Katello 4.12.")
50
52
  if sca_param && !@taxonomy.simple_content_access?(cached: false)
51
53
  # user has requested SCA enable
52
54
  sync_task(::Actions::Katello::Organization::SimpleContentAccess::Enable, params[:id])
@@ -1,7 +1,7 @@
1
1
  module Katello
2
2
  if Katello.with_remote_execution?
3
3
  class RemoteExecutionController < JobInvocationsController
4
- include Concerns::Api::V2::BulkHostsExtensions
4
+ include ::Api::V2::BulkHostsExtension
5
5
  include Concerns::Api::V2::HostErrataExtensions
6
6
 
7
7
  def new
@@ -0,0 +1,11 @@
1
+ class CreateHostLifecycleExpireSoonNotifications < ApplicationJob
2
+ def perform
3
+ Katello::UINotifications::Hosts::LifecycleExpireSoon.deliver!
4
+ ensure
5
+ self.class.set(:wait => 1.week).perform_later
6
+ end
7
+
8
+ def humanized_name
9
+ _('Host lifecycle support expiration notification')
10
+ end
11
+ end
@@ -8,14 +8,24 @@ module Actions
8
8
  end
9
9
 
10
10
  def run
11
+ error = false
11
12
  input[:host_ids].each do |host_id|
12
13
  content_facet = ::Katello::Host::ContentFacet.find_by_host_id(host_id)
13
14
  if content_facet.present?
15
+ # Catch errors and log them, but continue processing the rest of the hosts
14
16
  content_facet.calculate_and_import_applicability
15
17
  else
16
18
  Rails.logger.warn(_("Content Facet for host with id %s is non-existent. Skipping applicability calculation.") % host_id)
17
19
  end
20
+ rescue NoMethodError, PG::Error => e
21
+ Rails.logger.error("Error calculating applicability for host #{host_id}: #{e.message}")
22
+ error = true
18
23
  end
24
+ fail "Error calculating applicability for one or more hosts" if error
25
+ end
26
+
27
+ def rescue_strategy
28
+ Dynflow::Action::Rescue::Skip
19
29
  end
20
30
 
21
31
  def queue
@@ -18,7 +18,8 @@ module Actions
18
18
  plan_self(:smart_proxy_id => smart_proxy.id,
19
19
  :environment_id => options[:environment]&.id,
20
20
  :content_view_id => options[:content_view]&.id,
21
- :repository_id => options[:repository]&.id)
21
+ :repository_id => options[:repository]&.id,
22
+ :repository_ids_list => options[:repository_ids_list])
22
23
  end
23
24
 
24
25
  def invoke_external_task
@@ -33,7 +34,12 @@ module Actions
33
34
  current_repos_on_capsule = smart_proxy_service.current_repositories(environment, content_view)
34
35
  current_repos_on_capsule_ids = current_repos_on_capsule.pluck(:id)
35
36
 
36
- list_of_repos_to_sync = smart_proxy_helper.combined_repos_available_to_capsule(environment, content_view, repository)
37
+ if input[:repository_ids_list].nil?
38
+ list_of_repos_to_sync = smart_proxy_helper.combined_repos_available_to_capsule(environment, content_view, repository)
39
+ else
40
+ list_of_repos_to_sync = ::Katello::Repository.where(:id => input[:repository_ids_list])
41
+ end
42
+
37
43
  list_of_repos_to_sync.each do |repo|
38
44
  next unless act_on_repo?(repo, smart_proxy)
39
45
 
@@ -2,10 +2,13 @@ module Actions
2
2
  module Katello
3
3
  module CapsuleContent
4
4
  class Sync < ::Actions::EntryAction
5
+ include ::Actions::ObservableAction
5
6
  def resource_locks
6
7
  :link
7
8
  end
8
9
 
10
+ execution_plan_hooks.use :notify_on_failure, :on => [:failure, :paused]
11
+
9
12
  input_format do
10
13
  param :name
11
14
  end
@@ -19,24 +22,19 @@ module Actions
19
22
  end
20
23
 
21
24
  def plan(smart_proxy, options = {})
25
+ input[:options] = options
26
+
22
27
  action_subject(smart_proxy)
23
28
  smart_proxy.verify_ueber_certs
24
- environment_id = options.fetch(:environment_id, nil)
25
- environment = ::Katello::KTEnvironment.find(environment_id) if environment_id
26
- repository_id = options.fetch(:repository_id, nil)
27
- repository = ::Katello::Repository.find(repository_id) if repository_id
28
- content_view_id = options.fetch(:content_view_id, nil)
29
- content_view = ::Katello::ContentView.find(content_view_id) if content_view_id
29
+
30
+ subjects = subjects(options)
30
31
 
31
32
  fail _("Action not allowed for the default smart proxy.") if smart_proxy.pulp_primary?
32
33
 
33
- refresh_options = options.merge(content_view: content_view,
34
- environment: environment,
35
- repository: repository)
34
+ refresh_options = options.merge(subjects)
36
35
  sequence do
37
36
  if smart_proxy.has_feature?(SmartProxy::PULP3_FEATURE)
38
37
  plan_action(Actions::Pulp3::ContentGuard::Refresh, smart_proxy)
39
- plan_action(Actions::Pulp3::Orchestration::Repository::RefreshRepos, smart_proxy, refresh_options)
40
38
  end
41
39
  plan_action(SyncCapsule, smart_proxy, refresh_options)
42
40
  end
@@ -49,6 +47,28 @@ module Actions
49
47
  smart_proxy&.audit_capsule_sync
50
48
  end
51
49
  end
50
+
51
+ def notify_on_failure(_plan)
52
+ notification = MailNotification[:proxy_sync_failure]
53
+ proxy = SmartProxy.find(input.fetch(:smart_proxy, {})[:id])
54
+ subjects = subjects(input[:options]).merge(smart_proxy: proxy)
55
+ notification.users.where(disabled: [nil, false], mail_enabled: true).each do |user|
56
+ notification.deliver(subjects.merge(user: user, task: task))
57
+ end
58
+ end
59
+
60
+ def subjects(options = {})
61
+ environment_id = options.fetch(:environment_id, nil)
62
+ environment = ::Katello::KTEnvironment.find(environment_id) if environment_id
63
+
64
+ repository_id = options.fetch(:repository_id, nil)
65
+ repository = ::Katello::Repository.find(repository_id) if repository_id
66
+
67
+ content_view_id = options.fetch(:content_view_id, nil)
68
+ content_view = ::Katello::ContentView.find(content_view_id) if content_view_id
69
+
70
+ {content_view: content_view, environment: environment, repository: repository}
71
+ end
52
72
  end
53
73
  end
54
74
  end
@@ -3,6 +3,7 @@ module Actions
3
3
  module CapsuleContent
4
4
  class SyncCapsule < ::Actions::EntryAction
5
5
  # rubocop:disable Metrics/MethodLength
6
+ execution_plan_hooks.use :update_content_counts, :on => :success
6
7
  def plan(smart_proxy, options = {})
7
8
  plan_self(:smart_proxy_id => smart_proxy.id)
8
9
  action_subject(smart_proxy)
@@ -14,6 +15,13 @@ module Actions
14
15
  repos = repos_to_sync(smart_proxy, environment, content_view, repository, skip_metadata_check)
15
16
  return nil if repos.empty?
16
17
 
18
+ if environment.nil? && content_view.nil? && repository.nil?
19
+ options[:repository_ids_list] = repos.pluck(:id)
20
+ end
21
+ if smart_proxy.has_feature?(SmartProxy::PULP3_FEATURE)
22
+ plan_action(Actions::Pulp3::Orchestration::Repository::RefreshRepos, smart_proxy, options)
23
+ end
24
+
17
25
  repos.in_groups_of(Setting[:foreman_proxy_content_batch_size], false) do |repo_batch|
18
26
  concurrence do
19
27
  repo_batch.each do |repo|
@@ -60,6 +68,11 @@ module Actions
60
68
  end
61
69
  end
62
70
 
71
+ def update_content_counts(_execution_plan)
72
+ smart_proxy = ::SmartProxy.unscoped.find(input[:smart_proxy_id])
73
+ ::ForemanTasks.async_task(::Actions::Katello::CapsuleContent::UpdateContentCounts, smart_proxy)
74
+ end
75
+
63
76
  def resource_locks
64
77
  :link
65
78
  end
@@ -0,0 +1,24 @@
1
+ module Actions
2
+ module Katello
3
+ module CapsuleContent
4
+ class UpdateContentCounts < Actions::EntryAction
5
+ def plan(smart_proxy)
6
+ plan_self(:smart_proxy_id => smart_proxy.id)
7
+ end
8
+
9
+ def humanized_name
10
+ _("Update Content Counts")
11
+ end
12
+
13
+ def run
14
+ smart_proxy = ::SmartProxy.unscoped.find(input[:smart_proxy_id])
15
+ smart_proxy.update_content_counts!
16
+ end
17
+
18
+ def rescue_strategy
19
+ Dynflow::Action::Rescue::Skip
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,6 +4,7 @@ module Actions
4
4
  class Promote < Actions::EntryAction
5
5
  extend ApipieDSL::Class
6
6
  include ::Actions::ObservableAction
7
+ execution_plan_hooks.use :notify_on_failure, :on => [:failure, :paused]
7
8
 
8
9
  def plan(version, environments, is_force = false, description = nil, incremental_update = false)
9
10
  action_subject(version.content_view)
@@ -23,6 +24,14 @@ module Actions
23
24
  end
24
25
  end
25
26
 
27
+ def notify_on_failure(_plan)
28
+ notification = MailNotification[:content_view_promote_failure]
29
+ view = ::Katello::ContentView.find(input.fetch(:content_view, {})[:id])
30
+ notification.users.where(disabled: [nil, false], mail_enabled: true).each do |user|
31
+ notification.deliver(user: user, content_view: view, task: task)
32
+ end
33
+ end
34
+
26
35
  def environments
27
36
  input['environments']
28
37
  end
@@ -7,6 +7,7 @@ module Actions
7
7
  include ::Actions::ObservableAction
8
8
  attr_accessor :version
9
9
  execution_plan_hooks.use :trigger_capsule_sync, :on => :success
10
+ execution_plan_hooks.use :notify_on_failure, :on => [:failure, :paused]
10
11
 
11
12
  # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity
12
13
  def plan(content_view, description = "", options = {importing: false, syncable: false}) # rubocop:disable Metrics/PerceivedComplexity
@@ -132,6 +133,14 @@ module Actions
132
133
  end
133
134
  end
134
135
 
136
+ def notify_on_failure(_plan)
137
+ notification = MailNotification[:content_view_publish_failure]
138
+ view = ::Katello::ContentView.find(input.fetch(:content_view, {})[:id])
139
+ notification.users.where(disabled: [nil, false], mail_enabled: true).each do |user|
140
+ notification.deliver(user: user, content_view: view, task: task)
141
+ end
142
+ end
143
+
135
144
  def content_view_version_id
136
145
  input['content_view_version_id']
137
146
  end
@@ -15,9 +15,17 @@ module Actions
15
15
  plan_action(
16
16
  Actions::Pulp3::Orchestration::OrphanCleanup::RemoveOrphans,
17
17
  proxy)
18
+ plan_self(:smart_proxy_id => proxy.id)
18
19
  end
19
20
  end
20
21
  end
22
+
23
+ def finalize
24
+ smart_proxy = ::SmartProxy.unscoped.find(input[:smart_proxy_id])
25
+ if smart_proxy.pulp_mirror?
26
+ ::ForemanTasks.async_task(::Actions::Katello::CapsuleContent::UpdateContentCounts, smart_proxy)
27
+ end
28
+ end
21
29
  end
22
30
  end
23
31
  end
@@ -8,6 +8,8 @@ module Actions
8
8
  include ::Actions::ObservableAction
9
9
  middleware.use Actions::Middleware::ExecuteIfContentsChanged
10
10
 
11
+ execution_plan_hooks.use :notify_on_failure, :on => [:failure, :paused]
12
+
11
13
  input_format do
12
14
  param :id, Integer
13
15
  param :sync_result, Hash
@@ -83,6 +85,7 @@ module Actions
83
85
  def validate_repo!(repo:, source_url:, skip_metadata_check:, skip_candlepin_check:)
84
86
  fail ::Katello::Errors::InvalidActionOptionError, _("Unable to sync repo. This repository does not have a feed url.") if repo.url.blank? && source_url.blank?
85
87
  fail ::Katello::Errors::InvalidActionOptionError, _("Cannot skip metadata check on non-yum/deb repositories.") if skip_metadata_check && !repo.yum? && !repo.deb?
88
+ fail ::Katello::Errors::InvalidActionOptionError, _("Unable to sync repo. This repository is not a library instance repository.") unless repo.library_instance?
86
89
  ::Katello::Util::CandlepinRepositoryChecker.check_repository_for_sync!(repo) if repo.yum? && !skip_candlepin_check
87
90
  end
88
91
 
@@ -96,6 +99,14 @@ module Actions
96
99
  Dynflow::Action::Rescue::Skip
97
100
  end
98
101
 
102
+ def notify_on_failure(_plan)
103
+ notification = MailNotification[:repository_sync_failure]
104
+ repo = ::Katello::Repository.find(input.fetch(:repository, {})[:id])
105
+ notification.users.where(disabled: [nil, false], mail_enabled: true).each do |user|
106
+ notification.deliver(user: user, repo: repo, task: task)
107
+ end
108
+ end
109
+
99
110
  def repository_id
100
111
  input['repository']['id']
101
112
  end
@@ -3,6 +3,7 @@ module Actions
3
3
  module CapsuleContent
4
4
  class ReclaimSpace < Pulp3::AbstractAsyncTask
5
5
  def plan(smart_proxy)
6
+ action_subject(smart_proxy)
6
7
  if smart_proxy.pulp_primary?
7
8
  repository_hrefs = ::Katello::Pulp3::RepositoryReference.default_cv_repository_hrefs(::Katello::Repository.unscoped.on_demand, ::Organization.all)
8
9
  repository_hrefs.flatten!
@@ -20,6 +21,10 @@ module Actions
20
21
  output[:pulp_tasks] = ::Katello::Pulp3::Api::Core.new(SmartProxy.find(input[:smart_proxy_id])).
21
22
  repositories_reclaim_space_api.reclaim(repo_hrefs: input[:repository_hrefs])
22
23
  end
24
+
25
+ def rescue_strategy
26
+ Dynflow::Action::Rescue::Skip
27
+ end
23
28
  end
24
29
  end
25
30
  end
@@ -16,11 +16,16 @@ module Actions
16
16
  param :exported_file_checksum, String
17
17
  end
18
18
 
19
- def run
19
+ def run # rubocop:disable Metrics/AbcSize
20
20
  smart_proxy = ::SmartProxy.unscoped.find(input[:smart_proxy_id])
21
21
  api = ::Katello::Pulp3::Api::Core.new(smart_proxy)
22
22
  export_data = api.export_api.list(input[:exporter_data][:pulp_href]).results.first
23
23
  output[:exported_file_checksum] = export_data.output_file_info
24
+ if output[:exported_file_checksum].blank?
25
+ output[:export_history_id] = nil
26
+ output[:message] = _("Export failed: One or more repositories needs to be synced (with Immediate download policy.)")
27
+ return
28
+ end
24
29
  file_name = output[:exported_file_checksum].first&.first
25
30
  path = File.dirname(file_name.to_s)
26
31
  output[:path] = path