Class: Katello::Repository

Inherits:
Model
  • Object
show all
Includes:
ERB::Util, ForemanTasks::Concerns::ActionSubject, Authorization::Repository, Glue, Glue::Candlepin::Repository, ScopedSearchExtensions
Defined in:
app/models/katello/repository.rb

Overview

rubocop:disable Metrics/ClassLength

Defined Under Namespace

Classes: Jail

Constant Summary collapse

PULP_ID_MAX_LENGTH =

pulp uses pulp id to sync with ‘yum_distributor’ on the end

220
AUDIT_SYNC_ACTION =
'sync'.freeze
DEB_TYPE =
'deb'.freeze
YUM_TYPE =
'yum'.freeze
FILE_TYPE =
'file'.freeze
DOCKER_TYPE =
'docker'.freeze
OSTREE_TYPE =
'ostree'.freeze
ANSIBLE_COLLECTION_TYPE =
'ansible_collection'.freeze
GENERIC_TYPE =
'generic'.freeze
EXPORTABLE_TYPES =
[YUM_TYPE, FILE_TYPE, ANSIBLE_COLLECTION_TYPE, DOCKER_TYPE, DEB_TYPE].freeze
ALLOWED_UPDATE_FIELDS =
['version_href', 'last_indexed'].freeze

Constants included from Glue::Candlepin::Repository

Glue::Candlepin::Repository::CANDLEPIN_DOCKER_TYPE, Glue::Candlepin::Repository::CANDLEPIN_OSTREE_TYPE

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Authorization::Repository

#deletable?, #readable?, #redhat_deletable?

Methods included from Glue

logger

Methods included from Glue::Candlepin::Repository

included

Methods inherited from Model

#destroy!

Class Method Details

.attribute_nameObject



270
271
272
# File 'app/models/katello/repository.rb', line 270

def self.attribute_name
  :name
end

.clean_container_name(name) ⇒ Object



980
981
982
# File 'app/models/katello/repository.rb', line 980

def self.clean_container_name(name)
  name.gsub(/[^-\/\w]/, "_").gsub(/_{3,}/, "_").gsub(/-_|^_+|_+$/, "").downcase.strip
end

.errata_with_module_stream_counts(repo) ⇒ Object



407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'app/models/katello/repository.rb', line 407

def self.errata_with_module_stream_counts(repo)
  repository_errata = Katello::RepositoryErratum.table_name
  errata = Katello::Erratum.table_name
  erratum_package = Katello::ErratumPackage.table_name
  repository_module_stream = Katello::RepositoryModuleStream.table_name
  msep = ::Katello::ModuleStreamErratumPackage.table_name
  ::Katello::Erratum.joins(
    "INNER JOIN #{erratum_package} on #{erratum_package}.erratum_id = #{errata}.id",
    "INNER JOIN #{msep} on #{msep}.erratum_package_id = #{erratum_package}.id",
    "INNER JOIN #{repository_errata} on #{repository_errata}.erratum_id = #{errata}.id",
    "INNER JOIN #{repository_module_stream} on #{repository_module_stream}.module_stream_id = #{msep}.module_stream_id").
    where("#{repository_module_stream}.repository_id" => repo.id).
    where("#{repository_errata}.repository_id" => repo.id).
    group("#{errata}.id").count
end

.errata_with_package_counts(repo) ⇒ Object



391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'app/models/katello/repository.rb', line 391

def self.errata_with_package_counts(repo)
  repository_rpm = Katello::RepositoryRpm.table_name
  repository_errata = Katello::RepositoryErratum.table_name
  rpm = Katello::Rpm.table_name
  errata = Katello::Erratum.table_name
  erratum_package = Katello::ErratumPackage.table_name
  ::Katello::Erratum.joins(
    "INNER JOIN #{erratum_package} on #{erratum_package}.erratum_id = #{errata}.id",
    "INNER JOIN #{repository_errata} on #{repository_errata}.erratum_id = #{errata}.id",
    "INNER JOIN #{rpm} on #{rpm}.filename = #{erratum_package}.filename",
    "INNER JOIN #{repository_rpm} on #{repository_rpm}.rpm_id = #{rpm}.id").
    where("#{repository_rpm}.repository_id" => repo.id).
    where("#{repository_errata}.repository_id" => repo.id).
    group("#{errata}.id").count
end

.exportable(format: ::Katello::Pulp3::ContentViewVersion::Export::IMPORTABLE) ⇒ Object



193
194
195
# File 'app/models/katello/repository.rb', line 193

def self.exportable(format: ::Katello::Pulp3::ContentViewVersion::Export::IMPORTABLE)
  with_type(exportable_types(format: format))
end

.exportable_types(format: ::Katello::Pulp3::ContentViewVersion::Export::IMPORTABLE) ⇒ Object



188
189
190
191
# File 'app/models/katello/repository.rb', line 188

def self.exportable_types(format: ::Katello::Pulp3::ContentViewVersion::Export::IMPORTABLE)
  return [YUM_TYPE, FILE_TYPE] if format == ::Katello::Pulp3::ContentViewVersion::Export::SYNCABLE
  EXPORTABLE_TYPES
end

.feed_ca_cert(url) ⇒ Object



317
318
319
320
# File 'app/models/katello/repository.rb', line 317

def self.feed_ca_cert(url)
  file = feed_ca_file(url)
  File.read(file) if file
end

.feed_ca_file(url) ⇒ Object



322
323
324
# File 'app/models/katello/repository.rb', line 322

def self.feed_ca_file(url)
  ::Katello::Resources::CDN::CdnResource.ca_file if ::Katello::Resources::CDN::CdnResource.redhat_cdn?(url)
