katello 4.13.0 → 4.14.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 (341) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/hosts/host_and_hostgroup_edit.js +12 -8
  3. data/app/assets/javascripts/katello/locale/bn/katello.js +274 -22
  4. data/app/assets/javascripts/katello/locale/bn_IN/katello.js +274 -22
  5. data/app/assets/javascripts/katello/locale/ca/katello.js +274 -22
  6. data/app/assets/javascripts/katello/locale/cs/katello.js +274 -22
  7. data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +275 -23
  8. data/app/assets/javascripts/katello/locale/de/katello.js +280 -28
  9. data/app/assets/javascripts/katello/locale/de_AT/katello.js +274 -22
  10. data/app/assets/javascripts/katello/locale/de_DE/katello.js +274 -22
  11. data/app/assets/javascripts/katello/locale/el/katello.js +274 -22
  12. data/app/assets/javascripts/katello/locale/en/katello.js +274 -22
  13. data/app/assets/javascripts/katello/locale/en_GB/katello.js +274 -22
  14. data/app/assets/javascripts/katello/locale/en_US/katello.js +274 -22
  15. data/app/assets/javascripts/katello/locale/es/katello.js +276 -24
  16. data/app/assets/javascripts/katello/locale/et_EE/katello.js +274 -22
  17. data/app/assets/javascripts/katello/locale/fr/katello.js +283 -31
  18. data/app/assets/javascripts/katello/locale/gl/katello.js +274 -22
  19. data/app/assets/javascripts/katello/locale/gu/katello.js +274 -22
  20. data/app/assets/javascripts/katello/locale/he_IL/katello.js +274 -22
  21. data/app/assets/javascripts/katello/locale/hi/katello.js +274 -22
  22. data/app/assets/javascripts/katello/locale/id/katello.js +274 -22
  23. data/app/assets/javascripts/katello/locale/it/katello.js +274 -22
  24. data/app/assets/javascripts/katello/locale/ja/katello.js +283 -31
  25. data/app/assets/javascripts/katello/locale/ka/katello.js +280 -28
  26. data/app/assets/javascripts/katello/locale/kn/katello.js +274 -22
  27. data/app/assets/javascripts/katello/locale/ko/katello.js +274 -22
  28. data/app/assets/javascripts/katello/locale/ml_IN/katello.js +274 -22
  29. data/app/assets/javascripts/katello/locale/mr/katello.js +274 -22
  30. data/app/assets/javascripts/katello/locale/nl_NL/katello.js +274 -22
  31. data/app/assets/javascripts/katello/locale/or/katello.js +274 -22
  32. data/app/assets/javascripts/katello/locale/pa/katello.js +274 -22
  33. data/app/assets/javascripts/katello/locale/pl/katello.js +274 -22
  34. data/app/assets/javascripts/katello/locale/pl_PL/katello.js +274 -22
  35. data/app/assets/javascripts/katello/locale/pt/katello.js +274 -22
  36. data/app/assets/javascripts/katello/locale/pt_BR/katello.js +276 -24
  37. data/app/assets/javascripts/katello/locale/ro/katello.js +274 -22
  38. data/app/assets/javascripts/katello/locale/ro_RO/katello.js +274 -22
  39. data/app/assets/javascripts/katello/locale/ru/katello.js +274 -22
  40. data/app/assets/javascripts/katello/locale/sl/katello.js +274 -22
  41. data/app/assets/javascripts/katello/locale/sv_SE/katello.js +274 -22
  42. data/app/assets/javascripts/katello/locale/ta/katello.js +274 -22
  43. data/app/assets/javascripts/katello/locale/ta_IN/katello.js +274 -22
  44. data/app/assets/javascripts/katello/locale/te/katello.js +274 -22
  45. data/app/assets/javascripts/katello/locale/tr/katello.js +274 -22
  46. data/app/assets/javascripts/katello/locale/vi/katello.js +274 -22
  47. data/app/assets/javascripts/katello/locale/vi_VN/katello.js +274 -22
  48. data/app/assets/javascripts/katello/locale/zh/katello.js +274 -22
  49. data/app/assets/javascripts/katello/locale/zh_CN/katello.js +283 -31
  50. data/app/assets/javascripts/katello/locale/zh_TW/katello.js +274 -22
  51. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +118 -74
  52. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +15 -2
  53. data/app/controllers/katello/api/v2/activation_keys_controller.rb +1 -1
  54. data/app/controllers/katello/api/v2/api_controller.rb +7 -0
  55. data/app/controllers/katello/api/v2/content_view_versions_controller.rb +4 -4
  56. data/app/controllers/katello/api/v2/debs_controller.rb +3 -2
  57. data/app/controllers/katello/api/v2/environments_controller.rb +2 -4
  58. data/app/controllers/katello/api/v2/host_contents_controller.rb +8 -3
  59. data/app/controllers/katello/api/v2/host_errata_controller.rb +4 -4
  60. data/app/controllers/katello/api/v2/host_packages_controller.rb +2 -2
  61. data/app/controllers/katello/api/v2/organizations_controller.rb +1 -1
  62. data/app/controllers/katello/api/v2/packages_controller.rb +13 -3
  63. data/app/controllers/katello/api/v2/repositories_bulk_actions_controller.rb +6 -2
  64. data/app/controllers/katello/api/v2/repositories_controller.rb +3 -4
  65. data/app/controllers/katello/api/v2/repository_sets_controller.rb +13 -14
  66. data/app/controllers/katello/api/v2/subscriptions_controller.rb +15 -9
  67. data/app/controllers/katello/api/v2/sync_controller.rb +2 -2
  68. data/app/controllers/katello/application_controller.rb +1 -1
  69. data/app/controllers/katello/concerns/api/v2/authorization.rb +3 -2
  70. data/app/controllers/katello/concerns/api/v2/hosts_controller_extensions.rb +28 -0
  71. data/app/controllers/katello/concerns/api/v2/registration_commands_controller_extensions.rb +1 -1
  72. data/app/controllers/katello/concerns/api/v2/repository_content_controller.rb +4 -3
  73. data/app/controllers/katello/concerns/hosts_controller_extensions.rb +2 -4
  74. data/app/controllers/katello/remote_execution_controller.rb +53 -58
  75. data/app/helpers/katello/hosts_and_hostgroups_helper.rb +19 -2
  76. data/app/helpers/katello/katello_urls_helper.rb +1 -1
  77. data/app/lib/actions/katello/alternate_content_source/alternate_content_source_common.rb +1 -1
  78. data/app/lib/actions/katello/alternate_content_source/update.rb +2 -1
  79. data/app/lib/actions/katello/capsule_content/verify_checksum.rb +1 -2
  80. data/app/lib/actions/katello/content_view/publish.rb +1 -0
  81. data/app/lib/actions/katello/content_view_version/create_repos.rb +1 -0
  82. data/app/lib/actions/katello/content_view_version/incremental_update.rb +3 -2
  83. data/app/lib/actions/katello/environment/{publish_repositories.rb → publish_container_repositories.rb} +10 -8
  84. data/app/lib/actions/katello/foreman/content_update.rb +4 -6
  85. data/app/lib/actions/katello/host/hypervisors_update.rb +6 -4
  86. data/app/lib/actions/katello/repository/create.rb +4 -4
  87. data/app/lib/actions/katello/repository/discover.rb +11 -4
  88. data/app/lib/actions/katello/repository/import_upload.rb +4 -6
  89. data/app/lib/actions/katello/repository/metadata_generate.rb +1 -0
  90. data/app/lib/actions/katello/repository/update.rb +3 -3
  91. data/app/lib/actions/katello/repository_set/enable_repository.rb +5 -6
  92. data/app/lib/actions/middleware/backend_services_check.rb +3 -2
  93. data/app/lib/actions/pulp3/abstract_async_task.rb +2 -4
  94. data/app/lib/actions/pulp3/capsule_content/verify_checksum.rb +1 -2
  95. data/app/lib/actions/pulp3/orchestration/repository/copy_all_units.rb +5 -1
  96. data/app/lib/actions/pulp3/orchestration/repository/delete.rb +5 -2
  97. data/app/lib/actions/pulp3/repository/create_publication.rb +4 -0
  98. data/app/lib/actions/pulp3/repository/save_version.rb +3 -5
  99. data/app/lib/katello/concerns/base_template_scope_extensions.rb +5 -9
  100. data/app/lib/katello/errors.rb +1 -0
  101. data/app/lib/katello/http_resource.rb +1 -0
  102. data/app/lib/katello/lazy_accessor.rb +1 -1
  103. data/app/lib/katello/repo_discovery.rb +4 -190
  104. data/app/lib/katello/resources/candlepin/candlepin_ping.rb +0 -5
  105. data/app/lib/katello/resources/candlepin/owner.rb +1 -1
  106. data/app/lib/katello/resources/candlepin/pool.rb +1 -2
  107. data/app/lib/katello/resources/candlepin/upstream_job.rb +1 -1
  108. data/app/lib/katello/resources/cdn.rb +3 -2
  109. data/app/lib/katello/resources/discovery/container.rb +127 -0
  110. data/app/lib/katello/resources/discovery/yum.rb +95 -0
  111. data/app/lib/katello/util/cdn_var_substitutor.rb +5 -3
  112. data/app/lib/katello/util/data.rb +3 -2
  113. data/app/lib/katello/util/errata.rb +4 -3
  114. data/app/lib/katello/util/package.rb +3 -3
  115. data/app/lib/katello/util/path_with_substitutions.rb +1 -1
  116. data/app/lib/katello/util/report_table.rb +3 -2
  117. data/app/lib/katello/util/url_matcher.rb +1 -1
  118. data/app/lib/katello/validators/alternate_content_source_path_validator.rb +4 -3
  119. data/app/lib/katello/validators/alternate_content_source_products_validator.rb +5 -7
  120. data/app/lib/katello/validators/container_image_name_validator.rb +1 -1
  121. data/app/lib/katello/validators/katello_name_format_validator.rb +2 -2
  122. data/app/lib/katello/validators/no_trailing_space_validator.rb +2 -2
  123. data/app/lib/katello/validators/prior_validator.rb +2 -2
  124. data/app/lib/katello/validators/product_unique_attribute_validator.rb +2 -4
  125. data/app/models/katello/activation_key.rb +4 -6
  126. data/app/models/katello/alternate_content_source.rb +1 -1
  127. data/app/models/katello/authorization/host_tracer.rb +1 -2
  128. data/app/models/katello/candlepin/repository_mapper.rb +2 -2
  129. data/app/models/katello/concerns/host_managed_extensions.rb +41 -10
  130. data/app/models/katello/concerns/hostgroup_extensions.rb +2 -4
  131. data/app/models/katello/concerns/location_extensions.rb +2 -4
  132. data/app/models/katello/concerns/operatingsystem_extensions.rb +84 -16
  133. data/app/models/katello/concerns/smart_proxy_extensions.rb +4 -4
  134. data/app/models/katello/concerns/subscription_facet_host_extensions.rb +2 -0
  135. data/app/models/katello/content_view.rb +5 -1
  136. data/app/models/katello/content_view_environment.rb +19 -4
  137. data/app/models/katello/content_view_environment_content_facet.rb +11 -0
  138. data/app/models/katello/erratum.rb +1 -1
  139. data/app/models/katello/event.rb +1 -1
  140. data/app/models/katello/glue/provider.rb +1 -2
  141. data/app/models/katello/hash_util.rb +1 -1
  142. data/app/models/katello/host/content_facet.rb +16 -3
  143. data/app/models/katello/host/subscription_facet.rb +27 -4
  144. data/app/models/katello/host_collection.rb +12 -8
  145. data/app/models/katello/pool.rb +5 -1
  146. data/app/models/katello/product.rb +7 -4
  147. data/app/models/katello/provider.rb +1 -2
  148. data/app/models/katello/repository.rb +18 -4
  149. data/app/models/katello/root_repository.rb +29 -0
  150. data/app/models/katello/rpm.rb +2 -2
  151. data/app/models/katello/subscription_facet_pool.rb +1 -1
  152. data/app/models/katello/sync_plan.rb +5 -4
  153. data/app/models/katello/task_status.rb +18 -18
  154. data/app/presenters/katello/product_host_count_presenter.rb +10 -0
  155. data/app/services/katello/candlepin/consumer.rb +11 -11
  156. data/app/services/katello/candlepin/message_handler.rb +3 -2
  157. data/app/services/katello/content_unit_indexer.rb +6 -0
  158. data/app/services/katello/pulp3/alternate_content_source.rb +1 -3
  159. data/app/services/katello/pulp3/api/core.rb +1 -1
  160. data/app/services/katello/pulp3/api/docker.rb +10 -0
  161. data/app/services/katello/pulp3/content_view_version/export.rb +1 -0
  162. data/app/services/katello/pulp3/content_view_version/import.rb +6 -4
  163. data/app/services/katello/pulp3/content_view_version/importable_products.rb +1 -3
  164. data/app/services/katello/pulp3/repository/apt.rb +4 -16
  165. data/app/services/katello/pulp3/repository/yum.rb +9 -5
  166. data/app/services/katello/pulp3/repository.rb +2 -2
  167. data/app/services/katello/pulp3/repository_mirror.rb +2 -9
  168. data/app/services/katello/pulp3/task.rb +4 -2
  169. data/app/services/katello/registration_manager.rb +13 -3
  170. data/app/services/katello/repository_type.rb +1 -1
  171. data/app/services/katello/smart_proxy_helper.rb +1 -0
  172. data/app/views/dashboard/_host_collection_widget.html.erb +5 -4
  173. data/app/views/foreman/job_templates/install_errata.erb +2 -0
  174. data/app/views/foreman/job_templates/install_errata_-_katello_ansible_default.erb +2 -0
  175. data/app/views/foreman/job_templates/install_errata_by_search_query.erb +2 -0
  176. data/app/views/foreman/job_templates/install_errata_by_search_query_-_katello_ansible_default.erb +3 -1
  177. data/app/views/foreman/job_templates/install_packages_by_search_query_-_katello_ansible_default.erb +1 -1
  178. data/app/views/foreman/job_templates/remove_packages_by_search_query_-_katello_ansible_default.erb +2 -2
  179. data/app/views/foreman/job_templates/resolve_traces.erb +5 -1
  180. data/app/views/foreman/job_templates/update_packages_by_search_query_-_katello_ansible_default.erb +1 -1
  181. data/app/views/foreman/job_templates/upload_profile.erb +2 -0
  182. data/app/views/foreman/smart_proxies/_reclaim_space.html.erb +7 -5
  183. data/app/views/katello/api/v2/content_facet/base.json.rabl +18 -2
  184. data/app/views/katello/api/v2/packages/thindex.json.rabl +6 -0
  185. data/app/views/katello/api/v2/repositories/show.json.rabl +8 -8
  186. data/app/views/katello/api/v2/repository_sets/show.json.rabl +1 -1
  187. data/app/views/katello/api/v2/subscription_facet/base.json.rabl +1 -1
  188. data/app/views/katello/api/v2/subscriptions/index.json.rabl +1 -0
  189. data/app/views/katello/api/v2/subscriptions/show.json.rabl +1 -0
  190. data/app/views/overrides/activation_keys/_host_environment_select.html.erb +14 -11
  191. data/app/views/overrides/activation_keys/_host_synced_content_select.html.erb +4 -4
  192. data/config/initializers/monkeys.rb +0 -1
  193. data/config/routes/api/v2.rb +3 -1
  194. data/config/routes.rb +1 -3
  195. data/db/migrate/20160114200145_add_mirror_on_sync_to_repositories.rb +1 -0
  196. data/db/migrate/20160131182301_add_download_policy_to_katello_repositories.rb +1 -0
  197. data/db/migrate/20210119162528_delete_puppet_and_ostree_repos.rb +3 -0
  198. data/db/migrate/20240522165308_add_priority_to_content_view_environment_content_facet.rb +5 -0
  199. data/db/migrate/20240621121212_katello_repository_debs_id_bigint.rb +6 -0
  200. data/db/migrate/20240729192228_add_convert2rhel_to_host_facets.rb +9 -0
  201. data/db/seeds.d/102-organizations.rb +5 -7
  202. data/db/seeds.d/150-module_job_templates.rb +7 -9
  203. data/db/seeds.d/75-job_templates.rb +9 -16
  204. data/engines/bastion_katello/README.md +3 -0
  205. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-errata.controller.js +3 -3
  206. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/details/views/deb-info.html +6 -6
  207. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/details/views/erratum-content-hosts.html +2 -2
  208. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +4 -4
  209. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/packages/details/views/package-info.html +6 -6
  210. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +31 -27
  211. data/engines/bastion_katello/lib/bastion_katello/engine.rb +2 -2
  212. data/lib/katello/engine.rb +1 -8
  213. data/lib/katello/permission_creator.rb +3 -2
  214. data/lib/katello/plugin.rb +31 -27
  215. data/lib/katello/repository_types/docker.rb +1 -0
  216. data/lib/katello/repository_types/yum.rb +1 -0
  217. data/lib/katello/tasks/clean_old_file_repos.rake +2 -4
  218. data/lib/katello/tasks/reset.rake +3 -4
  219. data/lib/katello/version.rb +1 -1
  220. data/lib/katello.rb +0 -4
  221. data/lib/monkeys/ar_postgres_evr_t.rb +2 -0
  222. data/locale/action_names.rb +1 -1
  223. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  224. data/locale/bn/katello.po +274 -22
  225. data/locale/bn_IN/katello.po +274 -22
  226. data/locale/ca/katello.po +274 -22
  227. data/locale/cs/katello.po +274 -22
  228. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  229. data/locale/cs_CZ/katello.po +275 -23
  230. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  231. data/locale/de/katello.po +280 -28
  232. data/locale/de_AT/katello.po +274 -22
  233. data/locale/de_DE/katello.po +274 -22
  234. data/locale/el/katello.po +274 -22
  235. data/locale/en/katello.po +274 -22
  236. data/locale/en_GB/katello.po +274 -22
  237. data/locale/en_US/katello.po +274 -22
  238. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  239. data/locale/es/katello.po +276 -24
  240. data/locale/et_EE/katello.po +274 -22
  241. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  242. data/locale/fr/katello.po +283 -31
  243. data/locale/gl/katello.po +274 -22
  244. data/locale/gu/katello.po +274 -22
  245. data/locale/he_IL/katello.po +274 -22
  246. data/locale/hi/katello.po +274 -22
  247. data/locale/id/katello.po +274 -22
  248. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  249. data/locale/it/katello.po +274 -22
  250. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  251. data/locale/ja/katello.po +283 -31
  252. data/locale/ka/LC_MESSAGES/katello.mo +0 -0
  253. data/locale/ka/katello.po +280 -28
  254. data/locale/katello.pot +1001 -527
  255. data/locale/kn/katello.po +274 -22
  256. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  257. data/locale/ko/katello.po +274 -22
  258. data/locale/ml_IN/katello.po +274 -22
  259. data/locale/mr/katello.po +274 -22
  260. data/locale/nl_NL/katello.po +274 -22
  261. data/locale/or/katello.po +274 -22
  262. data/locale/pa/katello.po +274 -22
  263. data/locale/pl/katello.po +274 -22
  264. data/locale/pl_PL/katello.po +274 -22
  265. data/locale/pt/katello.po +274 -22
  266. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  267. data/locale/pt_BR/katello.po +276 -24
  268. data/locale/ro/katello.po +274 -22
  269. data/locale/ro_RO/katello.po +274 -22
  270. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  271. data/locale/ru/katello.po +274 -22
  272. data/locale/sl/katello.po +274 -22
  273. data/locale/sv_SE/katello.po +274 -22
  274. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  275. data/locale/ta/katello.po +274 -22
  276. data/locale/ta_IN/katello.po +274 -22
  277. data/locale/te/katello.po +274 -22
  278. data/locale/tr/katello.po +274 -22
  279. data/locale/vi/katello.po +274 -22
  280. data/locale/vi_VN/katello.po +274 -22
  281. data/locale/zh/katello.po +274 -22
  282. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  283. data/locale/zh_CN/katello.po +283 -31
  284. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  285. data/locale/zh_TW/katello.po +274 -22
  286. data/webpack/ForemanColumnExtensions/index.js +44 -1
  287. data/webpack/components/Table/TableWrapper.js +6 -0
  288. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ChangeHostCVModal.js +24 -3
  289. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ContentViewDetailsCard.js +124 -56
  290. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/HostContentViewActions.js +2 -3
  291. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/__tests__/contentViewDetailsCard.test.js +44 -10
  292. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionActions.js +75 -31
  293. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionConstants.js +1 -0
  294. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionHooks.js +1 -1
  295. data/webpack/components/extensions/HostDetails/Tabs/customizedRexUrlHelpers.js +22 -7
  296. data/webpack/components/extensions/Hosts/ActionsBar/ActionsBar.scss +14 -0
  297. data/webpack/components/extensions/Hosts/ActionsBar/index.js +82 -23
  298. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/index.js +5 -2
  299. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/02_BulkErrataTable.js +171 -0
  300. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/04_Review.js +160 -0
  301. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/04_ReviewFooter.js +99 -0
  302. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/BulkErrataWizard.js +157 -0
  303. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/index.js +24 -0
  304. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/02_BulkPackagesTable.js +157 -0
  305. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/04_Review.js +168 -0
  306. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/04_ReviewFooter.js +141 -0
  307. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/BulkPackagesWizard.js +252 -0
  308. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/index.js +24 -0
  309. data/webpack/components/extensions/Hosts/BulkActions/HostReview.js +176 -0
  310. data/webpack/components/extensions/Hosts/TableRowActions/index.js +17 -0
  311. data/webpack/global_index.js +11 -3
  312. data/webpack/redux/actions/RedHatRepositories/repositorySetRepositories.js +5 -6
  313. data/webpack/redux/reducers/RedHatRepositories/__tests__/repositorySetRepositories.test.js +1 -1
  314. data/webpack/redux/reducers/RedHatRepositories/repositorySetRepositories.js +1 -1
  315. data/webpack/scenes/ContentViews/Copy/CopyContentViewModal.js +2 -1
  316. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js +2 -1
  317. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js +2 -1
  318. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ContentViewComponents.js +2 -1
  319. data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +2 -1
  320. data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +2 -2
  321. data/webpack/scenes/ContentViews/Publish/CVPublishForm.js +2 -1
  322. data/webpack/scenes/ContentViews/Publish/CVPublishReview.js +3 -2
  323. data/webpack/scenes/ContentViews/Publish/PublishContentViewWizard.js +2 -1
  324. data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +2 -1
  325. data/webpack/scenes/ContentViews/components/CVBreadCrumb.js +2 -1
  326. data/webpack/scenes/ContentViews/components/ContentViewSelect/ContentViewSelectOption.js +2 -2
  327. data/webpack/scenes/Subscriptions/Details/SubscriptionAttributes.js +1 -0
  328. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailInfo.test.js.snap +10 -0
  329. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +6 -0
  330. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +2 -0
  331. data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +14 -0
  332. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableHelpers.js +1 -0
  333. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableSchema.js +10 -0
  334. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.fixtures.js +1 -0
  335. data/webpack/scenes/Subscriptions/components/SubscriptionsToolbar/__snapshots__/SubscriptionsToolbar.test.js.snap +10 -0
  336. data/webpack/scenes/Tasks/helpers.js +1 -1
  337. metadata +49 -29
  338. data/app/assets/javascripts/katello/containers/container.js +0 -304
  339. data/db/migrate/20240531193030_remove_sha1_repository_checksum_type.rb +0 -10
  340. data/lib/monkeys/anemone.rb +0 -33
  341. data/webpack/utils/useKatelloDocUrl.js +0 -18
