katello 4.5.0.rc1 → 4.5.0.rc2

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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/hosts/activation_key_edit.js +9 -2
  3. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +3 -0
  4. data/app/controllers/katello/api/v2/alternate_content_sources_bulk_actions_controller.rb +44 -0
  5. data/app/controllers/katello/api/v2/alternate_content_sources_controller.rb +29 -6
  6. data/app/controllers/katello/api/v2/content_view_components_controller.rb +1 -1
  7. data/app/controllers/katello/api/v2/content_view_repositories_controller.rb +1 -1
  8. data/app/controllers/katello/api/v2/repositories_controller.rb +2 -8
  9. data/app/lib/actions/katello/alternate_content_source/refresh.rb +27 -0
  10. data/app/lib/actions/katello/cdn_configuration/update.rb +1 -1
  11. data/app/lib/actions/katello/content_view/publish.rb +1 -1
  12. data/app/lib/actions/katello/organization/manifest_refresh.rb +1 -1
  13. data/app/lib/actions/pulp3/alternate_content_source/delete.rb +2 -2
  14. data/app/lib/actions/pulp3/alternate_content_source/delete_remote.rb +2 -2
  15. data/app/lib/actions/pulp3/alternate_content_source/refresh.rb +23 -0
  16. data/app/lib/actions/pulp3/alternate_content_source/update.rb +2 -2
  17. data/app/lib/actions/pulp3/alternate_content_source/update_remote.rb +2 -2
  18. data/app/lib/actions/pulp3/orchestration/alternate_content_source/create.rb +0 -2
  19. data/app/lib/actions/pulp3/orchestration/alternate_content_source/refresh.rb +15 -0
  20. data/app/lib/actions/pulp3/orchestration/alternate_content_source/update.rb +0 -2
  21. data/app/lib/actions/pulp3/repository/refresh_distribution.rb +1 -4
  22. data/app/lib/actions/pulp3/repository/save_artifact.rb +1 -1
  23. data/app/lib/actions/pulp3/repository/save_distribution_references.rb +0 -2
  24. data/app/models/katello/alternate_content_source.rb +5 -0
  25. data/app/services/katello/pulp3/alternate_content_source.rb +6 -0
  26. data/app/services/katello/pulp3/content_view_version/metadata_map.rb +1 -1
  27. data/app/services/katello/pulp3/repository.rb +29 -1
  28. data/app/views/katello/api/v2/alternate_content_sources/base.json.rabl +10 -1
  29. data/app/views/katello/api/v2/content_facet/show.json.rabl +12 -0
  30. data/app/views/katello/api/v2/repository_sets/show.json.rabl +4 -0
  31. data/config/routes/api/v2.rb +16 -4
  32. data/db/migrate/20220303160220_remove_duplicate_errata.rb +1 -1
  33. data/db/migrate/20220428203334_add_last_refreshed_to_katello_alternate_content_sources.rb +5 -0
  34. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/capsule-content/capsule-content.controller.js +1 -1
  35. data/lib/katello/permission_creator.rb +4 -2
  36. data/lib/katello/tasks/refresh_alternate_content_sources.rake +10 -0
  37. data/lib/katello/version.rb +1 -1
  38. data/webpack/components/Bookmark/index.js +22 -14
  39. data/webpack/components/Search/Search.js +4 -0
  40. data/webpack/components/Table/MainTable.scss +5 -1
  41. data/webpack/components/Table/TableWrapper.js +5 -1
  42. data/webpack/components/TypeAhead/TypeAhead.js +4 -0
  43. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +2 -0
  44. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ChangeHostCVModal.js +2 -8
  45. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ContentViewDetailsCard.js +41 -11
  46. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsActions.js +2 -2
  47. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsCard.js +32 -13
  48. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/__tests__/hostCollectionsCard.test.js +8 -0
  49. data/webpack/components/extensions/HostDetails/DetailsTabCards/RecentCommunicationCardExtensions.js +37 -0
  50. data/webpack/components/extensions/HostDetails/HostDetailsActions.js +11 -0
  51. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/SecondaryTabsRoutes.js +4 -0
  52. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/constants.js +2 -0
  53. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/index.js +6 -1
  54. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/ErrataTab.js +120 -51
  55. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/ModuleStreamsTab.js +71 -37
  56. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackageInstallModal.js +4 -3
  57. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackagesTab.js +117 -40
  58. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionActions.js +25 -3
  59. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionHooks.js +85 -0
  60. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js +87 -33
  61. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/EnableTracerModal.js +14 -7
  62. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/HostTracesActions.js +2 -1
  63. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/TracesEnabler.js +104 -0
  64. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/TracesTab.js +92 -51
  65. data/webpack/components/extensions/HostDetails/Tabs/__tests__/errataTab.test.js +13 -23
  66. data/webpack/components/extensions/HostDetails/Tabs/{ModuleStreamsTab/__tests__/modules.fixtures.json → __tests__/moduleStreams.fixtures.json} +0 -0
  67. data/webpack/components/extensions/HostDetails/Tabs/{ModuleStreamsTab/__tests__ → __tests__}/moduleStreamsTab.test.js +13 -6
  68. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packageInstallModal.test.js +21 -15
  69. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packagesTab.test.js +8 -0
  70. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySets.fixtures.json +4 -1
  71. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySetsTab.test.js +26 -0
  72. data/webpack/components/extensions/HostDetails/Tabs/__tests__/tracesTab.test.js +7 -4
  73. data/webpack/components/extensions/HostDetails/hostDetailsHelpers.js +18 -0
  74. data/webpack/global_index.js +2 -2
  75. data/webpack/redux/actions/RedHatRepositories/helpers.js +5 -1
  76. data/webpack/scenes/AlternateContentSources/ACSActions.js +13 -1
  77. data/webpack/scenes/AlternateContentSources/ACSConstants.js +14 -0
  78. data/webpack/scenes/AlternateContentSources/ACSSelectors.js +10 -1
  79. data/webpack/scenes/AlternateContentSources/Create/ACSCreateContext.js +4 -0
  80. data/webpack/scenes/AlternateContentSources/Create/ACSCreateWizard.js +160 -0
  81. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSCreateFinish.js +79 -0
  82. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSCredentials.js +199 -0
  83. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSReview.js +104 -0
  84. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSSmartProxies.js +41 -0
  85. data/webpack/scenes/AlternateContentSources/Create/Steps/AcsUrlPaths.js +71 -0
  86. data/webpack/scenes/AlternateContentSources/Create/Steps/NameACS.js +57 -0
  87. data/webpack/scenes/AlternateContentSources/Create/Steps/SelectSource.js +77 -0
  88. data/webpack/scenes/AlternateContentSources/Create/__tests__/acsCreate.test.js +149 -0
  89. data/webpack/scenes/AlternateContentSources/Create/__tests__/acsCreateData.fixtures.json +3 -0
  90. data/webpack/scenes/AlternateContentSources/Create/__tests__/contentCredentials.fixtures.json +69 -0
  91. data/webpack/scenes/AlternateContentSources/Create/__tests__/smartProxy.fixtures.json +65 -0
  92. data/webpack/scenes/AlternateContentSources/MainTable/ACSTable.js +33 -23
  93. data/webpack/scenes/ContentCredentials/ContentCredentialSelectors.js +4 -1
  94. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +2 -2
  95. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +1 -1
  96. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js +1 -1
  97. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js +2 -2
  98. data/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.test.js +4 -4
  99. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +1 -1
  100. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +4 -4
  101. data/webpack/scenes/ContentViews/components/ContentViewIcon.js +1 -1
  102. data/webpack/scenes/ContentViews/components/ContentViewsCounter.js +1 -1
  103. data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.js +1 -1
  104. data/webpack/scenes/ContentViews/expansions/DetailsExpansion.js +2 -2
  105. data/webpack/scenes/ContentViews/expansions/RelatedContentViewComponentsModal.js +2 -2
  106. data/webpack/scenes/ContentViews/expansions/__tests__/contentViewComponentsModal.test.js +1 -1
  107. data/webpack/scenes/RedHatRepositories/components/Search.js +4 -4
  108. data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +9 -2
  109. data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +1 -1
  110. data/webpack/scenes/SmartProxy/SmartProxyContentSelectors.js +10 -1
  111. data/webpack/scenes/Tasks/helpers.js +30 -3
  112. metadata +34 -14
  113. data/db/seeds.d/107-enable_dynflow.rb +0 -8
  114. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/EnableTracerEmptyState.js +0 -42
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2fd3647b864eba8c468c3eea9e6d6d867a43192dcb29c0758f0771085fb1621
4
- data.tar.gz: 764696ceedc7d01432439f6ac00012be79383073c35f0d491cbf4a1da1af6a77
3
+ metadata.gz: 5922047abc1b1bd8649e30bbaaf5eaf2e09f09bc9abb5e1b61920c0b84b1b57b
4
+ data.tar.gz: 8105c45f9d16ca034430e89224f9bb81fa95c02d38ca638268864e34a9d57e2b
5
5
  SHA512:
6
- metadata.gz: d67f10a68cf3f81316e77099d82266960fc5887513004f5e35daa47c591ccc44f2a8ba78f54e8ef84c6ba8bc53d5a42c0621d842c70fa5b20c3dd61cae90e648
7
- data.tar.gz: 5c798d57fbde2baf9c9d62c172e294ade51f32e2d822ed56c63983f48d8f690abd0d2f625e061c7318d4680e916d477fc64025974396ead7f17b919bf06a83c4
6
+ metadata.gz: '069335f24169763ce80081693498c668a115893acb4e9c7b2a1486d54d5394f53b9d21cb6442acd6cba990f07d58e6b75f7ec0d9e32515165226fb833874a311'
7
+ data.tar.gz: 22cda386e45a6d989daff56fe3897d07a75205282b2aa1e901bf7c333fd38d72869ab3dd808641a5535d8f72063c2961aa575c2420dfa51c2f98a3ab4152b28c
@@ -75,8 +75,15 @@ function ktSetParam(name, value) {
75
75
  var paramContainer = ktFindParamContainer(name);
76
76
  if(value) {
77
77
  if(! paramContainer) { // we create the param for kt_activation_keys
78
- $("div#parameters a[target~='#global_parameters_table']").click();
79
- paramContainer = $("div#parameters .fields").last();
78
+ var addParameterButton = $('#parameters').find('.btn-primary');
79
+ addParameterButton.click();
80
+ var directionOfAddedItems = addParameterButton.attr('direction');
81
+ var paramContainer = $('#parameters').find('.fields');
82
+ if(directionOfAddedItems === 'append'){
83
+ paramContainer = paramContainer.last();
84
+ } else {
85
+ paramContainer = paramContainer.first();
86
+ }
80
87
  paramContainer.find("input[name*='name']").val(name);
81
88
  }
82
89
  paramContainer.find("textarea").val(value);
@@ -177,6 +177,9 @@ module Katello
177
177
  end
178
178
  end
179
179
  response.headers['Content-Type'] = media_type
180
+ length = manifest_response.try(:body).try(:size)
181
+ length ||= 0
182
+ response.header['Content-Length'] = "#{length}"
180
183
  render json: manifest_response
181
184
  end
182
185
  end
@@ -0,0 +1,44 @@
1
+ module Katello
2
+ class Api::V2::AlternateContentSourcesBulkActionsController < Api::V2::ApiController
3
+ before_action :find_alternate_content_sources
4
+
5
+ api :PUT, '/alternate_content_sources/bulk/destroy', N_('Destroy one or more alternate content sources')
6
+ param :ids, Array, desc: N_('List of alternate content source IDs'), required: true
7
+ def destroy_alternate_content_sources
8
+ deletable_alternate_content_sources = @alternate_content_sources.deletable
9
+
10
+ if deletable_alternate_content_sources.empty?
11
+ msg = _("Unable to delete any alternate content source. You either do not have the permission to"\
12
+ " delete, or none of the alternate content sources exist.")
13
+ fail HttpErrors::UnprocessableEntity, msg
14
+ end
15
+ task = async_task(::Actions::BulkAction,
16
+ ::Actions::Katello::AlternateContentSource::Destroy,
17
+ deletable_alternate_content_sources)
18
+ respond_for_async :resource => task
19
+ end
20
+
21
+ api :POST, '/alternate_content_sources/bulk/refresh', N_('Refresh alternate content sources')
22
+ param :ids, Array, desc: N_('List of alternate content source IDs'), required: true
23
+ def refresh_alternate_content_sources
24
+ refreshable_alternate_content_sources = @alternate_content_sources.editable
25
+ if refreshable_alternate_content_sources.empty?
26
+ msg = _("Unable to refresh any alternate content source. You either do not have the permission to"\
27
+ " refresh, or none of the alternate content sources exist.")
28
+ fail HttpErrors::UnprocessableEntity, msg
29
+ else
30
+ task = async_task(::Actions::BulkAction,
31
+ ::Actions::Katello::AlternateContentSource::Refresh,
32
+ refreshable_alternate_content_sources)
33
+ respond_for_async resource: task
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def find_alternate_content_sources
40
+ params.require(:ids)
41
+ @alternate_content_sources = AlternateContentSource.readable.where(id: params[:ids])
42
+ end
43
+ end
44
+ end
@@ -2,8 +2,10 @@ module Katello
2
2
  class Api::V2::AlternateContentSourcesController < Api::V2::ApiController
3
3
  include Katello::Concerns::FilteredAutoCompleteSearch
4
4
 
5
- before_action :find_authorized_katello_resource, :only => [:show, :update, :destroy]
6
- before_action :find_smart_proxies
5
+ acs_wrap_params = AlternateContentSource.attribute_names + [:smart_proxy_ids, :smart_proxy_names]
6
+ wrap_parameters :alternate_content_source, include: acs_wrap_params
7
+
8
+ before_action :find_authorized_katello_resource, only: [:show, :update, :destroy, :refresh]
7
9
 
8
10
  def_param_group :acs do
9
11
  param :name, String, desc: N_("Name of the alternate content source")
@@ -11,6 +13,7 @@ module Katello
11
13
  param :base_url, String, desc: N_('Base URL for finding alternate content'), required: false
12
14
  param :subpaths, Array, desc: N_('Path suffixes for finding alternate content'), required: false
13
15
  param :smart_proxy_ids, Array, desc: N_("Ids of smart proxies to associate"), required: false
16
+ param :smart_proxy_names, Array, desc: N_("Names of smart proxies to associate"), required: false
14
17
  param :content_type, RepositoryTypeManager.defined_repository_types.keys & AlternateContentSource::CONTENT_TYPES, desc: N_("The content type for the Alternate Content Source"), required: false
15
18
  param :alternate_content_source_type, AlternateContentSource::ACS_TYPES, desc: N_("The Alternate Content Source type")
16
19
  param :upstream_username, String, desc: N_("Basic authentication username"), required: false
@@ -54,7 +57,8 @@ module Katello
54
57
  api :POST, '/alternate_content_sources', N_('Create an ACS')
55
58
  param_group :acs
56
59
  def create
57
- @alternate_content_source = ::Katello::AlternateContentSource.new(acs_params)
60
+ find_smart_proxies
61
+ @alternate_content_source = ::Katello::AlternateContentSource.new(acs_params.except(:smart_proxy_ids, :smart_proxy_names))
58
62
  sync_task(::Actions::Katello::AlternateContentSource::Create, @alternate_content_source, @smart_proxies)
59
63
  @alternate_content_source.reload
60
64
  respond_for_create(resource: @alternate_content_source)
@@ -67,8 +71,12 @@ module Katello
67
71
  # If a user doesn't include smart proxies in the update call, don't accidentally remove all of them.
68
72
  if params[:smart_proxy_ids].nil?
69
73
  @smart_proxies = @alternate_content_source.smart_proxies
74
+ elsif params[:smart_proxy_ids].empty?
75
+ @smart_proxies = []
76
+ else
77
+ find_smart_proxies
70
78
  end
71
- sync_task(::Actions::Katello::AlternateContentSource::Update, @alternate_content_source, @smart_proxies, acs_params)
79
+ sync_task(::Actions::Katello::AlternateContentSource::Update, @alternate_content_source, @smart_proxies, acs_params.except(:smart_proxy_ids))
72
80
  respond_for_show(:resource => @alternate_content_source)
73
81
  end
74
82
 
@@ -79,10 +87,17 @@ module Katello
79
87
  respond_for_destroy
80
88
  end
81
89
 
90
+ api :POST, '/alternate_content_sources/:id/refresh', N_('Refresh an alternate content source')
91
+ param :id, :number, :required => true, :desc => N_("Alternate content source ID")
92
+ def refresh
93
+ task = async_task(::Actions::Katello::AlternateContentSource::Refresh, @alternate_content_source)
94
+ respond_for_async :resource => task
95
+ end
96
+
82
97
  protected
83
98
 
84
99
  def acs_params
85
- keys = [:name, :label, :base_url, {subpaths: []}, {smart_proxy_ids: []}, :content_type, :alternate_content_source_type,
100
+ keys = [:name, :label, :base_url, {subpaths: []}, {smart_proxy_ids: []}, {smart_proxy_names: []}, :content_type, :alternate_content_source_type,
86
101
  :upstream_username, :upstream_password, :ssl_ca_cert_id, :ssl_client_cert_id, :ssl_client_key_id,
87
102
  :http_proxy_id, :verify_ssl]
88
103
  params.require(:alternate_content_source).permit(*keys).to_h.with_indifferent_access
@@ -91,7 +106,15 @@ module Katello
91
106
  def find_smart_proxies
92
107
  if params[:smart_proxy_ids]
93
108
  @smart_proxies = ::SmartProxy.where(id: params[:smart_proxy_ids])
94
- fail HttpErrors::NotFound, _("Couldn't find smart proxies with id '%s'") % params[:smart_proxy_ids].to_sentence if @smart_proxies.empty?
109
+ elsif params[:smart_proxy_names]
110
+ @smart_proxies = ::SmartProxy.where(name: params[:smart_proxy_names])
111
+ end
112
+ if params[:smart_proxy_ids] && @smart_proxies.length < params[:smart_proxy_ids].length
113
+ missing_smart_proxies = params[:smart_proxy_ids] - @smart_proxies.pluck(:id)
114
+ fail HttpErrors::NotFound, _("Couldn't find smart proxies with id '%s'") % missing_smart_proxies.to_sentence
115
+ elsif params[:smart_proxy_names] && @smart_proxies.length < params[:smart_proxy_names].length
116
+ missing_smart_proxies = params[:smart_proxy_names] - @smart_proxies.pluck(:name)
117
+ fail HttpErrors::NotFound, _("Couldn't find smart proxies with name '%s'") % missing_smart_proxies.to_sentence
95
118
  end
96
119
  end
97
120
  end
@@ -57,7 +57,7 @@ module Katello
57
57
  else
58
58
  query
59
59
  end
60
- custom_sort = ->(sort_query) { sort_query.joins(join_query).order(order_query) }
60
+ custom_sort = ->(sort_query) { sort_query.joins(join_query).order(Arel.sql(order_query)) }
61
61
  options = { resource_class: Katello::ContentView, custom_sort: custom_sort }
62
62
  collection = scoped_search(query, nil, nil, options)
63
63
  collection[:results] = ComponentViewPresenter.component_presenter(@view, params[:status], views: collection[:results])
@@ -28,7 +28,7 @@ module Katello
28
28
  query = query.with_type(params[:content_type]) if params[:content_type]
29
29
  # Use custom sort to perform the join and order since we need to order by specific content_view
30
30
  # and the ORDER BY query needs access to the katello_content_view_repositories table
31
- custom_sort = ->(sort_query) { sort_query.joins(:root).joins(join_query).order(order_query) }
31
+ custom_sort = ->(sort_query) { sort_query.joins(:root).joins(join_query).order(Arel.sql(order_query)) }
32
32
  options = { resource_class: Katello::Repository, custom_sort: custom_sort }
33
33
  repos = scoped_search(query, nil, nil, options)
34
34
 
@@ -420,8 +420,8 @@ module Katello
420
420
  param 'id', String, :required => true
421
421
  param 'content_unit_id', String
422
422
  param 'size', String
423
- param 'checksum', String, :required => true
424
- param 'name', String, :required => true, :desc => N_("Needs to only be set for file repositories or docker tags")
423
+ param 'checksum', String
424
+ param 'name', String, :desc => N_("Needs to only be set for file repositories or docker tags")
425
425
  param 'digest', String, :desc => N_("Needs to only be set for docker tags")
426
426
  end
427
427
  Katello::RepositoryTypeManager.generic_repository_types.each_pair do |_, repo_type|
@@ -439,12 +439,6 @@ module Katello
439
439
  end
440
440
 
441
441
  uploads = (params[:uploads] || []).map do |upload|
442
- if upload[:checksum].nil?
443
- fail HttpErrors::BadRequest, _('Checksum is a required parameter.')
444
- end
445
- if upload[:name].nil?
446
- fail HttpErrors::BadRequest, _('Name is a required parameter.')
447
- end
448
442
  upload.permit(:id, :content_unit_id, :size, :checksum, :name, :digest).to_h
449
443
  end
450
444
 
@@ -0,0 +1,27 @@
1
+ module Actions
2
+ module Katello
3
+ module AlternateContentSource
4
+ class Refresh < Actions::EntryAction
5
+ def plan(acs)
6
+ action_subject(acs)
7
+ concurrence do
8
+ acs.smart_proxies.each do |smart_proxy|
9
+ plan_action(Pulp3::Orchestration::AlternateContentSource::Refresh,
10
+ acs, smart_proxy)
11
+ end
12
+ end
13
+ plan_self(acs_id: acs.id)
14
+ end
15
+
16
+ def finalize
17
+ acs = ::Katello::AlternateContentSource.find_by(id: input[:acs_id])
18
+ acs.update(last_refreshed: ::DateTime.now)
19
+ end
20
+
21
+ def humanized_name
22
+ _("Refresh Alternate Content Source")
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -21,7 +21,7 @@ module Actions
21
21
  full_path = if cdn_configuration.redhat_cdn?
22
22
  root.product.repo_url(root.library_instance.generate_content_path)
23
23
  elsif cdn_configuration.network_sync?
24
- resource.repository_url(content_label: root.content.label)
24
+ resource.repository_url(content_label: root.content.label, arch: root.arch, major: root.major, minor: root.minor)
25
25
  end
26
26
  plan_action(::Actions::Katello::Repository::Update, root, url: full_path)
27
27
  end
@@ -41,7 +41,7 @@ module Actions
41
41
  :triggered_by => options[:triggered_by]
42
42
  )
43
43
  source_repositories = []
44
- content_view.publish_repositories(options[:override_cvvs]) do |repositories|
44
+ content_view.publish_repositories(options[:override_components]) do |repositories|
45
45
  source_repositories += [repositories]
46
46
  end
47
47
 
@@ -9,7 +9,7 @@ module Actions
9
9
  def plan(organization)
10
10
  action_subject organization
11
11
  manifest_update = organization.products.redhat.any?
12
- path = "/tmp/#{rand}.zip"
12
+ path = File.join(::Rails.root, "tmp", "#{rand}.zip")
13
13
  details = organization.owner_details
14
14
  upstream = details['upstreamConsumer'].blank? ? {} : details['upstreamConsumer']
15
15
 
@@ -1,12 +1,12 @@
1
1
  module Actions
2
2
  module Pulp3
3
3
  module AlternateContentSource
4
- class Delete < Pulp3::Abstract
4
+ class Delete < Pulp3::AbstractAsyncTask
5
5
  def plan(acs, smart_proxy)
6
6
  plan_self(:acs_id => acs.id, :smart_proxy_id => smart_proxy.id)
7
7
  end
8
8
 
9
- def run
9
+ def invoke_external_task
10
10
  acs = ::Katello::AlternateContentSource.find(input[:acs_id])
11
11
  output[:response] = acs.backend_service(smart_proxy).delete_alternate_content_source
12
12
  end
@@ -1,12 +1,12 @@
1
1
  module Actions
2
2
  module Pulp3
3
3
  module AlternateContentSource
4
- class DeleteRemote < Pulp3::Abstract
4
+ class DeleteRemote < Pulp3::AbstractAsyncTask
5
5
  def plan(acs, smart_proxy)
6
6
  plan_self(:acs_id => acs.id, :smart_proxy_id => smart_proxy.id)
7
7
  end
8
8
 
9
- def run
9
+ def invoke_external_task
10
10
  acs = ::Katello::AlternateContentSource.find(input[:acs_id])
11
11
  output[:response] = acs.backend_service(smart_proxy).delete_remote
12
12
  end
@@ -0,0 +1,23 @@
1
+ module Actions
2
+ module Pulp3
3
+ module AlternateContentSource
4
+ class Refresh < Pulp3::AbstractAsyncTask
5
+ def plan(acs, smart_proxy)
6
+ plan_self(acs_id: acs.id, smart_proxy_id: smart_proxy.id)
7
+ end
8
+
9
+ def invoke_external_task
10
+ acs = ::Katello::AlternateContentSource.find(input[:acs_id])
11
+ output[:response] = acs.backend_service(smart_proxy).refresh
12
+ end
13
+
14
+ def rescue_strategy_for_self
15
+ # There are various reasons why refreshing fails, but not all of them are
16
+ # fatal. When failing to refresh, we continue with the task ending up
17
+ # in the warning state, but don't lock further refreshing
18
+ Dynflow::Action::Rescue::Skip
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,12 +1,12 @@
1
1
  module Actions
2
2
  module Pulp3
3
3
  module AlternateContentSource
4
- class Update < Pulp3::Abstract
4
+ class Update < Pulp3::AbstractAsyncTask
5
5
  def plan(acs, smart_proxy)
6
6
  plan_self(:acs_id => acs.id, :smart_proxy_id => smart_proxy.id)
7
7
  end
8
8
 
9
- def run
9
+ def invoke_external_task
10
10
  acs = ::Katello::AlternateContentSource.find(input[:acs_id])
11
11
  output[:response] = acs.backend_service(smart_proxy).update
12
12
  end
@@ -1,13 +1,13 @@
1
1
  module Actions
2
2
  module Pulp3
3
3
  module AlternateContentSource
4
- class UpdateRemote < Pulp3::Abstract
4
+ class UpdateRemote < Pulp3::AbstractAsyncTask
5
5
  def plan(acs, smart_proxy)
6
6
  acs.backend_service(smart_proxy).create_test_remote
7
7
  plan_self(:acs_id => acs.id, :smart_proxy_id => smart_proxy.id)
8
8
  end
9
9
 
10
- def run
10
+ def invoke_external_task
11
11
  acs = ::Katello::AlternateContentSource.find(input[:acs_id])
12
12
  output[:response] = acs.backend_service(smart_proxy).update_remote
13
13
  end
@@ -7,8 +7,6 @@ module Actions
7
7
  sequence do
8
8
  plan_action(Actions::Pulp3::AlternateContentSource::CreateRemote, acs, smart_proxy)
9
9
  plan_action(Actions::Pulp3::AlternateContentSource::Create, acs, smart_proxy)
10
- # TODO: Should the hrefs be committed to acs records in a new action? Is it okay to be in the service class methods?
11
- # -> i.e. do we need something like SaveVersions?
12
10
  end
13
11
  end
14
12
  end
@@ -0,0 +1,15 @@
1
+ module Actions
2
+ module Pulp3
3
+ module Orchestration
4
+ module AlternateContentSource
5
+ class Refresh < Pulp3::Abstract
6
+ def plan(acs, smart_proxy)
7
+ sequence do
8
+ plan_action(Actions::Pulp3::AlternateContentSource::Refresh, acs, smart_proxy)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -7,8 +7,6 @@ module Actions
7
7
  sequence do
8
8
  plan_action(Actions::Pulp3::AlternateContentSource::UpdateRemote, acs, smart_proxy)
9
9
  plan_action(Actions::Pulp3::AlternateContentSource::Update, acs, smart_proxy)
10
- # TODO: Should the hrefs be committed to acs records in a new action? Is it okay to be in the service class methods?
11
- # -> i.e. do we need something like SaveVersions?
12
10
  end
13
11
  end
14
12
  end
@@ -3,7 +3,6 @@ module Actions
3
3
  module Repository
4
4
  class RefreshDistribution < Pulp3::AbstractAsyncTask
5
5
  include Helpers::Presenter
6
- middleware.use Actions::Middleware::ExecuteIfContentsChanged
7
6
 
8
7
  def plan(repository, smart_proxy, options = {})
9
8
  smart_proxy = SmartProxy.unscoped.find_by(id: smart_proxy) #support bulk actions
@@ -16,11 +15,9 @@ module Actions
16
15
  :repository_id => repository.id,
17
16
  :smart_proxy_id => smart_proxy.id
18
17
  }
19
- refresh_options[:contents_changed] if options.key?(:contents_changed)
20
18
  action = plan_self(refresh_options)
21
19
 
22
- plan_action(SaveDistributionReferences, repository, smart_proxy,
23
- action.output, :contents_changed => options[:contents_changed])
20
+ plan_action(SaveDistributionReferences, repository, smart_proxy, action.output)
24
21
  end
25
22
  end
26
23
 
@@ -5,7 +5,7 @@ module Actions
5
5
  #This task creates a content unit and may or may not create a new repository version in the process
6
6
  def plan(file, repository, smart_proxy, tasks, unit_type_id, options = {})
7
7
  options[:file_name] = file[:filename]
8
- options[:sha256] = file[:sha256] || Digest::SHA256.hexdigest(File.read(file[:path]))
8
+ options[:sha256] = file[:sha256] || (Digest::SHA256.hexdigest(File.read(file[:path])) if file[:path].present?)
9
9
  plan_self(:repository_id => repository.id, :smart_proxy_id => smart_proxy.id, :tasks => tasks, :unit_type_id => unit_type_id, :options => options)
10
10
  end
11
11
 
@@ -2,8 +2,6 @@ module Actions
2
2
  module Pulp3
3
3
  module Repository
4
4
  class SaveDistributionReferences < Pulp3::Abstract
5
- middleware.use Actions::Middleware::ExecuteIfContentsChanged
6
-
7
5
  def plan(repository, smart_proxy, tasks, options = {})
8
6
  plan_self(repository_id: repository.id, smart_proxy_id: smart_proxy.id, tasks: tasks, contents_changed: options[:contents_changed])
9
7
  end
@@ -62,5 +62,10 @@ module Katello
62
62
  conditions = sanitize_sql_for_conditions(["? #{operator} ANY (subpaths)", value_to_sql(operator, value)])
63
63
  { conditions: conditions }
64
64
  end
65
+
66
+ def latest_dynflow_refresh_task
67
+ @latest_dynflow_refresh_task ||= ForemanTasks::Task::DynflowTask.where(:label => Actions::Katello::AlternateContentSource::Refresh.name).
68
+ for_resource(self).order(:started_at).last
69
+ end
65
70
  end
66
71
  end
@@ -101,6 +101,12 @@ module Katello
101
101
  ignore_404_exception { api.alternate_content_source_api.delete(href) } if href
102
102
  end
103
103
 
104
+ def refresh
105
+ href = smart_proxy_acs.alternate_content_source_href
106
+ # https://github.com/pulp/pulp_rpm/issues/2504
107
+ api.alternate_content_source_api.refresh(href, 'placeholder')
108
+ end
109
+
104
110
  private
105
111
 
106
112
  def insert_pulp_manifest!(subpaths)
@@ -24,12 +24,12 @@ module Katello
24
24
 
25
25
  def initialize(metadata:)
26
26
  @toc = metadata[:toc]
27
+ @gpg_keys = parse_gpg_keys(metadata[:gpg_keys]) if metadata[:gpg_keys]
27
28
  @products = parse_products(metadata[:products]) if metadata[:products]
28
29
  @repositories = parse_repositories(metadata[:repositories]) if metadata[:repositories]
29
30
  @content_view = parse_content_view(metadata[:content_view]) if metadata[:content_view]
30
31
  @content_view_version = parse_content_view_version(metadata[:content_view_version]) if metadata[:content_view_version]
31
32
  @from_content_view_version = parse_content_view_version(metadata[:from_content_view_version]) if metadata[:from_content_view_version]
32
- @gpg_keys = parse_gpg_keys(metadata[:gpg_keys]) if metadata[:gpg_keys]
33
33
  end
34
34
 
35
35
  private
@@ -231,11 +231,17 @@ module Katello
231
231
  return update_distribution
232
232
  end
233
233
 
234
- if dist_ref
234
+ if dist && dist_ref
235
+ # If the saved distribution reference is wrong, delete it and use the existing distribution
236
+ if dist.pulp_href != dist_ref.href
237
+ dist_ref.destroy
238
+ save_distribution_references([dist.pulp_href])
239
+ end
235
240
  return update_distribution
236
241
  end
237
242
 
238
243
  # Since we got this far, we need to create a new distribution
244
+ # Note: the distribution reference can't be saved yet because distribution creation is async
239
245
  begin
240
246
  create_distribution(relative_path)
241
247
  rescue api.client_module::ApiError => e
@@ -253,6 +259,9 @@ module Katello
253
259
 
254
260
  def create_distribution(path)
255
261
  distribution_data = api.distribution_class.new(secure_distribution_options(path))
262
+ unless ::Katello::RepositoryTypeManager.find(repo.content_type).pulp3_skip_publication
263
+ fail_missing_publication(distribution_data.publication)
264
+ end
256
265
  api.distributions_api.create(distribution_data)
257
266
  end
258
267
 
@@ -260,9 +269,16 @@ module Katello
260
269
  api.distributions_api.list(args).results
261
270
  end
262
271
 
272
+ def read_distribution(href = distribution_reference.href)
273
+ ignore_404_exception { api.distributions_api.read(href) }
274
+ end
275
+
263
276
  def update_distribution
264
277
  if distribution_reference
265
278
  options = secure_distribution_options(relative_path).except(:name)
279
+ unless ::Katello::RepositoryTypeManager.find(repo.content_type).pulp3_skip_publication
280
+ fail_missing_publication(options[:publication])
281
+ end
266
282
  distribution_reference.update(:content_guard_href => options[:content_guard])
267
283
  api.distributions_api.partial_update(distribution_reference.href, options)
268
284
  end
@@ -321,6 +337,12 @@ module Katello
321
337
  hrefs.each do |href|
322
338
  pulp3_distribution_data = api.get_distribution(href)
323
339
  path, content_guard_href = pulp3_distribution_data&.base_path, pulp3_distribution_data&.content_guard
340
+ if distribution_reference
341
+ found_distribution = read_distribution(distribution_reference.href)
342
+ unless found_distribution
343
+ distribution_reference.destroy
344
+ end
345
+ end
324
346
  unless distribution_reference
325
347
  # Ensure that duplicates won't be created in the case of a race condition
326
348
  DistributionReference.where(path: path, href: href, repository_id: repo.id, content_guard_href: content_guard_href).first_or_create!
@@ -473,6 +495,12 @@ module Katello
473
495
  return 0 if root.retain_package_versions_count.nil? || root.using_mirrored_content?
474
496
  root.retain_package_versions_count.to_i
475
497
  end
498
+
499
+ def fail_missing_publication(publication_href)
500
+ unless lookup_publication(publication_href)
501
+ fail _("The repository's publication is missing. Please run a 'complete sync' on %s." % repo.name)
502
+ end
503
+ end
476
504
  end
477
505
  end
478
506
  end
@@ -2,7 +2,16 @@ object @resource
2
2
 
3
3
  extends 'katello/api/v2/common/identifier'
4
4
 
5
- attributes :name, :base_url, :subpaths, :content_type, :alternate_content_source_type, :smart_proxies, :upstream_username
5
+ attributes :name, :base_url, :subpaths, :content_type, :alternate_content_source_type, :smart_proxies, :upstream_username, :last_refreshed
6
+
7
+ child :latest_dynflow_refresh_task => :last_refresh do |_object|
8
+ attributes :id, :username, :started_at, :ended_at, :state, :result, :progress
9
+ node :last_refresh_words do |object|
10
+ if (object.respond_to?('started_at') && object.started_at)
11
+ time_ago_in_words(Time.parse(object.started_at.to_s))
12
+ end
13
+ end
14
+ end
6
15
 
7
16
  if params.key?(:include_permissions)
8
17
  node :permissions do |alternate_content_source|
@@ -33,6 +33,18 @@ child :content_facet => :content_facet_attributes do
33
33
  node :remote_execution_by_default do
34
34
  Katello.remote_execution_by_default?
35
35
  end
36
+
37
+ user = User.current # current_user is not available here
38
+ child :permissions do
39
+ node(:view_lifecycle_environments) { user.can?("view_lifecycle_environments") }
40
+ node(:view_content_views) { user.can?("view_content_views") }
41
+ node(:promote_or_remove_content_views_to_environments) { user.can?("promote_or_remove_content_views_to_environments") }
42
+ node(:view_host_collections) { user.can?("view_host_collections") }
43
+ node(:create_job_invocations) { user.can?("create_job_invocations") }
44
+ node(:view_activation_keys) { user.can?("view_activation_keys") }
45
+ node(:view_products) { user.can?("view_products") }
46
+ node(:create_bookmarks) { user.can?("create_bookmarks") }
47
+ end
36
48
  end
37
49
 
38
50
  attributes :description, :facts
@@ -37,6 +37,10 @@ child @resource.repositories => :repositories do
37
37
  attributes :minor => :releasever
38
38
  end
39
39
 
40
+ node :osRestricted do |pc|
41
+ pc.repositories&.first&.os_versions&.first
42
+ end
43
+
40
44
  node :override do |pc|
41
45
  pc.override if pc.respond_to? :override
42
46
  end
@@ -14,6 +14,10 @@ Katello::Engine.routes.draw do
14
14
  # re-routes alphabetical
15
15
  ##############################
16
16
 
17
+ api_resources :alternate_content_sources, :only => [:index, :show, :create, :update, :destroy] do
18
+ get :auto_complete_search, :on => :collection
19
+ end
20
+
17
21
  api_resources :capsules, :only => [:index, :show] do
18
22
  member do
19
23
  resource :content, :only => [], :controller => 'capsule_content' do
@@ -349,6 +353,18 @@ Katello::Engine.routes.draw do
349
353
  ##############################
350
354
  ##############################
351
355
 
356
+ api_resources :alternate_content_sources, :only => [], :constraints => { :id => /[0-9a-zA-Z\-_.]*/ } do
357
+ collection do
358
+ match '/bulk/destroy' => 'alternate_content_sources_bulk_actions#destroy_alternate_content_sources', :via => :put
359
+ match '/bulk/refresh' => 'alternate_content_sources_bulk_actions#refresh_alternate_content_sources', :via => :post
360
+ get :auto_complete_search
361
+ end
362
+
363
+ member do
364
+ post :refresh
365
+ end
366
+ end
367
+
352
368
  api_resources :organizations do
353
369
  api_resources :sync_plans do
354
370
  member do
@@ -469,10 +485,6 @@ Katello::Engine.routes.draw do
469
485
  get :auto_complete_search, :on => :collection
470
486
  put :sync
471
487
  end
472
-
473
- api_resources :alternate_content_sources, :only => [:index, :show, :create, :update, :destroy] do
474
- get :auto_complete_search, :on => :collection
475
- end
476
488
  end # module v2
477
489
  end # '/api' namespace
478
490
  end # '/katello' namespace