Class: Katello::Api::V2::RepositoriesController

Inherits:
ApiController
  • Object
show all
Includes:
Concerns::FilteredAutoCompleteSearch
Defined in:
app/controllers/katello/api/v2/repositories_controller.rb

Overview

rubocop:disable Metrics/ClassLength

Constant Summary collapse

CONTENT_CREDENTIAL_GPG_KEY_TYPE =
"gpg_key".freeze
CONTENT_CREDENTIAL_SSL_CA_CERT_TYPE =
"ssl_ca_cert".freeze
CONTENT_CREDENTIAL_SSL_CLIENT_CERT_TYPE =
"ssl_client_cert".freeze
CONTENT_CREDENTIAL_SSL_CLIENT_KEY_TYPE =
"ssl_client_key".freeze

Constants included from Concerns::FilteredAutoCompleteSearch

Concerns::FilteredAutoCompleteSearch::PAGE_SIZE

Instance Method Summary collapse

Methods included from Concerns::FilteredAutoCompleteSearch

#auto_complete_search

Methods inherited from ApiController

#check_katello_agent_not_disabled, #deprecate_katello_agent, #empty_search_query?, #full_result_response, #katello_agent_removal_release, #resource_class, #scoped_search, #skip_session

Methods included from Rendering

#respond_for_async, #respond_for_bulk_async, #respond_for_create, #respond_for_destroy, #respond_for_index, #respond_for_show, #respond_for_status, #respond_for_update, #respond_with_template, #respond_with_template_collection, #respond_with_template_resource, #try_specific_collection_template, #try_specific_resource_template

Methods included from Katello::Api::Version2

#api_version

Instance Method Details

#compareObject



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 241

def compare
  fail _("No content_view_version_ids provided") if params[:content_view_version_ids].empty?
  @versions = ContentViewVersion.readable.where(:id => params[:content_view_version_ids])
  if @versions.count != params[:content_view_version_ids].uniq.length
    missing = params[:content_view_version_ids] - @versions.pluck(:id)
    fail HttpErrors::NotFound, _("Couldn't find content view versions '%s'") % missing.join(',')
  end

  archived_version_repos = Katello::Repository.where(:content_view_version_id => @versions&.pluck(:id))&.archived
  repos = Katello::Repository.where(id: archived_version_repos&.pluck(:library_instance_id))
  repos = repos.where(:root_id => @repo.root_id) if @repo
  repositories = restrict_comparison(repos, @versions, params[:restrict_comparison])
  collection = scoped_search(repositories.distinct, :name, :asc)
  collection[:results] = collection[:results].map { |item| ContentViewVersionComparePresenter.new(item, @versions, @repo) }
  respond_for_index(:collection => collection)
end

#compare_same(collection, content_view_versions = nil) ⇒ Object



271
272
273
274
275
276
277
278
279
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 271

def compare_same(collection, content_view_versions = nil)
  same_repo_ids = []
  collection.each do |repo|
    if (content_view_versions&.pluck(:id)&.- repo.published_in_versions&.pluck(:id))&.empty?
      same_repo_ids << repo.id
    end
  end
  same_repo_ids
end

#content_typesObject



547
548
549
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 547

def content_types
  render :json => Katello::RepositoryTypeManager.enabled_content_types.map { |type| Katello::RepositoryTypeManager.find_content_type(type) }
end

#createObject



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 286

def create
  repo_params = repository_params
  unless RepositoryTypeManager.creatable_by_user?(repo_params[:content_type], false)
    msg = _("Invalid params provided - content_type must be one of %s") %
      RepositoryTypeManager.creatable_repository_types.keys.sort.join(",")
    fail HttpErrors::UnprocessableEntity, msg
  end

  if !repo_params[:url].nil? && URI(repo_params[:url]).userinfo
    fail "Do not include the username/password in the URL. Use the username/password settings instead."
  end

  gpg_key = get_content_credential(repo_params, CONTENT_CREDENTIAL_GPG_KEY_TYPE)
  ssl_ca_cert = get_content_credential(repo_params, CONTENT_CREDENTIAL_SSL_CA_CERT_TYPE)
  ssl_client_cert = get_content_credential(repo_params, CONTENT_CREDENTIAL_SSL_CLIENT_CERT_TYPE)
  ssl_client_key = get_content_credential(repo_params, CONTENT_CREDENTIAL_SSL_CLIENT_KEY_TYPE)

  repo_params[:label] = labelize_params(repo_params)
  repo_params[:arch] = repo_params[:arch] || 'noarch'
  repo_params[:url] = nil if repo_params[:url].blank?
  repo_params[:unprotected] = repo_params.key?(:unprotected) ? repo_params[:unprotected] : true
  repo_params[:gpg_key] = gpg_key
  repo_params[:ssl_ca_cert] = ssl_ca_cert
  repo_params[:ssl_client_cert] = ssl_client_cert
  repo_params[:ssl_client_key] = ssl_client_key

  root = construct_repo_from_params(repo_params)
  sync_task(::Actions::Katello::Repository::CreateRoot, root)
  @repository = root.reload.library_instance
  respond_for_create(:resource => @repository)