@@ -58,8 +58,8 @@ module Actions
58
58
 
59
59
  def run
60
60
  repository = ::Katello::Repository.find(input[:repository_id])
61
- if input[:sync_capsule]
62
- ForemanTasks.async_task(Katello::Repository::CapsuleSync, repository) if Setting[:foreman_proxy_content_auto_sync]
61
+ if input[:sync_capsule] && (Setting[:foreman_proxy_content_auto_sync])
62
+ ForemanTasks.async_task(Katello::Repository::CapsuleSync, repository)
63
63
  end
64
64
  output[:upload_results] = results_to_json(input[:upload_results])
65
65
  rescue ::Katello::Errors::CapsuleCannotBeReached # skip any capsules that cannot be connected to
@@ -92,10 +92,8 @@ module Actions
92
92
  json_results << {:type => 'file'}
93
93
  end
94
94
  end
95
- unless json_results.size
96
- if result[:content_unit_href]
97
- json_results << {:type => 'file'}
98
- end
95
+ if !json_results.size && (result[:content_unit_href])
96
+ json_results << {:type => 'file'}
99
97
  end
100
98
  end
101
99
  json_results
@@ -3,6 +3,7 @@ module Actions
3
3
  module Repository
4
4
  class MetadataGenerate < Actions::EntryAction