end

.for_products(products) ⇒ Object



201
202
203
# File 'app/models/katello/repository.rb', line 201

def self.for_products(products)
  joins(:root).where("#{Katello::RootRepository.table_name}.product_id" => products)
end

.import_distributionsObject



782
783
784
785
786
# File 'app/models/katello/repository.rb', line 782

def self.import_distributions
  self.all.each do |repo|
    repo.import_distribution_data
  end
end

.in_content_views(views) ⇒ Object



312
313
314
315
# File 'app/models/katello/repository.rb', line 312

def self.in_content_views(views)
  joins(:content_view_version)
    .where("#{Katello::ContentViewVersion.table_name}.content_view_id" => views.map(&:id))
end

.in_environment(env_id) ⇒ Object



304
305
306
# File 'app/models/katello/repository.rb', line 304

def self.in_environment(env_id)
  where(environment_id: env_id)
end

.in_organization(org) ⇒ Object



300
301
302
# File 'app/models/katello/repository.rb', line 300

def self.in_organization(org)
  where("#{Repository.table_name}.environment_id" => org.kt_environments.pluck("#{KTEnvironment.table_name}.id"))
end

.in_product(prod) ⇒ Object



308
309
310
# File 'app/models/katello/repository.rb', line 308

def self.in_product(prod)
  where(:root_id => RootRepository.where(product_id: prod))
end

.linked_repositoriesObject



900
901
902
903
904
905
906
# File 'app/models/katello/repository.rb', line 900

def self.linked_repositories
  to_return = []
  Katello::Repository.yum_type.in_non_default_view.find_each do |repo|
    to_return << repo if repo.link?
  end
  to_return
end

.repo_path_from_content_path(environment, content_path) ⇒ Object



205
206
207
208
209
# File 'app/models/katello/repository.rb', line 205

def self.repo_path_from_content_path(environment, content_path)
  path = content_path.sub(%r|^/|, '')
  path_prefix = [environment.organization.label, environment.label].join('/')
  "#{path_prefix}/#{path}"
end

.safe_render_container_name(repository, pattern = nil) ⇒ Object



933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
# File 'app/models/katello/repository.rb', line 933

def self.safe_render_container_name(repository, pattern = nil)
  #            pattern provided / env pattern provided
  #                 |  00 |  01 |  11 |  10
  # ----------------+-----+-----+-----+------
  # env exists /  00|   4 | n/a | n/a |   4
  # is cv default 01|   2 | n/a | n/a |   4
  #               11|   2 |   1 |   1 |   1
  #               10|   3 |   1 |   1 |   1
  #
  # This table shows the name to render given the properties of
  # the container provided. Branches numbered as ordered below.
  #
  # 1 - Render promotion pattern (or env pattern if no promo pattern)
  # 2 - <org label>/<product label>/<repo label>
  # 3 - <org label>/<env label>/<cv label>/<product label>/<repo label>
  # 4 - <org label>/<cv label>/<cvv label>/<product label>/<repo label>
  is_pattern_provided = pattern.present?
  env_exists = repository.environment.present?
  is_env_pattern_provided = env_exists && repository.environment.registry_name_pattern.present?
  is_cv_default = repository.content_view.default?

  if is_env_pattern_provided || (is_pattern_provided && env_exists)
    pattern ||= repository.environment.registry_name_pattern
    allowed_methods = {}
    allowed_vars = {}
    scope_variables = {
      repository: repository,
      organization: repository.organization,
      product: repository.product,
      lifecycle_environment: repository.environment,
      content_view: repository.content_view_version.content_view,
      content_view_version: repository.content_view_version,
    }
    box = Safemode::Box.new(repository, allowed_methods)
    erb = ERB.new(pattern)
    pattern = box.eval(erb.src, allowed_vars, scope_variables)
    return Repository.clean_container_name(pattern)
  elsif is_cv_default && !is_pattern_provided
    items = [repository.organization.label, repository.product.label, repository.label]
  elsif env_exists
    items = [repository.organization.label, repository.environment.label, repository.content_view.label, repository.product.label, repository.label]
  else
    items = [repository.organization.label, repository.content_view.label, repository.content_view_version.version, repository.product.label, repository.label]
  end
  Repository.clean_container_name(items.compact.join("/"))
end

.search_by_content_label(_key, operator, value) ⇒ Object



922
923
924
925
926
927
928
929
930
931
# File 'app/models/katello/repository.rb', line 922

def self.(_key, operator, value)
  conditions = sanitize_sql_for_conditions(["label #{operator} ?", value_to_sql(operator, value)])
  contents = Katello::Content.where(conditions).pluck(:cp_content_id)
  root_ids = Katello::RootRepository.where(:content_id => contents).pluck(:id)
  if root_ids.empty?
    { :conditions => "1=0" }
  else
    { :conditions => "#{Katello::Repository.table_name}.root_id IN (#{root_ids.join(',')})" }
  end
end

.search_by_redhat(_key, operator, value) ⇒ Object



908
909
910
911
912
913
914
915
916
917
918
919
920
# File 'app/models/katello/repository.rb', line 908

def self.search_by_redhat(_key, operator, value)
  value = value == 'true'
  value = !value if operator == '<>'

  product_ids = Katello::Product.redhat.select(:id)
  root_ids = Katello::RootRepository.where(:product_id => product_ids).pluck(:id)
  if product_ids.empty?
    {:conditions => "1=0"}
  else
    operator = value ? 'IN' : 'NOT IN'
    {:conditions => "#{Katello::Repository.table_name}.root_id #{operator} (#{root_ids.join(',')})"}
  end