end

#custom_index_relation(collection) ⇒ Object



38
39
40
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 38

def custom_index_relation(collection)
  collection.includes(:product)
end

#destroyObject



419
420
421
422
423
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 419

def destroy
  sync_task(::Actions::Katello::Repository::Destroy, @repository,
    remove_from_content_view_versions: ::Foreman::Cast.to_bool(params.fetch(:remove_from_content_view_versions, false)))
  respond_for_destroy
end

#gpg_key_contentObject



538
539
540
541
542
543
544
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 538

def gpg_key_content
  if @repository.root.gpg_key && @repository.root.gpg_key.content.present?
    render(:plain => @repository.root.gpg_key.content, :layout => false)
  else
    head(404)
  end
end

#import_uploadsObject



497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 497

def import_uploads
   = ::Foreman::Cast.to_bool(params.fetch(:publish_repository, true))
  sync_capsule = ::Foreman::Cast.to_bool(params.fetch(:sync_capsule, true))
  async = ::Foreman::Cast.to_bool(params.fetch(:async, false))
  if params['uploads'].empty?
    fail HttpErrors::BadRequest, _('No uploads param specified. An array of uploads to import is required.')
  end

  uploads = (params[:uploads] || []).map do |upload|
    upload.permit(:id, :content_unit_id, :size, :checksum, :name, :digest).to_h
  end

  if @repository.content_type != 'docker' && uploads.first['checksum'].nil?
    fail HttpErrors::BadRequest, _('Checksum is a required parameter.')
  end

  if uploads.first['name'].nil?
    fail HttpErrors::BadRequest, _('Name is a required parameter.')
  end

  begin
    upload_args = {
      content_type: params[:content_type],
      generate_metadata: ,
      sync_capsule: sync_capsule
    }
    upload_args.merge!(generic_content_type_import_upload_args)

    respond_for_async(resource: send(
      async ? :async_task : :sync_task,
      ::Actions::Katello::Repository::ImportUpload, @repository, uploads, upload_args))
  rescue => e
    raise HttpErrors::BadRequest, e.message
  end
end

#indexObject



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
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 115

def index
  unless params[:content_type].empty? || RepositoryTypeManager.find(params[:content_type])
    msg = _("Invalid params provided - content_type must be one of %s") %
      RepositoryTypeManager.enabled_repository_types.keys.sort.join(",")
    fail HttpErrors::UnprocessableEntity, msg
  end
  unless params[:with_content].empty? || RepositoryTypeManager.find_content_type(params[:with_content], true)
    msg = _("Invalid params provided - with_content must be one of %s") %
      RepositoryTypeManager.indexable_content_types.map(&:label).sort.join(",")
    fail HttpErrors::UnprocessableEntity, msg
  end
  base_args = [index_relation.distinct, :name, :asc]
  options = {:includes => [:environment, {:root => [:gpg_key, :product]}]}

  respond_to do |format|
    format.csv do
      options[:csv] = true
      repos = scoped_search(*base_args, options)
      csv_response(repos,
                   [:id, :name, :description, :label, :content_type, :arch, :url, :major, :minor,
                    :content_label, :pulp_id, :container_repository_name,
                    :download_policy, 'relative_path', 'product.id', 'product.name',
                    'environment_id'],
                   ['Id', 'Name', 'Description', 'label', 'Content Type', 'Arch', 'Url', 'Major', 'Minor',
                    'Content Label', 'Pulp Id', 'Container Repository Name', 'Download Policy', 'Relative Path',
                    'Product Id', 'Product Name',
                    'Environment Id'])
    end
    format.any do
      repos = scoped_search(*base_args, options)
      respond(:collection => repos)
    end
  end
end

#index_relationObject



150
151
152
153
154
155
156
157
158
159
160
161
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 150

def index_relation
  query = Repository.readable
  query = query.with_content(params[:with_content]) if params[:with_content]
  query = index_relation_product(query)
  query = query.with_type(params[:content_type]) if params[:content_type]
  query = query.where(:root_id => RootRepository.where(:name => params[:name])) if params[:name]
  query = query.where(:root_id => RootRepository.where(:label => params[:label])) if params[:label]
  query = index_relation_content_unit(query)
  query = index_relation_content_view(query)
  query = index_relation_environment(query)
  query