5
5
  def plan(repository, options = {})
6
+ return if repository.root.is_container_push && repository.library_instance?
6
7
  action_subject(repository)
7
8
  repository.check_ready_to_act!
8
9
  source_repository = options.fetch(:source_repository, nil)
@@ -92,7 +92,7 @@ module Actions
92
92
  # match the ACS content type and have a non-nil URL
93
93
  product = repository.product
94
94
  repo_content_types = Set.new
95
- product.repositories.each do |test_repo|
95
+ product.acs_compatible_repositories.each do |test_repo|
96
96
  # we need to check id because test_repo will still contain the old, non-nil url
97
97
  repo_content_types.add(test_repo.content_type) if (repository.id != test_repo.id) && test_repo.url.present?
98
98
  end
@@ -110,11 +110,11 @@ module Actions
110
110
  end
111
111
 
112
112
  def create_acs?(old_url, new_url)
113
- old_url.nil? && new_url.present?
113
+ (old_url.nil? || old_url.start_with?('uln')) && new_url.present? && !new_url.start_with?('uln')
114
114
  end
115
115
 
116
116
  def delete_acs?(old_url, new_url)
117
- old_url.present? && new_url.nil?
117
+ old_url.present? && (new_url.nil? || new_url.start_with?('uln'))
118
118
  end