end

.smart_proxy_syncableObject



742
743
744
745
746
# File 'app/models/katello/repository.rb', line 742

def self.smart_proxy_syncable
  joins(:content_view_version => :content_view).
    merge(ContentView.ignore_generated(include_library_generated: true)).
    where.not(environment_id: nil)
end

.synced_on_capsule(smart_proxy) ⇒ Object



638
639
640
# File 'app/models/katello/repository.rb', line 638

def self.synced_on_capsule(smart_proxy)
  smart_proxy.smart_proxy_sync_histories.map { |sph| sph.repository unless sph.finished_at.nil? }
end

.undisplayable_typesObject



296
297
298
# File 'app/models/katello/repository.rb', line 296

def self.undisplayable_types
  [::Katello::Repository::CANDLEPIN_DOCKER_TYPE]
end

.with_errata(errata) ⇒ Object



589
590
591
# File 'app/models/katello/repository.rb', line 589

def self.with_errata(errata)
  joins(:repository_errata).where("#{Katello::RepositoryErratum.table_name}.erratum_id" => errata)
end

.with_type(content_type) ⇒ Object



197
198
199
# File 'app/models/katello/repository.rb', line 197

def self.with_type(content_type)
  joins(:root).where("#{RootRepository.table_name}.content_type" => content_type)
end

Instance Method Details

#all_instancesObject



473
474
475
# File 'app/models/katello/repository.rb', line 473

def all_instances
  self.root.repositories
end

#archive?Boolean

Returns:

  • (Boolean)


331
332
333
# File 'app/models/katello/repository.rb', line 331

def archive?
  self.environment.nil?
end

#archived_instanceObject



716
717
718
719
720
721
722
723
724
# File 'app/models/katello/repository.rb', line 716

def archived_instance
  if self.environment_id.nil? || self.library_instance_id.nil?
    self
  elsif self.content_view.rolling?
    self.library_instance
  else
    self.content_view_version.archived_repos.where(:root_id => self.root_id).first
  end
end

#assert_deletableObject



854
855
856
# File 'app/models/katello/repository.rb', line 854

def assert_deletable
  throw :abort unless destroyable?
end

#audit_syncObject



251
252
253
# File 'app/models/katello/repository.rb', line 251

def audit_sync
  write_audit(action: AUDIT_SYNC_ACTION, comment: _('Successfully synchronized.'), audited_changes: {})
end

#backend_content_service(smart_proxy) ⇒ Object



231
232
233
# File 'app/models/katello/repository.rb', line 231

def backend_content_service(smart_proxy)
  backend_service(smart_proxy).content_service
end

#backend_content_unit_service(smart_proxy, content_unit_type) ⇒ Object



235
236
237
# File 'app/models/katello/repository.rb', line 235

def backend_content_unit_service(smart_proxy, content_unit_type)
  backend_service(smart_proxy).content_service(content_unit_type)
end

#backend_service(smart_proxy) ⇒ Object



225
226
227
228
229
# File 'app/models/katello/repository.rb', line 225

def backend_service(smart_proxy)
  fail('Pulp 3 not supported') unless smart_proxy.pulp3_support?(self)

  @service ||= Katello::Pulp3::Repository.instance_for_type(self, smart_proxy)
end

#blocking_taskObject



683
684
685
686
687
688
689
690
691
692
693
694
695
# File 'app/models/katello/repository.rb', line 683

def blocking_task
  blocking_task_labels = [
    ::Actions::Katello::Repository::Sync.name,
    ::Actions::Katello::Repository::UploadFiles.name,
    ::Actions::Katello::Repository::RemoveContent.name,
    ::Actions::Katello::Repository::MetadataGenerate.name,
  ]
  ForemanTasks::Task::DynflowTask.where(:label => blocking_task_labels)
                                 .where.not(state: 'stopped')
                                 .for_resource(self)
                                 .order(:started_at)
                                 .last
end

#build_clone(options) ⇒ Object

TODO: break up method



599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
# File 'app/models/katello/repository.rb', line 599

def build_clone(options)
  to_env       = options[:environment]
  version      = options[:version]
  content_view = options[:content_view] || to_env.default_content_view
  to_version   = version || content_view.version(to_env)

  fail _("Cannot clone into the Default Content View") if content_view.default?

  if to_env && version
    fail "Cannot clone into both an environment and a content view version archive"
  end

  if to_version.nil?
    fail _("View %{view} has not been promoted to %{env}") %
              {:view => content_view.name, :env => to_env.name}
  end

  if to_env && self.clones.in_content_views([content_view]).in_environment(to_env).any?
    fail _("Repository has already been cloned to %{cv_name} in environment %{to_env}") %
              {:to_env => to_env, :cv_name => content_view.name}
  end

  if self.yum?
    if self.library_instance?
      checksum_type = root.checksum_type
    else
      checksum_type = self.saved_checksum_type
    end
  end
  clone = Repository.new(:environment => to_env,
                 :library_instance => library_instance_or_self,
                 :root => self.root,
                 :content_view_version => to_version,
                 :saved_checksum_type => checksum_type)

  clone.relative_path = clone.docker? ? clone.generate_docker_repo_path : clone.generate_repo_path
  clone
end

#cancel_dynflow_syncObject



666
667
668
669
670
671
672
673
674
675
676
# File 'app/models/katello/repository.rb', line 666