end

#index_relation_content_unit(query) ⇒ Object



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
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 201

def index_relation_content_unit(query)
  if params[:deb_id]
    query = query.joins(:debs)
      .where("#{Deb.table_name}.id" => Deb.with_identifiers(params[:deb_id]))
  end

  if params[:erratum_id]
    query = query.joins(:errata)
      .where("#{Erratum.table_name}.id" => Erratum.with_identifiers(params[:erratum_id]))
  end

  if params[:rpm_id]
    query = query.joins(:rpms)
      .where("#{Rpm.table_name}.id" => Rpm.with_identifiers(params[:rpm_id]))
  end

  if params[:file_id]
    query = query.joins(:files)
      .where("#{FileUnit.table_name}.id" => FileUnit.with_identifiers(params[:file_id]))
  end

  if params[:ansible_collection_id]
    query = query.joins(:ansible_collections)
                .where("#{AnsibleCollection.table_name}.id" => AnsibleCollection.with_identifiers(params[:ansible_collection_id]))
  end

  generic_type_param = RepositoryTypeManager.generic_content_types.find { |type| params["#{type}_id".to_sym] }
  if generic_type_param
    query = query.joins(:generic_content_units)
                 .where("#{GenericContentUnit.table_name}.id" => GenericContentUnit.with_identifiers(params["#{generic_type_param}_id".to_sym]))
  end

  query
end

#index_relation_content_view(query) ⇒ Object



170
171
172
173
174
175
176
177
178
179
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 170

def index_relation_content_view(query)
  if params[:content_view_version_id]
    query = query.where(:content_view_version_id => params[:content_view_version_id])
    query = query.archived if ::Foreman::Cast.to_bool params[:archived]
    query = Katello::Repository.where(:id => query.select(:library_instance_id)) if params[:library]
  elsif params[:content_view_id]
    query = filter_by_content_view(query, params[:content_view_id], params[:environment_id], params[:available_for] == 'content_view')
  end
  query
end

#index_relation_environment(query) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 181

def index_relation_environment(query)
  if params[:environment_id] && !params[:library]
    query = query.where(:environment_id => params[:environment_id])
  elsif params[:environment_id] && params[:library]
    instances = query.where(:environment_id => params[:environment_id])
    instance_ids = instances.pluck(:library_instance_id).reject(&:blank?)
    instance_ids += instances.where(:library_instance_id => nil)
    query = Repository.where(:id => instance_ids)
  elsif (params[:library] && !params[:environment_id]) || (params[:environment_id].blank? && params[:content_view_version_id].blank? && params[:content_view_id].blank?)
    if params[:available_for] == 'content_view_version'
      query = query.where.not(:content_view_version_id => nil, :environment_id => nil)
    elsif @organization
      query = query.where(:content_view_version_id => @organization.default_content_view.versions.first.id)
    else
      query = query.in_default_view
    end
  end
  query
end

#index_relation_product(query) ⇒ Object



163
164
165
166
167
168
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 163

def index_relation_product(query)
  query = query.joins(:root => :product).where("#{Product.table_name}.organization_id" => @organization) if @organization
  query = query.joins(:root).where("#{RootRepository.table_name}.product_id" => @product.id) if @product
  query = query.joins(:root).where("#{RootRepository.table_name}.download_policy" => params[:download_policy]) if params[:download_policy]
  query
end

#reclaim_spaceObject



383
384
385
386
387
388
389
390
391
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 383

def reclaim_space
  if @repository.download_policy != ::Katello::RootRepository::DOWNLOAD_ON_DEMAND
    fail HttpErrors::BadRequest, _("Only On Demand repositories may have space reclaimed.")
  end
  task = async_task(::Actions::Pulp3::Repository::ReclaimSpace, @repository)
  respond_for_async :resource => task
rescue Errors::InvalidActionOptionError => e
  raise HttpErrors::BadRequest, e.message
end

#remove_contentObject



433
434
435
436
437
438
439
440
441
442
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 433

def remove_content
  unless params[:content_type].empty? || RepositoryTypeManager.removable_content_types.map(&:label).include?(params[:content_type])
    msg = _("Invalid params provided - content_type must be one of %s") %
      RepositoryTypeManager.removable_content_types.map(&:label).sort.join(",")
    fail HttpErrors::UnprocessableEntity, msg
  end
  sync_capsule = ::Foreman::Cast.to_bool(params.fetch(:sync_capsule, true))
  fail _("No content ids provided") if @content.blank?
  respond_for_async :resource => sync_task(::Actions::Katello::Repository::RemoveContent, @repository, @content, content_type: params[:content_type], sync_capsule: sync_capsule)