119
119
  end
120
120
  end
@@ -6,8 +6,7 @@ module Actions
6
6
  _("Enable")
7
7
  end
8
8
 
9
- def plan(product, content, substitutions, override_url: nil,
10
- override_arch: nil)
9
+ def plan(product, content, substitutions, opts = {})
11
10
  mapper = ::Katello::Candlepin::RepositoryMapper.new(product,
12
11
  content,
13
12
  substitutions)
@@ -16,10 +15,10 @@ module Actions
16
15
  fail ::Katello::Errors::ConflictException, _("The repository is already enabled")
17
16
  end
18
17
  repository = mapper.build_repository
19
- repository.root.arch = override_arch if override_arch.present?
20
- if override_url
21
- repository.root.url = override_url
22
- repository.root.download_policy = ::Katello::RootRepository::DOWNLOAD_IMMEDIATE if URI(override_url).scheme == 'file'
18
+ repository.root.arch = opts[:override_arch] if opts[:override_arch].present?
19
+ if opts[:override_url]
20
+ repository.root.url = opts[:override_url]
21
+ repository.root.download_policy = ::Katello::RootRepository::DOWNLOAD_IMMEDIATE if URI(opts[:override_url]).scheme == 'file'
23
22
  end
24
23
  plan_action(Repository::Create, repository, clone: false)