def cancel_dynflow_sync
  if latest_dynflow_sync
    plan = latest_dynflow_sync.execution_plan

    plan.steps.each_pair do |_number, step|
      if step.cancellable? && step.is_a?(Dynflow::ExecutionPlan::Steps::RunStep)
        ::ForemanTasks.dynflow.world.event(plan.id, step.id, Dynflow::Action::Cancellable::Cancel)
      end
    end
  end
end

#check_ready_to_act!Object



697
698
699
700
701
702
703
704
705
706
707
708
# File 'app/models/katello/repository.rb', line 697

def check_ready_to_act!
  blocking_tasks = content_views&.map { |cv| cv.blocking_task }&.compact

  if blocking_tasks&.any?
    errored_tasks = blocking_tasks
                      .uniq
                      .map { |task| "- #{Setting['foreman_url']}/foreman_tasks/tasks/#{task&.id}" }
                      .join("\n")
    fail _("Repository #{self.label} has pending tasks in associated content views. Please wait for the tasks: " + errored_tasks +
           " to complete before proceeding.")
  end
end

#clear_smart_proxy_sync_histories(smart_proxy = nil) ⇒ Object



642
643
644
645
646
647
648
# File 'app/models/katello/repository.rb', line 642

def clear_smart_proxy_sync_histories(smart_proxy = nil)
  if smart_proxy
    self.smart_proxy_sync_histories.where(:smart_proxy_id => smart_proxy.id).try(:delete_all)
  else
    self.smart_proxy_sync_histories.delete_all
  end
end

#cloned_in?(env) ⇒ Boolean

is the repo cloned in the specified environment

Returns:

  • (Boolean)


498
499
500
# File 'app/models/katello/repository.rb', line 498

def cloned_in?(env)
  !get_clone(env).nil?
end

#clonesObject



469
470
471
# File 'app/models/katello/repository.rb', line 469

def clones
  self.root.repositories.where.not(:id => library_instance_id || id)
end

#component_source_repositoriesObject



894
895
896
897
898
# File 'app/models/katello/repository.rb', line 894

def component_source_repositories
  #find other copies of this repositories, in the CV version's components, that are in the 'archive'
  Katello::Repository.where(:content_view_version_id => self.content_view_version.components, :environment_id => nil,
                            :root_id => self.root_id)
end

#contentObject



217
218
219
# File 'app/models/katello/repository.rb', line 217

def content
  Katello::Content.find_by(:cp_content_id => self.content_id, :organization_id => self.product.organization_id)
end

#content_countsObject



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'app/models/katello/repository.rb', line 369

def content_counts
  content_counts = {}
  RepositoryTypeManager.defined_repository_types[content_type].content_types_to_index.each do |content_type|
    case content_type&.model_class::CONTENT_TYPE
    when DockerTag::CONTENT_TYPE
      content_counts[DockerTag::CONTENT_TYPE] = docker_tags.count
    when GenericContentUnit::CONTENT_TYPE
      content_counts[content_type.content_type] = content_type&.model_class&.in_repositories(self)&.where(:content_type => content_type.content_type)&.count
    else
      content_counts[content_type.label] = content_type&.model_class&.in_repositories(self)&.count
    end
  end

  content_counts['module_stream'] = content_counts.delete('modulemd') if content_counts.key?('modulemd')
  content_counts
end

#content_idObject



211
212
213
214
215
# File 'app/models/katello/repository.rb', line 211

def content_id
  # Currently deb content will store a content_id on each Repository, while all other content
  # types will store one on the RootRepository.
  self[:content_id] || root.content_id
end

#content_viewObject



278
279
280
# File 'app/models/katello/repository.rb', line 278

def content_view
  self.content_view_version.content_view
end

#content_view_environmentObject



282
283
284
# File 'app/models/katello/repository.rb', line 282

def content_view_environment
  self.content_view.content_view_environment(self.environment)
end

#content_views_all(include_composite: false) ⇒ Object



834
835
836
837
838
839
840
841
# File 'app/models/katello/repository.rb', line 834

def content_views_all(include_composite: false)
  if include_composite
    cv_ids = library_instances_inverse&.joins(:content_view_version)&.map { |cvv| cvv&.content_view&.id }
    return ContentView.where(id: cv_ids.uniq)
  else
    return self.content_views
  end
end

#copy_indexed_data(source_repository) ⇒ Object



1001
1002
1003
1004
1005
1006
# File 'app/models/katello/repository.rb', line 1001

def copy_indexed_data(source_repository)
  repository_type.content_types_to_index.each do |type|
    type.model_class.copy_repository_associations(source_repository, self)
    repository_type.index_additional_data_proc&.call(self, source_repository)
  end
end

#create_smart_proxy_sync_history(smart_proxy) ⇒ Object



650
651
652
653
654
655
656
657
658
659
660
# File 'app/models/katello/repository.rb', line 650

def create_smart_proxy_sync_history(smart_proxy)
  clear_smart_proxy_sync_histories(smart_proxy)
  sp_history_args = {
    :smart_proxy_id => smart_proxy.id,
    :repository_id => self.id,
    :started_at => Time.now,
  }
  sp_history = ::Katello::SmartProxySyncHistory.create sp_history_args
  sp_history.save!
  sp_history.id
end

#custom_docker_repo_pathObject



993
994
995
996
997
998
999
# File 'app/models/katello/repository.rb', line 993

def custom_docker_repo_path
  if [environment, product, root.label].any?(&:nil?)
    return nil # can't generate valid path
  end
  parts = [environment.organization.label, product.label, root.label]
  parts.map { |x| x.gsub(/[^-\w]/, "_") }.join("-").downcase
end

#custom_repo_pathObject