end

#repository_typesObject



320
321
322
323
324
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 320

def repository_types
  creatable = ::Foreman::Cast.to_bool(params[:creatable])
  repo_types = creatable ? RepositoryTypeManager.creatable_repository_types : RepositoryTypeManager.enabled_repository_types
  render :json => repo_types.values
end

#republishObject



329
330
331
332
333
334
335
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 329

def republish
  unless ::Foreman::Cast.to_bool(params[:force])
    fail HttpErrors::BadRequest, _('Metadata republishing must be forced because it is a dangerous operation.')
  end
  task = async_task(::Actions::Katello::Repository::MetadataGenerate, @repository)
  respond_for_async :resource => task
end

#restrict_comparison(collection, content_view_versions = nil, compare = 'all') ⇒ Object



258
259
260
261
262
263
264
265
266
267
268
269
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 258

def restrict_comparison(collection, content_view_versions = nil, compare = 'all')
  case compare
  when 'same'
    same_repo_ids = compare_same(collection, content_view_versions)
    collection.where(id: same_repo_ids)
  when 'different'
    same_repo_ids = compare_same(collection, content_view_versions)
    collection.where.not(id: same_repo_ids)
  else
    collection
  end
end

#showObject



340
341
342
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 340

def show
  respond_for_show(:resource => @repository)
end

#syncObject



350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 350

def sync
  sync_options = {
    :skip_metadata_check => ::Foreman::Cast.to_bool(params[:skip_metadata_check]),
    :validate_contents => ::Foreman::Cast.to_bool(params[:validate_contents]),
    :incremental => ::Foreman::Cast.to_bool(params[:incremental]),
    :source_url => params[:source_url]
  }

  if params[:source_url].present? && params[:source_url] !~ /\A#{URI::DEFAULT_PARSER.make_regexp}\z/
    fail HttpErrors::BadRequest, _("source URL is malformed")
  end

  if params[:source_url].blank? && @repository.url.blank?
    fail HttpErrors::BadRequest, _("attempted to sync without a feed URL")
  end

  task = async_task(::Actions::Katello::Repository::Sync, @repository, sync_options)
  respond_for_async :resource => task
rescue Errors::InvalidActionOptionError => e
  raise HttpErrors::BadRequest, e.message
end

#updateObject



398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 398

def update
  repo_params = repository_params
  if !repo_params[:url].nil? && URI(repo_params[:url]).userinfo
    fail "Do not include the username/password in the URL. Use the username/password settings instead."
  end

  if @repository.generic?
    generic_remote_options = generic_remote_options_hash(repo_params)
    repo_params[:generic_remote_options] = generic_remote_options.to_json
    RepositoryTypeManager.generic_remote_options.each do |option|
      repo_params&.delete(option.name)
    end
  end

  sync_task(::Actions::Katello::Repository::Update, @repository.root, repo_params)
  respond_for_show(:resource => @repository)
end

#upload_contentObject



448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 448

def upload_content
  fail Katello::Errors::InvalidRepositoryContent, _("Cannot upload Container Image content.") if @repository.docker?
  fail Katello::Errors::InvalidRepositoryContent, _("Cannot upload Ansible collections.") if @repository.ansible_collection?
  unless params[:content_type].empty? || RepositoryTypeManager.uploadable_content_types.map(&:label).include?(params[:content_type])
    msg = _("Invalid params provided - content_type must be one of %s") %
      RepositoryTypeManager.uploadable_content_types.map(&:label).sort.join(",")
    fail HttpErrors::UnprocessableEntity, msg
  end

  filepaths = Array.wrap(params[:content]).compact.collect do |content|
    {path: content.path, filename: content.original_filename}
  end

  if !filepaths.blank?
    sync_task(::Actions::Katello::Repository::UploadFiles, @repository, filepaths, params[:content_type])
    render :json => {:status => "success", :filenames => filepaths.map { |item| item[:filename] }}
  else
    fail HttpErrors::BadRequest, _("No file uploaded")
  end
rescue Katello::Errors::InvalidRepositoryContent => error
  respond_for_exception(
    error,
    :status => :unprocessable_entity,
    :text => error.message,
    :errors => [error.message],
    :with_logging => true
  )
end

#verify_checksumObject



374
375
376
377
378
379
# File 'app/controllers/katello/api/v2/repositories_controller.rb', line 374

def verify_checksum
  task = async_task(::Actions::Katello::Repository::VerifyChecksum, @repository)
  respond_for_async :resource => task
rescue Errors::InvalidActionOptionError => e
  raise HttpErrors::BadRequest, e.message
end