25
24
  action_subject(repository)
@@ -28,9 +28,10 @@ module Actions
28
28
  def capsule_id(args)
29
29
  capsule_id = nil
30
30
  args.each do |arg|
31
- if arg.is_a? SmartProxy
31
+ case arg
32
+ when SmartProxy
32
33
  capsule_id = arg.id
33
- elsif arg.is_a? Hash
34
+ when Hash
34
35
  capsule_id = arg[:capsule_id] || arg[:smart_proxy_id]
35
36
  end
36
37
  break if capsule_id
@@ -96,10 +96,9 @@ module Actions
96
96
  def transform_task_response(response)
97
97
  response = [] if response.nil?
98
98
  response = [response] unless response.is_a?(Array)
99
- response = response.map do |task|
99
+ response.map do |task|
100
100
  task.as_json
101
101
  end
102
- response
103
102
  end
104
103
 
105
104
  def check_for_errors
@@ -166,8 +165,7 @@ module Actions
166
165
  def get_task_label(name, href)
167
166
  name = name.split('.').last if name
168
167
  href = href.split('-').last[0...-1] if href
169
- label = "%s (ID: %s)" % [name, href]
170
- label
168
+ "%s (ID: %s)" % [name, href]
171
169
  end
172
170
  end
173
171
  end
@@ -17,8 +17,7 @@ module Actions
17
17
  if repository
18
18
  [repository]
19
19
  else
20
- repositories = smart_proxy_helper.repositories_available_to_capsule(environment, content_view).by_rpm_count
21
- repositories
20
+ smart_proxy_helper.repositories_available_to_capsule(environment, content_view).by_rpm_count
22
21
  end
23
22
  end
24
23
  end
@@ -23,7 +23,7 @@ module Actions
23
23
  plan_action(Actions::Pulp3::Repository::SaveVersion, target_repo, tasks: action.output[:pulp_tasks])
24
24
  copy_actions = []
25
25
  #since we're creating a new version from the first repo, start copying at the 2nd
26
- source_repositories[1..-1].each do |source_repo|
26
+ source_repositories[1..].each do |source_repo|
27
27
  # TODO: In a future refactor, can :copy_all be utilized? Filters should not be needed in this code segment.