984
985
986
987
988
989
990
991
# File 'app/models/katello/repository.rb', line 984

def custom_repo_path
  return custom_docker_repo_path if docker?
  if [environment, product, root.label].any?(&:nil?)
    return nil # can't generate valid path
  end
  prefix = [environment.organization.label, environment.label].map { |x| x.gsub(/[^-\w]/, "_") }.join("/")
  prefix + root.custom_content_path
end

#deb_content_url_optionsObject



1047
1048
1049
1050
1051
1052
1053
1054
# File 'app/models/katello/repository.rb', line 1047

def deb_content_url_options
  return '' unless version_href

  backend_service = self.backend_service(SmartProxy.pulp_primary)
  components = backend_service.pulp_components.join(',')
  distributions = backend_service.pulp_distributions.join(',')
  "/?comp=#{components}&rel=#{distributions}"
end

#destroyable?(remove_from_content_view_versions = false) ⇒ Boolean

deleteable? is already taken by the authorization mixin

Returns:

  • (Boolean)


813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
# File 'app/models/katello/repository.rb', line 813

def destroyable?(remove_from_content_view_versions = false)
  if self.environment.try(:library?) && self.content_view.default?
    if self.environment.organization.being_deleted?
      return true
    elsif self.custom? && self.deletable?(remove_from_content_view_versions)
      return true
    elsif !self.custom? && self.redhat_deletable?(remove_from_content_view_versions)
      return true
    elsif Setting.find_by(name: 'delete_repo_across_cv')&.value
      return true
    else
      errors.add(:base, _("Repository cannot be deleted since it has already been included in a published Content View. " \
                          "Please delete all Content View versions containing this repository before attempting to delete it "\
                          "or use --remove-from-content-view-versions flag to automatically remove the repository from all published versions."))

      return false
    end
  end
  return true
end

#distribution_informationObject



802
803
804
805
806
807
808
809
810
# File 'app/models/katello/repository.rb', line 802

def distribution_information
  {
    distribution_version: self.distribution_version,
    distribution_arch: self.distribution_arch,
    distribution_family: self.distribution_family,
    distribution_variant: self.distribution_variant,
    distribution_bootable: self.distribution_bootable,
  }
end

#docker_meta_tag_countObject



858
859
860
# File 'app/models/katello/repository.rb', line 858

def docker_meta_tag_count
  DockerMetaTag.in_repositories(self.id).count
end

#dynflow_handled_last_sync?(pulp_task_id) ⇒ Boolean

Returns true if the pulp_task_id was triggered by the last synchronization action for the repository. Dynflow action handles the synchronization by it’s own so no need to synchronize it again in this callback. Since the callbacks are run just after synchronization is finished, it should be enough to check for the last synchronization task.

Returns:

  • (Boolean)


526
527
528
529
530
# File 'app/models/katello/repository.rb', line 526

def dynflow_handled_last_sync?(pulp_task_id)
  task = ForemanTasks::Task::DynflowTask.for_action(::Actions::Katello::Repository::Sync).
      for_resource(self).order(:started_at).last
  return task && task.main_action.pulp_task_id == pulp_task_id
end

#environmental_instances(view) ⇒ Object

returns other instances of this repo with the same library equivalent of repo



712
713
714
# File 'app/models/katello/repository.rb', line 712

def environmental_instances(view)
  self.all_instances.non_archived.in_content_views([view])
end

#errata_filenamesObject



593
594
595
596
# File 'app/models/katello/repository.rb', line 593

def errata_filenames
  Katello::ErratumPackage.joins(:erratum => :repository_errata).
      where("#{RepositoryErratum.table_name}.repository_id" => self.id).pluck("#{Katello::ErratumPackage.table_name}.filename")
end

#exist_for_environment?(environment, content_view, attribute = nil) ⇒ Boolean

Returns:

  • (Boolean)


748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
# File 'app/models/katello/repository.rb', line 748

def exist_for_environment?(environment, content_view, attribute = nil)
  if environment.present? && content_view.in_environment?(environment)
    repos = content_view.version(environment).repos(environment)

    repos.any? do |repo|
      not_self = (repo.id != self.id)
      same_product = (repo.product.id == self.product.id)

      repo_exists = same_product && not_self

      if repo_exists && attribute
        same_attribute = repo.send(attribute) == self.send(attribute)
        repo_exists = same_attribute
      end

      repo_exists
    end
  else
    false
  end
end

#fetch_module_errata_to_filterObject



434
435
436
437
438
439
440
441
442
443
# File 'app/models/katello/repository.rb', line 434

def fetch_module_errata_to_filter
  errata_counts = ::Katello::Repository.errata_with_module_stream_counts(self)
  errata_counts_in_library = ::Katello::Repository.errata_with_module_stream_counts(library_instance)
  if errata_counts_in_library.any?
    errata_counts_in_library.keep_if { |id| errata_counts[id] != errata_counts_in_library[id] }
    errata_counts_in_library.keys
  else
    []
  end
end

#fetch_package_errata_to_keepObject



423
424
425
426
427
428
429
430
431
432
# File 'app/models/katello/repository.rb', line 423

def fetch_package_errata_to_keep
  errata_counts = ::Katello::Repository.errata_with_package_counts(self)
  if errata_counts.any?
    errata_counts_in_library = ::Katello::Repository.errata_with_package_counts(library_instance)
    errata_counts.keep_if { |id| errata_counts[id] == errata_counts_in_library[id] }
    errata_counts.keys
  else
    []
  end
end

#full_gpg_key_path(smart_proxy = nil, force_http = false) ⇒ Object



