forked from Katello/katello
-
Notifications
You must be signed in to change notification settings - Fork 0
/
repository_sets_controller.rb
264 lines (229 loc) · 12.5 KB
/
repository_sets_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
module Katello
class Api::V2::RepositorySetsController < Api::V2::ApiController
respond_to :json
include Katello::Concerns::FilteredAutoCompleteSearch
before_action :set_readable_product_scope, only: [:index, :show, :available_repositories, :auto_complete_search]
before_action :set_editable_product_scope, only: [:enable, :disable]
before_action :find_product
before_action :custom_product?
before_action :setup_params
before_action :find_authorized_activation_key, :only => [:index, :auto_complete_search]
before_action :find_authorized_host, :only => [:index, :auto_complete_search]
before_action :find_organization
before_action :find_product_content, :except => [:index, :auto_complete_search]
before_action :check_airgapped, :only => [:available_repositories, :enable, :disable]
resource_description do
api_version "v2"
end
api :GET, "/repository_sets", N_("List repository sets.")
api :GET, "/products/:product_id/repository_sets", N_("List repository sets for a product.")
param :product_id, :number, :required => false, :desc => N_("ID of a product to list repository sets from")
param :name, String, :required => false, :desc => N_("Repository set name to search on")
param :enabled, :bool, :required => false, :desc => N_("If true, only return repository sets that have been enabled. Defaults to false")
param :with_active_subscription, :bool, :required => false, :desc => N_("If true, only return repository sets that are associated with an active subscriptions")
param :organization_id, :number, :desc => N_("organization identifier"), :required => false
param :with_custom, :bool, :required => false, :desc => N_("If true, return custom repository sets along with redhat repos")
param :activation_key_id, :number, :desc => N_("activation key identifier"), :required => false
param :host_id, :number, :desc => N_("Id of the host"), :required => false
param :content_access_mode_all, :bool, :desc => N_("Get all content available, not just that provided by subscriptions.")
param :content_access_mode_env, :bool, :desc => N_("Limit content to just that available in the host's or activation key's content view version and lifecycle environment.")
param :status, [:enabled, :disabled, :overridden],
:desc => N_("Limit content to enabled / disabled / overridden"),
:required => false
param_group :search, Api::V2::ApiController
add_scoped_search_description_for(Katello::ProductContent)
def index
collection = scoped_search(index_relation, :name, :asc, :resource_class => Katello::ProductContent, :custom_sort => ->(relation) { custom_sort_results(relation) })
pcf = ProductContentFinder.wrap_with_overrides(
product_contents: collection[:results],
overrides: @consumable&.content_overrides)
collection[:results] = pcf
respond(:collection => collection)
end
api :GET, "/repository_sets/:id", N_("Get info about a repository set")
api :GET, "/products/:product_id/repository_sets/:id", N_("Get info about a repository set")
param :id, :number, :required => true, :desc => N_("ID of the repository set")
param :product_id, :number, :required => false, :desc => N_("ID of a product to list repository sets from")
param :organization_id, :number, :desc => N_("organization identifier"), :required => false
def show
respond :resource => @product_content
end
api :GET, "/repository_sets/:id/available_repositories", N_("Get list of available repositories for the repository set")
api :GET, "/products/:product_id/repository_sets/:id/available_repositories", N_("Get list of available repositories for the repository set")
param :id, :number, :required => true, :desc => N_("ID of the repository set")
param :product_id, :number, :required => false, :desc => N_("ID of a product to list repository sets from")
param :organization_id, :number, :desc => N_("organization identifier"), :required => false
def available_repositories
scan_cdn = sync_task(::Actions::Katello::RepositorySet::ScanCdn, @product, @product_content.content.cp_content_id)
repos = scan_cdn.output[:results]
repos = repos.select do |repo|
if repo[:path].include?('kickstart') && repo[:substitutions][:releasever].present?
repo[:substitutions][:releasever].include?('.') || repo[:enabled]
else
true
end
end
sorted_repos = repos.sort_by do |repo|
major, minor = repo[:substitutions][:releasever].nil? ? [1000, 1000] : repo[:substitutions][:releasever].split('.').map(&:to_i)
major = major == 0 ? 1000 : major
minor = minor.nil? ? 1000 : minor
arch = repo[:substitutions][:basearch].nil? ? "" : repo[:substitutions][:basearch]
[arch, major, minor]
end
collection = {
:results => sorted_repos.reverse,
:subtotal => repos.size,
:total => repos.size
}
respond_for_index :collection => collection
end
api :PUT, "/repository_sets/:id/enable", N_("Enable a repository from the set")
api :PUT, "/products/:product_id/repository_sets/:id/enable", N_("Enable a repository from the set")
param :id, :number, :required => true, :desc => N_("ID of the repository set to enable")
param :product_id, :number, :required => false, :desc => N_("ID of the product containing the repository set")
param :basearch, String, :required => false, :desc => N_("Basearch to enable")
param :releasever, String, :required => false, :desc => N_("Releasever to enable")
param :organization_id, :number, :desc => N_("organization identifier"), :required => false
def enable
task = sync_task(::Actions::Katello::RepositorySet::EnableRepository, @product, @product_content.content, substitutions)
respond_for_async :resource => task
end
api :PUT, "/repository_sets/:id/disable", N_("Disable a repository from the set")
api :PUT, "/products/:product_id/repository_sets/:id/disable", N_("Disable a repository from the set")
param :id, :number, :required => true, :desc => N_("ID of the repository set to disable")
param :repository_id, :number, :required => false, :desc => N_("ID of the repository within the set to disable")
param :product_id, :number, :required => false, :desc => N_("ID of the product containing the repository set")
param :basearch, String, :required => false, :desc => N_("Basearch to disable")
param :releasever, String, :required => false, :desc => N_("Releasever to disable")
param :organization_id, :number, :desc => N_("organization identifier"), :required => false
def disable
task = sync_task(::Actions::Katello::RepositorySet::DisableRepository, @product, @product_content.content, substitutions)
respond_for_async :resource => task
end
protected
def resource_class
Katello::ProductContent
end
def index_relation
if @product.nil?
authorized_product_contents = Katello::ProductContent.joins(:product).merge(@product_scope)
relation = @organization.product_contents.merge(authorized_product_contents).displayable
else
relation = @product.displayable_product_contents
end
if ::Foreman::Cast.to_bool(params[:enabled])
relation = relation.enabled(@organization)
elsif ::Foreman::Cast.to_bool(params[:with_active_subscription])
relation = relation.with_valid_subscription(@organization)
else
relation = relation.where(:id => Katello::ProductContent.with_valid_subscription(@organization)).or(
relation.where(:id => Katello::ProductContent.enabled(@organization)))
end
relation = relation.where(Katello::Content.table_name => {:name => params[:name]}) if params[:name].present?
relation = relation.redhat unless ::Foreman::Cast.to_bool(params[:with_custom])
index_relation_with_consumable_overrides(relation)
end
def index_relation_with_consumable_overrides(relation)
return relation if @consumable.blank?
content_access_mode_all = ::Foreman::Cast.to_bool(params[:content_access_mode_all])
content_access_mode_env = ::Foreman::Cast.to_bool(params[:content_access_mode_env])
content_finder = ProductContentFinder.new(
:match_subscription => !content_access_mode_all,
:match_environment => content_access_mode_env,
:consumable => @consumable)
unfiltered = relation.merge(content_finder.product_content)
return unfiltered unless params[:status]
filtered_ids = ProductContentFinder.wrap_with_overrides(
product_contents: unfiltered,
overrides: @consumable&.content_overrides,
status: params[:status]).map(&:id).uniq
unfiltered.where(id: filtered_ids)
end
def find_product_content
if @product.present?
@product_content = @product.product_content_by_id(params[:id])
else
content = Katello::Content.where(cp_content_id: params[:id], organization: @organization)
authorized_product_contents = Katello::ProductContent.joins(:product).merge(@product_scope)
@product_content = authorized_product_contents.joins(:content).merge(content).first
@product = @product_content&.product
end
throw_resource_not_found(name: 'repository set', id: params[:id]) if @product_content.nil?
end
def find_product
if params[:product_id]
@product = @product_scope.find_by(id: params[:product_id])
throw_resource_not_found(name: 'product', id: params[:product_id]) if @product.nil?
end
end
def set_readable_product_scope
@product_scope = Katello::Product.readable
end
def set_editable_product_scope
@product_scope = Katello::Product.editable
end
def find_organization
@organization = @product&.organization || @consumable&.organization || super
end
def custom_product?
fail _('Repository sets are not available for custom products.') if @product&.custom?
end
def substitutions
params.permit(:basearch, :releasever, :repository_id).to_h
end
def find_authorized_activation_key
return unless params[:activation_key_id]
@activation_key = ActivationKey.readable.find_by(:id => params[:activation_key_id])
@consumable = @activation_key
throw_resource_not_found(name: 'activation_key', id: params[:activation_key_id]) if @activation_key.blank?
end
def find_authorized_host
return unless params[:host_id]
find_host_with_subscriptions(params[:host_id], :view_hosts)
@consumable = @host.subscription_facet
end
def setup_params
return unless params[:id]
if params[:entity] == :activation_key
params[:activation_key_id] ||= params[:id]
else
params[:host_id] ||= params[:id]
end
end
def check_airgapped
if @organization.cdn_configuration.export_sync?
fail HttpErrors::BadRequest, _("Repositories are not available for enablement while CDN configuration is set to Air-gapped (disconnected).")
end
end
def sort_score(pc) # sort order for enabled
score = if pc.enabled_content_override&.value == "1"
4 # overridden to enabled
elsif pc.enabled_content_override.nil? && pc.enabled
3 # enabled
elsif pc.enabled_content_override.nil? && !pc.enabled
2 # disabled
elsif pc.enabled_content_override&.value == "0"
1 # overridden to disabled
else
0
end
score
end
def custom_sort_results(unsorted_relation)
return unsorted_relation unless params[:sort_by] == 'enabled_by_default'
product_content_finder = ProductContentFinder.wrap_with_overrides(
product_contents: unsorted_relation,
overrides: @consumable&.content_overrides,
status: params[:status])
sorted_pcps = if params[:sort_by] == 'enabled_by_default' && params[:sort_order] == 'desc'
product_content_finder.sort { |pca, pcb| sort_score(pca) <=> sort_score(pcb) }.reverse!
elsif params[:sort_by] == 'enabled_by_default'
product_content_finder.sort { |pca, pcb| sort_score(pca) <=> sort_score(pcb) }
else
product_content_finder
end
sort_order = sorted_pcps.map(&:id)
unsorted_relation.reorder(Arel.sql("array_position('{#{sort_order.join(',')}}'::int[], #{Katello::ProductContent.table_name}.id)"))
end
end
end