28
28
  copy_actions << plan_action(Actions::Pulp3::Repository::CopyContent, source_repo, smart_proxy, target_repo,
29
29
  filter_ids: filter_ids, solve_dependencies: solve_dependencies,
@@ -32,6 +32,10 @@ module Actions
32
32
  plan_action(Actions::Pulp3::Repository::SaveVersion, target_repo, tasks: copy_actions.last.output[:pulp_tasks])
33
33
  end
34
34
  end
35
+ elsif source_repositories.first.root.is_container_push
36
+ copy_action = plan_action(Actions::Pulp3::Repository::CopyContent, source_repositories.first, smart_proxy, target_repo,
37
+ copy_all: true)
38
+ plan_action(Actions::Pulp3::Repository::SaveVersion, target_repo, tasks: copy_action.output[:pulp_tasks])
35
39
  else
36
40
  plan_self(source_version_repo_id: source_repositories.first.id,
37
41
  target_repo_id: target_repo.id)
@@ -9,10 +9,13 @@ module Actions
9
9
  plan_action(Actions::Pulp3::Repository::DeleteDistributions, repository.id, smart_proxy)
10
10
 
11
11
  if repository.content_view.default?
12
- #we're deleting the library instance, so just delete the whole pulp3 repo
12
+ # Container push repositories must be deleted through the distribution
13
+ return if repository.root.is_container_push
14
+
15
+ # We're deleting the library instance, so just delete the whole pulp3 repo
13
16
  plan_action(Actions::Pulp3::Repository::Delete, repository.id, smart_proxy)
14
17
  elsif repository.environment.nil?
15
- #we're deleting the archived instance, so delete the version
18
+ # We're deleting the archived instance, so delete the version
16
19
  plan_action(Actions::Pulp3::Repository::DeleteVersion, repository, smart_proxy)
17
20
  end
18
21
  end
@@ -14,6 +14,10 @@ module Actions
14
14
  def invoke_external_task
15
15
  unless input[:skip_publication_creation]
16
16
  repository = ::Katello::Repository.find(input[:repository_id])
17
+ if repository.root.sha1_checksum?
18
+ repository.root.remove_sha1_checksum_type
19
+ repository.root.save!
20
+ end
17
21
  output[:response] = repository.backend_service(smart_proxy).with_mirror_adapter.create_publication
18
22
  end
19
23
  end
@@ -20,11 +20,9 @@ module Actions
20
20
  end
21
21
 
22
22
  output[:publication_provided] = false
23
- if input[:tasks].present?
24
- if (publication_href = ::Katello::Pulp3::Task.publication_href(input[:tasks]))
25
- repo.update(:publication_href => publication_href)
26
- output[:publication_provided] = true
27
- end
23
+ if input[:tasks].present? && (publication_href = ::Katello::Pulp3::Task.publication_href(input[:tasks]))
24
+ repo.update(:publication_href => publication_href)
25
+ output[:publication_provided] = true
28
26
  end
29
27
 
30
28
  if version_href
@@ -259,13 +259,9 @@ module Katello
259
259
  labels = 'label ^ (Actions::Katello::Host::Erratum::Install, Actions::Katello::Host::Erratum::ApplicableErrataInstall)'
260
260
  select = 'foreman_tasks_tasks.*'
261
261
 
262
- if Katello.with_remote_execution?
263
- new_labels = 'label = Actions::RemoteExecution::RunHostJob AND remote_execution_feature.label ^ (katello_errata_install, katello_errata_install_by_search)'
264
- labels = [labels, new_labels].map { |label| "(#{label})" }.join(' OR ')
265
- select += ',template_invocations.id AS template_invocation_id'
266
- else
267
- select += ',NULL AS template_invocation_id'
268
- end
262
+ new_labels = 'label = Actions::RemoteExecution::RunHostJob AND remote_execution_feature.label ^ (katello_errata_install, katello_errata_install_by_search)'
263
+ labels = [labels, new_labels].map { |label| "(#{label})" }.join(' OR ')
264
+ select += ',template_invocations.id AS template_invocation_id'
269
265
 
270
266
  search = [search_up_to, search_since, search_result, "state = stopped", labels].compact.join(' and ')
271
267
 
@@ -302,8 +298,8 @@ module Katello
302
298
  current_erratum_errata_type = current_erratum[1]
303
299
  current_erratum_issued = current_erratum.last
304
300
 
305
- if filter_errata_type != 'all'
306
- next unless filter_errata_type == current_erratum_errata_type
301
+ if filter_errata_type != 'all' && !(filter_errata_type == current_erratum_errata_type)
302
+ next
307
303
  end
308
304
 
309
305
  hash = {
@@ -134,6 +134,7 @@ module Katello
134
134
  end
135
135
 
136
136
  class UpstreamCandlepinError < CandlepinError; end
137
+
137
138
  class UpstreamConsumerGone < StandardError
138
139
  def message
139
140
  _("The manifest doesn't exist on console.redhat.com. " \
@@ -8,6 +8,7 @@ module Katello
8
8
 
9
9
  class RestClientException < StandardError
10
10
  attr_reader :service_code, :code
11
+
11
12
  def initialize(params)
12
13
  super params[:message]
13
14
  @service_code = params[:service_code]
@@ -24,7 +24,7 @@ module Katello
24
24
  def lazy_accessor(*args)
25
25
  options = args.extract_options!
26
26
  @lazy_attributes = [] if @lazy_attributes.nil?
27
- @lazy_attributes = @lazy_attributes.concat args
27
+ @lazy_attributes.concat args
28
28
  @lazy_attributes_options ||= {}
29
29
  fail ArgumentError, "Attribute names must be symbols" if args.any? { |attribute| !attribute.is_a?(Symbol) }
30
30
  redefined_attr = args.find { |attribute| instance_methods.include?(attribute.to_s) }
@@ -4,22 +4,11 @@ module Katello
4
4
  class RepoDiscovery
5
5
  include Katello::Util::HttpProxy
6
6
 
7
- attr_reader :found, :crawled, :to_follow
8
-
9
- # rubocop:disable Metrics/ParameterLists
10
- def initialize(url, content_type = 'yum', upstream_username = nil,
11
- upstream_password = nil, search = '*', crawled = [],
12
- found = [], to_follow = [])
13
- @uri = uri(url)
14
- @content_type = content_type
15
- @upstream_username = upstream_username.empty? ? nil : upstream_username
16
- @upstream_password = upstream_password.empty? ? nil : upstream_password
17
- @search = search
18
- @found = found
19
- @crawled = crawled
20
- @to_follow = to_follow
7
+ def self.class_for(content_type)
8
+ repo_discovery_class = RepositoryTypeManager.find_repository_type(content_type)&.repo_discovery_class
9
+ fail _("Content type does not support repo discovery") unless repo_discovery_class
10
+ repo_discovery_class
21
11
  end
22
- # rubocop:enable Metrics/ParameterLists
23
12
 
24
13
  def uri(url)
25
14
  #add a / on the end, as directories require it or else
@@ -27,180 +16,5 @@ module Katello
27
16
  url += '/' unless url.ends_with?('/')
28
17
  URI(url)
29
18
  end
30
-
31
- def run(resume_point)
32
- if @content_type == 'docker'
33
- docker_search
34
- else
35
- if @uri.scheme == 'file'
36
- file_crawl(uri(resume_point))
37
- elsif %w(http https).include?(@uri.scheme)
38
- http_crawl(uri(resume_point))
39
- else
40
- fail _("Unsupported URL protocol %s.") % @uri.scheme
41
- end
42
- end
43
- end
44
-
45
- private
46
-
47
- def parse_parameter(field_value)
48
- field_value.lstrip!
49
- i = field_value.index(/[ \t=;,]/) || field_value.length
50
- name = field_value.slice!(0, i).downcase(:ascii)
51
- field_value.lstrip!
52
- if field_value.delete_prefix!('=')
53
- field_value.lstrip!
54
- if field_value.delete_prefix!('"')
55
- value = ''
56
- until field_value.empty?
57
- break if field_value.delete_prefix!('"')
58
- field_value.delete_prefix!("\\")
59
- value += field_value.slice!(0, 1) || ''
60
- end
61
- else
62
- i = field_value.index(/[;,]/) || field_value.length
63
- value = field_value.slice!(0, i)
64
- end
65
- end
66
- {name: name, value: value || ''}
67
- end
68
-
69
- def parse_parameters(field_value)
70
- seen_rel = false
71
- has_next_rel = false
72
- has_anchor = false
73
- until field_value.empty?
74
- field_value.lstrip!
75
- break if field_value.delete_prefix!(';').nil?
76
- param = parse_parameter(field_value)
77
- case
78
- when param[:name] == 'rel' && !seen_rel
79
- seen_rel = true
80
- has_next_rel = param[:value].downcase(:ascii).split(/[ \t]/).include?('next')
81
- when param[:name] == 'anchor'
82
- has_anchor = true
83
- end
84
- end
85
- {has_next_rel: has_next_rel, has_anchor: has_anchor}
86
- end
87
-
88
- def get_next_link(link_header)
89
- # This code mostly follows Appendix B "Algorithms of Parsing Link Header Fields" of RFC 8288
90
- # "Web Linking", <https://www.rfc-editor.org/rfc/rfc8288#appendix-B> (that RFC appears to be
91
- # silent about multiple "next" links, so just use the first one and ignore any additional
92
- # ones, in the general spirit of being lenient):
93
- return nil if link_header.nil?
94
- field_value = link_header.clone
95
- until field_value.empty?
96
- # The following ignores any junk preceding the next <...> link URL:
97
- m = field_value.match(/<(.*)>/)
98
- break unless m
99
- target_string = m[1]
100
- field_value = m.post_match
101
- params = parse_parameters(field_value)
102
- if params[:has_next_rel]
103
- # To keep it simple, ignore a link with an (unlikely) anchor parameter; but the RFC
104
- # mandates that we "MUST NOT process the link without applying the anchor", so just raise
105
- # an exception in that (unlikely) case:
106
- fail "anchor not supported" if params[:has_anchor]
107
- return target_string
108
- end
109
- end
110
- nil
111
- end
112
-
113
- def docker_search
114
- request_params = {
115
- method: :get,
116
- headers: { accept: :json },
117
- url: "#{@uri}v1/search?q=#{@search}"
118
- }
119
-
120
- request_params[:user] = @upstream_username unless @upstream_username.empty?
121
- request_params[:password] = @upstream_password unless @upstream_password.empty?
122
- request_params[:proxy] = proxy_uri if proxy
123
-
124
- begin
125
- results = RestClient::Request.execute(request_params)
126
- JSON.parse(results)['results'].each do |result|
127
- @found << result['name']
128
- end
129
- rescue
130
- # Note: v2 endpoint does not support search
131
- request_params[:url] = "#{@uri}v2/_catalog"
132
- loop do
133
- results = RestClient::Request.execute(request_params)
134
- JSON.parse(results)['repositories'].each do |result|
135
- @found << result
136
- end
137
- next_uri = get_next_link(results.headers[:link])
138
- break if next_uri.nil?
139
- request_params[:url] = URI(request_params[:url]).merge(next_uri).to_s
140
- end
141
- end
142
- @found.sort!
143
- end
144
-
145
- def anemone_proxy_details
146
- details = {}
147
-
148
- if proxy
149
- details[:proxy_host] = proxy_host
150
- details[:proxy_port] = proxy_port
151
- details[:proxy_user] = proxy.username
152
- details[:proxy_password] = proxy.password
153
- end
154
-
155
- details
156
- end
157
-
158
- def http_crawl(resume_point)
159
- resume_point_uri = URI(resume_point)
160
- resume_point_uri.user = @upstream_username if @upstream_username
161
- resume_point_uri.password = @upstream_password if @upstream_password
162
-
163
- Anemone.crawl(resume_point_uri, anemone_proxy_details) do |anemone|
164
- anemone.focus_crawl do |page|
165
- @crawled << page.url.path
166
-
167
- page.links.each do |link|
168
- if link.path.ends_with?('/repodata/')
169
- page_url = page.url.clone
170
- page_url.user = nil
171
- page_url.password = nil
172
- @found << page_url.to_s
173
- else
174
- @to_follow << link.to_s if should_follow?(link.path)
175
- end
176
- end
177
- page.discard_doc! #saves memory, doc not needed
178
- []
179
- end
180
- end
181
- end
182
-
183
- def file_crawl(resume_point)
184
- if resume_point.path.ends_with?('/repodata/')
185
- found_path = Pathname(resume_point.path).parent.to_s
186
- @found << "file://#{found_path}"
187
- end
188
- if resume_point.path == @uri.path
189
- Dir.glob("#{@uri.path}**/").each { |path| @to_follow << path }
190
- @to_follow.shift
191
- end
192
- @crawled << resume_point.path
193
- end
194
-
195
- def should_follow?(path)
196
- #Verify:
197
- # * link's path starts with the base url
198
- # * link hasn't already been crawled
199
- # * link ends with '/' so it should be a directory
200
- # * link doesn't end with '/Packages/', as this increases
201
- # processing time and memory usage considerably
202
- return path.starts_with?(@uri.path) && !@crawled.include?(path) &&
203
- path.ends_with?('/') && !path.ends_with?('/Packages/')
204
- end
205
19
  end
206
20
  end
@@ -7,11 +7,6 @@ module Katello
7
7
  response = get('/candlepin/status').body
8
8
  JSON.parse(response).with_indifferent_access
9
9
  end
10
-
11
- def distributor_versions
12
- response = get("/candlepin/distributor_versions").body
13
- JSON.parse(response)
14
- end
15
10
  end
16
11
  end
17
12
  end
@@ -65,7 +65,7 @@ module Katello
65
65
  response = JSON.parse(response_json).with_indifferent_access
66
66
  if wait_until_complete && response['state'] == 'CREATED'
67
67
  while !response['state'].nil? && response['state'] != 'FINISHED' && response['state'] != 'ERROR'
68
- path = join_path('candlepin', response['statusPath'][1..-1])
68
+ path = join_path('candlepin', response['statusPath'][1..])
69
69
  response_json = self.get(path, self.default_headers)
70
70
  response = JSON.parse(response_json).with_indifferent_access
71
71
  end
@@ -13,8 +13,7 @@ module Katello
13
13
  end
14
14
 
15
15
  def create(owner_key, attrs)
16
- pool = self.post("/candlepin/owners/#{owner_key}/pools", attrs.to_json, self.default_headers).body
17
- pool
16
+ self.post("/candlepin/owners/#{owner_key}/pools", attrs.to_json, self.default_headers).body
18
17
  end
19
18
 
20
19
  def find(pool_id)
@@ -11,7 +11,7 @@ module Katello
11
11
  end
12
12
 
13
13
  def get(id, upstream)
14
- url = API_URL
14
+ url = ENV['REDHAT_RHSM_API_URL'] || API_URL
15
15
  response = Resources::Candlepin::UpstreamConsumer.start_upstream_export("#{url}#{path(id)}", upstream['idCert']['cert'],
16
16
  upstream['idCert']['key'], nil)
17
17
  job = JSON.parse(response)
@@ -104,9 +104,10 @@ module Katello
104
104
  # very old infrastructure for now, but that was considered better than having an insecure default.
105
105
  net.min_version = OpenSSL::SSL::TLS1_2_VERSION
106
106
 
107
- if (@options[:verify_ssl] == false) || (@options[:verify_ssl] == OpenSSL::SSL::VERIFY_NONE)
107
+ case @options[:verify_ssl]
108
+ when false, OpenSSL::SSL::VERIFY_NONE
108
109
  net.verify_mode = OpenSSL::SSL::VERIFY_NONE
109
- elsif @options[:verify_ssl].is_a? Integer
110
+ when Integer
110
111
  net.verify_mode = @options[:verify_ssl]
111
112
  net.verify_callback = lambda do |preverify_ok, ssl_context|
112
113
  if !preverify_ok || ssl_context.error != 0
@@ -0,0 +1,127 @@
1
+ module Katello
2
+ module Resources
3
+ module Discovery
4
+ class Container < RepoDiscovery
5
+ attr_reader :found, :crawled, :to_follow
6
+ def initialize(url, crawled = [], found = [], to_follow = [],
7
+ upstream_credentials_and_search = {
8
+ upstream_username: nil,
9
+ upstream_password: nil,
10
+ search: '*'
11
+ })
12
+ @uri = uri(url)
13
+ @upstream_username = upstream_credentials_and_search[:upstream_username].presence
14
+ @upstream_password = upstream_credentials_and_search[:upstream_password].presence
15
+ @search = upstream_credentials_and_search.fetch(:search, '*')
16
+ @found = found
17
+ @crawled = crawled
18
+ @to_follow = to_follow
19
+ end
20
+
21
+ def run(_resume_point)
22
+ docker_search
23
+ end
24
+
25
+ private
26
+
27
+ def parse_parameter(field_value)
28
+ field_value.lstrip!
29
+ i = field_value.index(/[ \t=;,]/) || field_value.length
30
+ name = field_value.slice!(0, i).downcase(:ascii)
31
+ field_value.lstrip!
32
+ if field_value.delete_prefix!('=')
33
+ field_value.lstrip!
34
+ if field_value.delete_prefix!('"')
35
+ value = ''
36
+ until field_value.empty?
37
+ break if field_value.delete_prefix!('"')
38
+ field_value.delete_prefix!("\\")
39
+ value += field_value.slice!(0, 1) || ''
40
+ end
41
+ else
42
+ i = field_value.index(/[;,]/) || field_value.length
43
+ value = field_value.slice!(0, i)
44
+ end
45
+ end
46
+ {name: name, value: value || ''}
47
+ end
48
+
49
+ def parse_parameters(field_value)
50
+ seen_rel = false
51
+ has_next_rel = false
52
+ has_anchor = false
53
+ until field_value.empty?
54
+ field_value.lstrip!
55
+ break if field_value.delete_prefix!(';').nil?
56
+ param = parse_parameter(field_value)
57
+ case
58
+ when param[:name] == 'rel' && !seen_rel
59
+ seen_rel = true
60
+ has_next_rel = param[:value].downcase(:ascii).split(/[ \t]/).include?('next')
61
+ when param[:name] == 'anchor'
62
+ has_anchor = true
63
+ end
64
+ end
65
+ {has_next_rel: has_next_rel, has_anchor: has_anchor}
66
+ end
67
+
68
+ def get_next_link(link_header)
69
+ # This code mostly follows Appendix B "Algorithms of Parsing Link Header Fields" of RFC 8288
70
+ # "Web Linking", <https://www.rfc-editor.org/rfc/rfc8288#appendix-B> (that RFC appears to be
71
+ # silent about multiple "next" links, so just use the first one and ignore any additional
72
+ # ones, in the general spirit of being lenient):
73
+ return nil if link_header.nil?
74
+ field_value = link_header.clone
75
+ until field_value.empty?
76
+ # The following ignores any junk preceding the next <...> link URL:
77
+ m = field_value.match(/<(.*)>/)
78
+ break unless m
79
+ target_string = m[1]
80
+ field_value = m.post_match
81
+ params = parse_parameters(field_value)
82
+ if params[:has_next_rel]
83
+ # To keep it simple, ignore a link with an (unlikely) anchor parameter; but the RFC
84
+ # mandates that we "MUST NOT process the link without applying the anchor", so just raise
85
+ # an exception in that (unlikely) case:
86
+ fail "anchor not supported" if params[:has_anchor]
87
+ return target_string
88
+ end
89
+ end
90
+ nil
91
+ end
92
+
93
+ def docker_search
94
+ request_params = {
95
+ method: :get,
96
+ headers: { accept: :json },
97
+ url: "#{@uri}v1/search?q=#{@search}"
98
+ }
99
+
100
+ request_params[:user] = @upstream_username if @upstream_username
101
+ request_params[:password] = @upstream_password if @upstream_password
102
+ request_params[:proxy] = proxy_uri if proxy
103
+
104
+ begin
105
+ results = RestClient::Request.execute(request_params)
106
+ JSON.parse(results)['results'].each do |result|
107
+ @found << result['name']
108
+ end
109
+ rescue
110
+ # Note: v2 endpoint does not support search
111
+ request_params[:url] = "#{@uri}v2/_catalog"
112
+ loop do
113
+ results = RestClient::Request.execute(request_params)
114
+ JSON.parse(results)['repositories'].each do |result|
115
+ @found << result
116
+ end
117
+ next_uri = get_next_link(results.headers[:link])
118
+ break if next_uri.nil?
119
+ request_params[:url] = URI(request_params[:url]).merge(next_uri).to_s
120
+ end
121
+ end
122
+ @found.sort!
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end