358
359
360
361
362
363
# File 'app/models/katello/repository.rb', line 358

def full_gpg_key_path(smart_proxy = nil, force_http = false)
  return if self.root.gpg_key.try(:content).blank?
  pulp_uri = URI.parse(smart_proxy ? smart_proxy.url : ::SmartProxy.pulp_primary.url)
  scheme = force_http ? 'http' : 'https'
  "#{scheme}://#{pulp_uri.host.downcase}#{gpg_key_content_api_repository_url(self, :only_path => true)}"
end

#full_path(smart_proxy = nil, force_http = false) ⇒ Object



481
482
483
484
485
486
487
488
489
490
491
# File 'app/models/katello/repository.rb', line 481

def full_path(smart_proxy = nil, force_http = false)
  pulp_uri = URI.parse(smart_proxy ? smart_proxy.url : ::SmartProxy.pulp_primary.url)
  scheme = force_http ? 'http' : 'https'
  if docker?
    "#{pulp_uri.host.downcase}/#{container_repository_name}"
  elsif ansible_collection?
    "#{scheme}://#{pulp_uri.host.downcase}/pulp_ansible/galaxy/#{relative_path}/api/"
  else
    "#{scheme}://#{pulp_uri.host.downcase}/pulp/content/#{relative_path}/"
  end
end

#generate_content_pathObject



532
533
534
535
536
537
538
# File 'app/models/katello/repository.rb', line 532

def generate_content_path
  path = content.content_url
  root.substitutions.each do |key, value|
    path = path.gsub("$#{key}", value) if value
  end
  path
end

#generate_docker_repo_pathObject



556
557
558
559
560
561
562
563
564
565
566
567
568
# File 'app/models/katello/repository.rb', line 556

def generate_docker_repo_path
  org = self.organization.label.downcase
  if self.environment
    cve = ContentViewEnvironment.where(:environment_id => self.environment,
                                       :content_view_id => self.content_view).first
    view = self.content_view.label
    product = self.product.label
    env = cve.label.split('/').first
    "#{org}/#{env.downcase}/#{view}/#{product}/#{self.root.label}"
  else
    "#{org}/#{self.content_view.label}/#{self.content_view_version.version}/#{self.root.product.label}/#{self.root.label}"
  end
end

#generate_repo_path(content_path = nil) ⇒ Object



544
545
546
547
548
549
550
551
552
553
554
# File 'app/models/katello/repository.rb', line 544

def generate_repo_path(content_path = nil)
  _org, _content, content_path = library_instance_or_self.relative_path.split("/", 3) if content_path.blank?
  content_path = content_path.sub(%r|^/|, '')
  if self.environment
    cve = ContentViewEnvironment.where(:environment_id => self.environment,
                                       :content_view_id => self.content_view).first
    "#{organization.label}/#{cve.label}/#{content_path}"
  else
    "#{organization.label}/#{ContentView::CONTENT_DIR}/#{self.content_view.label}/#{self.content_view_version.version}/#{content_path}"
  end
end

#get_clone(env) ⇒ Object



510
511
512
513
514
515
516
517
518
519
# File 'app/models/katello/repository.rb', line 510

def get_clone(env)
  if self.content_view.default
    # this repo is part of a default content view
    Repository.in_environment(env).clones.
        joins(:content_view_version => :content_view).where("#{Katello::ContentView.table_name}.default" => true).first
  else
    # this repo is part of a content view that was published from a user created view
    self.content_view.get_repo_clone(env, self).first
  end
end

#groupObject



477
478
479
# File 'app/models/katello/repository.rb', line 477

def group
  all_instances
end

#immediate?Boolean

Returns:

  • (Boolean)


347
348
349
# File 'app/models/katello/repository.rb', line 347

def immediate?
  root.download_policy == ::Katello::RootRepository::DOWNLOAD_IMMEDIATE
end

#import_distribution_data(target_repo = nil) ⇒ Object



788
789
790
791
792
793
794
795
796
797
798
799
800
# File 'app/models/katello/repository.rb', line 788

def import_distribution_data(target_repo = nil)
  if target_repo
    self.update!(
      :distribution_version => target_repo.distribution_version,
      :distribution_arch => target_repo.distribution_arch,
      :distribution_family => target_repo.distribution_family,
      :distribution_variant => target_repo.distribution_variant,
      :distribution_bootable => target_repo.distribution_bootable
    )
  else
    self.backend_service(SmartProxy.pulp_primary).import_distribution_data
  end
end

#in_content_view?(content_view) ⇒ Boolean

Returns:

  • (Boolean)


1043
1044
1045
# File 'app/models/katello/repository.rb', line 1043

def in_content_view?(content_view)
  content_view.repositories.include? self
end

#in_default_view?Boolean

Returns:

  • (Boolean)


339
340
341
# File 'app/models/katello/repository.rb', line 339

def in_default_view?
  content_view_version&.default_content_view?
end

#index_content(options = {}) ⇒ Object



1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
# File 'app/models/katello/repository.rb', line 1016

def index_content(options = {})
  # set full_index to true if you want to force fetch all data from pulp
  # This is automatically done for library instance repos
  # However for non-library instance as in those belonging to a version
  # by default we fetch only ids and match them with the library instance
  # some times we want to force fetch all data even for non-library repos.
  # Use the full_index for those times

  full_index = options.fetch(:full_index, false)
  source_repository = options.fetch(:source_repository, nil)
  if self.yum? && !self.primary?
    index_linked_repo
  elsif source_repository && !repository_type.unique_content_per_repo
    copy_indexed_data(source_repository)
  else
    repository_type.content_types_to_index.each do |type|
      Katello::Logging.time("CONTENT_INDEX", data: {type: type.model_class}) do
        Katello::ContentUnitIndexer.new(content_type: type, repository: self, optimized: !full_index).import_all
      end
    end
    repository_type.index_additional_data_proc&.call(self)
  end
  self.update!(last_indexed: DateTime.now)

  true
end

#index_linked_repoObject



1008
1009
1010
1011
1012
1013
1014
# File 'app/models/katello/repository.rb', line 1008

def index_linked_repo
  if (base_repo = self.target_repository)
    copy_indexed_data(base_repo)
  else
    Rails.logger.error("Cannot index #{self.id}, no target repository found.")
  end
end

#latest_dynflow_syncObject



678
679
680
681
# File 'app/models/katello/repository.rb', line 678

def latest_dynflow_sync
  @latest_dynflow_sync ||= ForemanTasks::Task::DynflowTask.where(:label => ::Actions::Katello::Repository::Sync.name).
                            for_resource(self).order(:started_at).last
end

#latest_sync_auditObject



662
663
664
# File 'app/models/katello/repository.rb', line 662

def latest_sync_audit
  self.audits.where(:action => AUDIT_SYNC_ACTION).order(:created_at).last
end

#library_instance?Boolean

Returns:

  • (Boolean)


292
293
294
# File 'app/models/katello/repository.rb', line 292

def library_instance?
  self.content_view.default?
end

#library_instance_or_selfObject



540
541
542
# File 'app/models/katello/repository.rb', line 540

def library_instance_or_self
  self.library_instance || self
end

#link?Boolean

a link repository has no content in the pulp repository and serves as a shell. It will always be empty. Only the YumCloneDistributor can be used to publish yum metadata, and it cannot be indexed from pulp, but must have its indexed associations copied from another repository (its target).

Returns:

  • (Boolean)


874
875
876
# File 'app/models/katello/repository.rb', line 874

def link?
  !primary?
end

#module_streams_without_errataObject



578
579
580
581
582
583
584
585
586
587
# File 'app/models/katello/repository.rb', line 578

def module_streams_without_errata
  module_stream_errata = Katello::ModuleStreamErratumPackage.joins(:erratum_package => {:erratum => :repository_errata})
                          .where("#{RepositoryErratum.table_name}.repository_id" => self.id)
                          .pluck("#{Katello::ModuleStreamErratumPackage.table_name}.module_stream_id")
  if module_stream_errata.any?
    self.module_streams.where("#{ModuleStream.table_name}.id NOT in (?)", module_stream_errata)
  else
    self.module_streams
  end
end

#node_syncable?Boolean

Returns:

  • (Boolean)


738
739
740
# File 'app/models/katello/repository.rb', line 738

def node_syncable?
  environment
end

#on_demand?Boolean

Returns:

  • (Boolean)


343
344
345
# File 'app/models/katello/repository.rb', line 343

def on_demand?
  root.download_policy == ::Katello::RootRepository::DOWNLOAD_ON_DEMAND
end

#organizationObject



239
240
241
242
243
244
245
# File 'app/models/katello/repository.rb', line 239

def organization
  if self.environment
    self.environment.organization
  else
    self.content_view.organization
  end
end

#organization_idObject



247
248
249
# File 'app/models/katello/repository.rb', line 247

def organization_id
  organization&.id
end

#packages_without_errataObject



570
571
572
573
574
575
576
# File 'app/models/katello/repository.rb', line 570

def packages_without_errata
  if errata_filenames.any?
    self.rpms.where("#{Rpm.table_name}.filename NOT in (?)", errata_filenames)
  else
    self.rpms
  end
end

#partial_errataObject



445
446
447
448
449
450
451
452
453
454
455
456
# File 'app/models/katello/repository.rb', line 445

def partial_errata
  return [] if library_instance?

  partial_errata = self.errata
  errata_to_keep = fetch_package_errata_to_keep - fetch_module_errata_to_filter

  if errata_to_keep.any?
    partial_errata = self.errata.where("#{Katello::Erratum.table_name}.id NOT IN (?)", errata_to_keep)
  end

  partial_errata
end

#primary?Boolean

a primary repository actually has content (rpms, errata, etc) in the pulp repository. For these repositories, we can use the YumDistributor to generate metadata and can index the content from pulp, or for the case of content view archives without filters, can also use the YumCloneDistributor

Returns:

  • (Boolean)


865
866
867
868
869
870
# File 'app/models/katello/repository.rb', line 865

def primary?
  !self.yum? || # non-yum repos
      self.in_default_view? || # default content view repos
      (self.archive? && !self.content_view.composite) || # non-composite content view archive repos
      (self.archive? && self.content_view.composite? && self.component_source_repositories.count > 1) # composite archive repo with more than 1 source repository
end

#product_typeObject



365
366
367
# File 'app/models/katello/repository.rb', line 365

def product_type
  redhat? ? "redhat" : "custom"
end

#promoted?Boolean

Returns:

  • (Boolean)


502
503
504
505
506
507
508
# File 'app/models/katello/repository.rb', line 502

def promoted?
  if environment&.library?
    self.clones.any?
  else
    false
  end
end

#published_in_versionsObject



386
387
388
389
# File 'app/models/katello/repository.rb', line 386

def published_in_versions
  Katello::ContentViewVersion.with_repositories(self.library_instances_inverse)
                             .where(content_view_id: Katello::ContentView.ignore_generated).distinct
end

#rabl_pathObject



850
851
852
# File 'app/models/katello/repository.rb', line 850

def rabl_path
  "katello/api/v2/#{self.class.to_s.demodulize.tableize}/show"
end


734
735
736
# File 'app/models/katello/repository.rb', line 734

def related_resources
  self.product
end

#remove_partial_errata! {|found| ... } ⇒ Object

Yields:

  • (found)


458
459
460
461
462
463
# File 'app/models/katello/repository.rb', line 458

def remove_partial_errata!
  found = partial_errata.to_a
  yield(found) if block_given?
  self.repository_errata.where(:erratum_id => found.map(&:id)).delete_all
  found
end

#requires_yum_clone_distributor?Boolean

Returns:

  • (Boolean)


726
727
728
# File 'app/models/katello/repository.rb', line 726

def requires_yum_clone_distributor?
  self.yum? && self.environment_id && !self.in_default_view?
end

#set_container_repository_nameObject



274
275
276
# File 'app/models/katello/repository.rb', line 274

def set_container_repository_name
  self.container_repository_name = Repository.safe_render_container_name(self)
end

#set_pulp_idObject



255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'app/models/katello/repository.rb', line 255

def set_pulp_id
  return if self.pulp_id

  if self.content_view.default?
    items = [SecureRandom.uuid]
  elsif self.environment
    items = [organization.id, content_view.label, environment.label, library_instance.pulp_id]
  else
    version = self.content_view_version.version.gsub('.', '_')
    items = [organization.id, content_view.label, "v#{version}", library_instance.pulp_id]
  end
  self.pulp_id = items.join('-')
  self.pulp_id = SecureRandom.uuid if self.pulp_id.length > PULP_ID_MAX_LENGTH
end

#siblingsObject



465
466
467
# File 'app/models/katello/repository.rb', line 465

def siblings
  content_view_version.archived_repos.where.not(:id => id)
end

#skip_container_name?Boolean

Skip setting container name if the repository is not container type or if it’s a library instance of a container-push repo, indicating that the container name is set by the user.

Returns:

  • (Boolean)


288
289
290
# File 'app/models/katello/repository.rb', line 288

def skip_container_name?
  !self.root.docker? || (self.root.is_container_push && self.library_instance?)
end

#soft_copy_of_library?Boolean

Returns:

  • (Boolean)


326
327
328
329
# File 'app/models/katello/repository.rb', line 326

def soft_copy_of_library?
  return false if self.version_href.nil?
  self.version_href.starts_with?(self.library_instance.backend_service(SmartProxy.pulp_primary).repository_reference.repository_href)
end

#sync_hookObject



843
844
845
846
847
848
# File 'app/models/katello/repository.rb', line 843

def sync_hook
  run_callbacks :sync do
    logger.debug "custom hook after_sync on #{name} will be executed if defined."
    true
  end
end

#sync_statusObject



1056
1057
1058
# File 'app/models/katello/repository.rb', line 1056

def sync_status
  return latest_dynflow_sync
end

#target_repositoryObject

A link (empty repo) points to a target (a repository that actually has units in pulp). Target repos are always archive repos of a content view version (a repo with no environment) But for composite view versions, an archive repo, usually won’t be a primary (but might be if multple components contain the same repo)



880
881
882
883
884
885
886
887
888
889
890
891
892
# File 'app/models/katello/repository.rb', line 880

def target_repository
  fail _("This is not a linked repository") if primary?
  return nil if self.archived_instance.nil?

  #this is an environment repo, and the archived_instance is a primary (not always true with composite)
  if self.environment_id? && self.archived_instance.primary?
    self.archived_instance
  elsif self.environment_id #this is an environment repo, but a composite who's archived_instance isn't a primary
    self.archived_instance.target_repository || self.archived_instance #to archived_instance if nil
  else #must be a composite archive repo, with only one component repo
    self.component_source_repositories.first
  end
end

#to_hash(content_source = nil, force_http = false) ⇒ Object



493
494
495
# File 'app/models/katello/repository.rb', line 493

def to_hash(content_source = nil, force_http = false)
  {id: id, name: label, url: full_path(content_source, force_http)}
end

#to_labelObject



221
222
223
# File 'app/models/katello/repository.rb', line 221

def to_label
  name
end

#units_for_removal(ids, type_class = nil) ⇒ Object



770
771
772
773
774
775
776
777
778
779
780
# File 'app/models/katello/repository.rb', line 770

def units_for_removal(ids, type_class = nil)
  removable_unit_association = unit_type_for_removal(type_class)
  table_name = removable_unit_association.table_name
  is_integer = Integer(ids.first) rescue false #assume all ids are either integers or not

  if is_integer
    removable_unit_association.where("#{table_name}.id in (?)", ids)
  else
    removable_unit_association.where("#{table_name}.pulp_id in (?)", ids)
  end
end

#url?Boolean

Returns:

  • (Boolean)


730
731
732
# File 'app/models/katello/repository.rb', line 730

def url?
  root.url.present?
end

#using_mirrored_metadata?Boolean

Returns:

  • (Boolean)


335
336
337
# File 'app/models/katello/repository.rb', line 335

def using_mirrored_metadata?
  self.yum? && self.library_instance? && self.root.mirroring_policy == Katello::RootRepository::MIRRORING_POLICY_COMPLETE
end

#yum_gpg_key_urlObject



351
352
353
354
355
356
# File 'app/models/katello/repository.rb', line 351

def yum_gpg_key_url
  # if the repo has a gpg key return a url to access it
  if self.root.gpg_key.try(:content).present?
    "../..#{gpg_key_content_api_repository_url(self, :only_path => true)}"
  end
end