diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 9edd0cb76f4..ea468284289 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -31,7 +31,7 @@ jobs: angular: name: Angular ${{ matrix.engine }} - NodeJS ${{ matrix.node }} - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: diff --git a/.gitignore b/.gitignore index 63493844a8c..b418ed9d5b1 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ locale/*/*.po.time_stamp locale/.cache/* locale/*/*.pox locale/*/LC_MESSAGES +locale/action_names.rb .yardoc yardoc doc/apidoc* diff --git a/app/controllers/katello/api/registry/registry_proxies_controller.rb b/app/controllers/katello/api/registry/registry_proxies_controller.rb index f224f725e49..965ca134a8a 100644 --- a/app/controllers/katello/api/registry/registry_proxies_controller.rb +++ b/app/controllers/katello/api/registry/registry_proxies_controller.rb @@ -5,7 +5,7 @@ class Api::Registry::RegistryProxiesController < Api::V2::ApiController before_action :confirm_settings skip_before_action :authorize before_action :optional_authorize, only: [:token, :catalog] - before_action :registry_authorize, except: [:token, :v1_search, :catalog] + before_action :registry_authorize, except: [:token, :v1_search, :catalog, :static_index] before_action :authorize_repository_read, only: [:pull_manifest, :tags_list, :check_blob, :pull_blob] before_action :container_push_prop_validation, only: [:start_upload_blob, :upload_blob, :finish_upload_blob, :push_manifest] before_action :create_container_repo_if_needed, only: [:start_upload_blob, :upload_blob, :finish_upload_blob, :push_manifest] @@ -806,5 +806,25 @@ def render_podman_error(code, message, status = :bad_request) def item_not_found(item) render_podman_error("NAME_UNKNOWN", _("%s was not found!") % item, :not_found) end + + def static_index + host_ip = request.remote_ip + host = ::Host.joins(:primary_interface).where("nics.ip = :host_ip OR nics.ip6 = :host_ip", host_ip: host_ip)&.first + flatpak_index = (redirect_client { Resources::Registry::Proxy.get(@_request.fullpath, headers) }) + flatpak_index_json = JSON.parse(flatpak_index) + # Filter out repositories if it's a registered host + if host&.content_view_environments&.any? + # host.update(flatpak_index: flatpak_index) Will this help?? + repos = host.content_view_environments.flat_map do |cve| + cve.content_view_version.repositories + end + available_container_repo_names = repos.map(&:container_repository_name) + flatpak_index_json['Results'] = flatpak_index_json['Results'].select do |result| + available_container_repo_names.include?(result['Name']) + end + end + # Otherwise just return unfiltered pulp flatpak index + render json: flatpak_index_json + end end end diff --git a/app/controllers/katello/api/v2/content_uploads_controller.rb b/app/controllers/katello/api/v2/content_uploads_controller.rb index d28e457c7ce..024f43bca7f 100644 --- a/app/controllers/katello/api/v2/content_uploads_controller.rb +++ b/app/controllers/katello/api/v2/content_uploads_controller.rb @@ -12,9 +12,10 @@ class Api::V2::ContentUploadsController < Api::V2::ApiController param :repository_id, :number, :required => true, :desc => N_("repository id") param :size, :number, :required => true, :desc => N_("Size of file to upload") param :checksum, String, :required => false, :desc => N_("Checksum of file to upload") - param :content_type, RepositoryTypeManager.uploadable_content_types(false).map(&:label), :required => false, :desc => N_("content type ('deb', 'docker_manifest', 'file', 'ostree_ref', 'rpm', 'srpm')") + param :content_type, RepositoryTypeManager.uploadable_content_types(false).map(&:label), :required => false, :desc => N_("content type ('deb', 'file', 'ostree_ref', 'rpm', 'srpm')") def create fail Katello::Errors::InvalidRepositoryContent, _("Cannot upload Ansible collections.") if @repository.ansible_collection? + fail Katello::Errors::InvalidRepositoryContent, _("Cannot upload container content via Hammer/API. Use podman push instead.") if @repository.docker? content_type = params[:content_type] || ::Katello::RepositoryTypeManager.find(@repository.content_type)&.default_managed_content_type&.label RepositoryTypeManager.check_content_matches_repo_type!(@repository, content_type) if ::Katello::RepositoryTypeManager.generic_content_type?(content_type) diff --git a/app/controllers/katello/api/v2/content_view_filter_rules_controller.rb b/app/controllers/katello/api/v2/content_view_filter_rules_controller.rb index 0b61607da58..5054a94e332 100644 --- a/app/controllers/katello/api/v2/content_view_filter_rules_controller.rb +++ b/app/controllers/katello/api/v2/content_view_filter_rules_controller.rb @@ -40,6 +40,7 @@ def resource_class param :types, Array, :desc => N_("erratum: types (enhancement, bugfix, security)") param :date_type, String, :desc => N_("erratum: search using the 'Issued On' or 'Updated On' column of the errata. Values are 'issued'/'updated'") param :module_stream_ids, Array, :desc => N_("module stream ids") + param :allow_other_types, :bool, :desc => N_("erratum: allow types not matching a valid errata type") def create rule_clazz = ContentViewFilter.rule_class_for(@filter) @@ -89,6 +90,7 @@ def show param :start_date, String, :desc => N_("erratum: start date (YYYY-MM-DD)") param :end_date, String, :desc => N_("erratum: end date (YYYY-MM-DD)") param :types, Array, :desc => N_("erratum: types (enhancement, bugfix, security)") + param :allow_other_types, :bool, :desc => N_("erratum: allow types not matching a valid errata type") def update update_params = rule_params update_params[:name] = update_params[:name].first if update_params[:name] @@ -136,7 +138,7 @@ def rule_params @rule_params ||= params.fetch(:content_view_filter_rule, {}). permit(:uuid, :version, :min_version, :max_version, :architecture, - :errata_id, :start_date, :end_date, :date_type, + :errata_id, :start_date, :end_date, :date_type, :allow_other_types, :types => [], :module_stream_ids => [], :errata_ids => [], name: []) end diff --git a/app/controllers/katello/api/v2/content_views_controller.rb b/app/controllers/katello/api/v2/content_views_controller.rb index a182c1eaa48..197ab139c59 100644 --- a/app/controllers/katello/api/v2/content_views_controller.rb +++ b/app/controllers/katello/api/v2/content_views_controller.rb @@ -288,7 +288,10 @@ def view_params if (!@content_view || !@content_view.composite?) attrs.push({:repository_ids => []}, :repository_ids) end - params.require(:content_view).permit(*attrs).to_h + result = params.require(:content_view).permit(*attrs).to_h + # sanitize repository_ids to be a list of integers + result[:repository_ids] = result[:repository_ids].compact.map(&:to_i) if result[:repository_ids].present? + result end def find_environment diff --git a/app/controllers/katello/api/v2/environments_controller.rb b/app/controllers/katello/api/v2/environments_controller.rb index 764a4aa5810..a0e70be7067 100644 --- a/app/controllers/katello/api/v2/environments_controller.rb +++ b/app/controllers/katello/api/v2/environments_controller.rb @@ -84,6 +84,10 @@ def show ID of an environment that is prior to the new environment in the chain. It has to be either the ID of Library or the ID of an environment at the end of a chain. DESC + param :path_id, Integer, :desc => <<-DESC + If you are adding an environment to an existing path after Library, pass the ID of the environment that is the current successor of Library in the path. + It has to be the id of the old environment following library in this path. + DESC def create create_params = environment_params create_params[:label] = labelize_params(create_params) diff --git a/app/controllers/katello/api/v2/errata_controller.rb b/app/controllers/katello/api/v2/errata_controller.rb index d8040aea0b8..57f113c4182 100644 --- a/app/controllers/katello/api/v2/errata_controller.rb +++ b/app/controllers/katello/api/v2/errata_controller.rb @@ -59,9 +59,20 @@ def custom_index_relation(collection) fail HttpErrors::UnprocessableEntity, msg end + custom_index_relation_handle_type_and_time(collection) + end + + def custom_index_relation_handle_type_and_time(collection) collection = collection.where("#{date_type} >= ?", params[:start_date]) if params[:start_date] collection = collection.where("#{date_type} <= ?", params[:end_date]) if params[:end_date] - collection = collection.of_type(params[:types]) if params[:types] + if params[:types] + include_other = params[:types]&.include?('other') + params[:types]&.delete('other') + collection = collection.of_type( + params[:types], + include_other + ) + end collection end diff --git a/app/controllers/katello/api/v2/host_bootc_images_controller.rb b/app/controllers/katello/api/v2/host_bootc_images_controller.rb new file mode 100644 index 00000000000..d3a11566502 --- /dev/null +++ b/app/controllers/katello/api/v2/host_bootc_images_controller.rb @@ -0,0 +1,71 @@ +module Katello + class Api::V2::HostBootcImagesController < Api::V2::ApiController + include Katello::Concerns::FilteredAutoCompleteSearch + + resource_description do + api_version 'v2' + api_base_url "/api" + end + + api :GET, "/hosts/bootc_images", N_("List booted bootc container images for hosts") + param_group :search, Api::V2::ApiController + def bootc_images + params[:sort_by] ||= 'bootc_booted_image' + params[:sort_order] ||= 'asc' + if params[:order] + params[:order] = "#{params[:order].split(' ')[0]} #{sanitize_sort_order(params[:order].split(' ')[1])}" + else + params[:order] = "#{params[:sort_by]} #{sanitize_sort_order(params[:sort_order])}" + end + per_page = params[:per_page].present? ? params[:per_page].to_i : Setting[:entries_per_page] + page = params[:page].present? ? params[:page].to_i : 1 + + bootc_image_map = bootc_host_image_map + paged_images = bootc_image_map.to_a.paginate(page: page, per_page: per_page) + results = paged_images.collect { |image| { bootc_booted_image: image[0], digests: image[1] } } + render json: { + total: bootc_image_map.size, + page: page, + per_page: per_page, + subtotal: bootc_image_map.size, + sort: { + by: params[:sort_by], + order: params[:sort_order], + }, + results: results, + } + end + + private + + def sanitize_sort_order(sort_order) + if sort_order.present? && ['asc', 'desc'].include?(sort_order.downcase) + sort_order.downcase + else + 'asc' + end + end + + def index_relation + query = resource_class.authorized(:view_hosts).distinct + query.joins(:content_facet).where.not(bootc_booted_image: nil, bootc_booted_digest: nil) + query + end + + def resource_class + ::Host::Managed + end + + def bootc_host_image_map + content_facets = ::Katello::Host::ContentFacet.where(host_id: ::Host::Managed.joins(:content_facet).search_for(params[:search]).pluck(:id)) + aggregate_bootc_data = content_facets.where.not(bootc_booted_image: nil, bootc_booted_digest: nil). + select(:bootc_booted_image, :bootc_booted_digest, 'COUNT(hosts.id) as host_count'). + joins(:host).group(:bootc_booted_image, :bootc_booted_digest).order(params[:order]) + bootc_image_map = Hash.new { |h, k| h[k] = [] } + aggregate_bootc_data.each do |host_image| + bootc_image_map[host_image.bootc_booted_image] << { bootc_booted_digest: host_image.bootc_booted_digest, host_count: host_image.host_count.to_i } + end + bootc_image_map + end + end +end diff --git a/app/controllers/katello/api/v2/host_subscriptions_controller.rb b/app/controllers/katello/api/v2/host_subscriptions_controller.rb index 865dac810e1..04400d68afa 100644 --- a/app/controllers/katello/api/v2/host_subscriptions_controller.rb +++ b/app/controllers/katello/api/v2/host_subscriptions_controller.rb @@ -184,7 +184,7 @@ def content_override validate_content_overrides_enabled(override_params) end sync_task(::Actions::Katello::Host::UpdateContentOverrides, @host, content_override_values, false) - fetch_product_content + fetch_product_content(!params.dig(:content_overrides_search, :search).nil? && Foreman::Cast.to_bool(params.dig(:content_overrides_search, :limit_to_env))) end api :GET, "/hosts/:host_id/subscriptions/available_release_versions", N_("Show releases available for the content host") @@ -203,8 +203,8 @@ def enabled_repositories private - def fetch_product_content - content_finder = ProductContentFinder.new(:consumable => @host.subscription_facet) + def fetch_product_content(limit_to_env = false) + content_finder = ProductContentFinder.new(:match_environment => limit_to_env, :consumable => @host.subscription_facet) content = content_finder.presenter_with_overrides(@host.subscription_facet.candlepin_consumer.content_overrides) respond_with_template_collection("index", 'repository_sets', :collection => full_result_response(content)) end diff --git a/app/controllers/katello/concerns/api/v2/http_proxies_controller_extensions.rb b/app/controllers/katello/concerns/api/v2/http_proxies_controller_extensions.rb index 2d2f8c5baca..2839a6a82f9 100644 --- a/app/controllers/katello/concerns/api/v2/http_proxies_controller_extensions.rb +++ b/app/controllers/katello/concerns/api/v2/http_proxies_controller_extensions.rb @@ -5,9 +5,9 @@ module V2 module HttpProxiesControllerExtensions extend ::Apipie::DSL::Concern - update_api(:create) do + update_api(:create, :show) do param :http_proxy, Hash do - param :default_content_proxy, :bool, :required => false, :desc => N_('Set this HTTP proxy as the default content HTTP proxy') + param :content_default_http_proxy, :bool, :required => false, :desc => N_('Set this HTTP proxy as the default content HTTP proxy') end end end diff --git a/app/controllers/katello/concerns/http_proxies_controller_extensions.rb b/app/controllers/katello/concerns/http_proxies_controller_extensions.rb index 303a9e11c8e..00049d9282c 100644 --- a/app/controllers/katello/concerns/http_proxies_controller_extensions.rb +++ b/app/controllers/katello/concerns/http_proxies_controller_extensions.rb @@ -11,7 +11,7 @@ module HttpProxiesControllerExtensions def update_content_default_http_proxy return unless @http_proxy.persisted? - return unless ActiveRecord::Type::Boolean.new.deserialize(params.dig('http_proxy', 'default_content')) + return unless ActiveRecord::Type::Boolean.new.deserialize(params.dig('http_proxy', 'content_default_http_proxy')) Setting[:content_default_http_proxy] = @http_proxy.name end diff --git a/app/lib/actions/katello/content_view_environment/reassign_objects.rb b/app/lib/actions/katello/content_view_environment/reassign_objects.rb index ac903337a0e..05ad9ab1350 100644 --- a/app/lib/actions/katello/content_view_environment/reassign_objects.rb +++ b/app/lib/actions/katello/content_view_environment/reassign_objects.rb @@ -14,7 +14,11 @@ def plan(content_view_environment, options) end content_view_environment.activation_keys.each do |key| - plan_action(ActivationKey::Reassign, key, options[:key_content_view_id], options[:key_environment_id]) + if key.multi_content_view_environment? + key.content_view_environments = key.content_view_environments - [content_view_environment] + else + plan_action(ActivationKey::Reassign, key, options[:key_content_view_id], options[:key_environment_id]) + end end end end diff --git a/app/lib/katello/validators/content_view_erratum_filter_rule_validator.rb b/app/lib/katello/validators/content_view_erratum_filter_rule_validator.rb index 3eee2a8f252..7b512488c6d 100644 --- a/app/lib/katello/validators/content_view_erratum_filter_rule_validator.rb +++ b/app/lib/katello/validators/content_view_erratum_filter_rule_validator.rb @@ -2,9 +2,9 @@ module Katello module Validators class ContentViewErratumFilterRuleValidator < ActiveModel::Validator def validate(record) - if record.errata_id.blank? && record.start_date.blank? && record.end_date.blank? && record.types.blank? + if record.errata_id.blank? && record.start_date.blank? && record.end_date.blank? && record.types.blank? && record.allow_other_types == false invalid_parameters = _("Invalid erratum filter rule specified, Must specify at least one of the following:" \ - " 'errata_id', 'start_date', 'end_date' or 'types'") + " 'errata_id', 'start_date', 'end_date', 'types', or 'allow_other_types'") record.errors.add(:base, invalid_parameters) return end diff --git a/app/models/katello/activation_key.rb b/app/models/katello/activation_key.rb index 571f2e57b2d..4666df4d71d 100644 --- a/app/models/katello/activation_key.rb +++ b/app/models/katello/activation_key.rb @@ -92,7 +92,7 @@ def self.in_environments(envs) def content_view_environments=(new_cves) if new_cves.length > 1 && !Setting['allow_multiple_content_views'] fail ::Katello::Errors::MultiEnvironmentNotSupportedError, - _("Assigning an activation key to multiple content view environments is not enabled.") + _("Assigning an activation key to multiple content view environments is not enabled. To enable, set the allow_multiple_content_views setting.") end super(new_cves) Katello::ContentViewEnvironmentActivationKey.reprioritize_for_activation_key(self, new_cves) diff --git a/app/models/katello/concerns/http_proxy_extensions.rb b/app/models/katello/concerns/http_proxy_extensions.rb index ad2ef8d9aa7..d12940d0ec3 100644 --- a/app/models/katello/concerns/http_proxy_extensions.rb +++ b/app/models/katello/concerns/http_proxy_extensions.rb @@ -84,6 +84,10 @@ def name_and_url uri.user = nil "#{name} (#{uri})" end + + def content_default_http_proxy? + Setting[:content_default_http_proxy] == name + end end end end diff --git a/app/models/katello/concerns/smart_proxy_extensions.rb b/app/models/katello/concerns/smart_proxy_extensions.rb index 3761f4110e6..abbbc998191 100644 --- a/app/models/katello/concerns/smart_proxy_extensions.rb +++ b/app/models/katello/concerns/smart_proxy_extensions.rb @@ -33,6 +33,7 @@ def refresh before_create :associate_default_locations before_create :associate_lifecycle_environments before_validation :set_default_download_policy + after_update :refresh_smart_proxy_sync_histories lazy_accessor :pulp_repositories, :initializer => lambda { |_s| pulp_node.extensions.repository.retrieve_all } @@ -471,6 +472,9 @@ def add_lifecycle_environment(environment) end def remove_lifecycle_environment(environment) + smart_proxy_helper = ::Katello::SmartProxyHelper.new(self) + repos = smart_proxy_helper.repositories_available_to_capsule(environment) + smart_proxy_helper.clear_smart_proxy_sync_histories(repos) unless repos.empty? self.lifecycle_environments.find(environment.id) unless self.lifecycle_environments.destroy(environment) fail _("Could not remove the lifecycle environment from the smart proxy") @@ -479,6 +483,16 @@ def remove_lifecycle_environment(environment) raise _("Lifecycle environment was not attached to the smart proxy; therefore, no changes were made.") end + def refresh_smart_proxy_sync_histories + smart_proxy_helper = ::Katello::SmartProxyHelper.new(self) + repos = smart_proxy_helper.repositories_available_to_capsule.select(:id) + if repos.size == 0 + self.smart_proxy_sync_histories.delete_all + else + self.smart_proxy_sync_histories.where.not(repository_id: repos).delete_all + end + end + def available_lifecycle_environments(organization_id = nil) scope = Katello::KTEnvironment.not_in_capsule(self) scope = scope.where(organization_id: organization_id) if organization_id diff --git a/app/models/katello/content_view_erratum_filter.rb b/app/models/katello/content_view_erratum_filter.rb index ee8d9f98103..a6e39a65c19 100644 --- a/app/models/katello/content_view_erratum_filter.rb +++ b/app/models/katello/content_view_erratum_filter.rb @@ -92,9 +92,21 @@ def erratum_arel end def types_clause + # Create an array to store output clauses for quick type filtering later + conditions = [] + + # Add clauses for types in the filter types = erratum_rules.first.types - return if types.blank? - errata_types_in(types) + conditions << errata_types_in(types) unless types.blank? + + # Add clauses for 'other' types + conditions << errata_types_not_in(Erratum::TYPES) if erratum_rules.first.allow_other_types? + + # Reduce the array of clauses to a single clause and return + return if conditions.empty? + conditions.reduce(nil) do |combined_clause, condition| + combined_clause ? combined_clause.or(condition) : condition + end end def filter_by_id? @@ -105,6 +117,10 @@ def errata_types_in(types) erratum_arel[:errata_type].in(types) end + def errata_types_not_in(types) + erratum_arel[:errata_type].not_in(types) + end + def errata_in(ids) erratum_arel[:errata_id].in(ids) end diff --git a/app/models/katello/erratum.rb b/app/models/katello/erratum.rb index b68062ee1cd..9a6b3893d51 100644 --- a/app/models/katello/erratum.rb +++ b/app/models/katello/erratum.rb @@ -48,8 +48,14 @@ class Erratum < Katello::Model :validator => ->(value) { ['true', 'false'].include?(value.downcase) }, :operators => ["="] - def self.of_type(type) - where(:errata_type => type) + def self.of_type(type, include_other = false) + if include_other + where.not( + :errata_type => [Erratum::SECURITY, Erratum::BUGZILLA, Erratum::ENHANCEMENT].flatten + ).or(where(:errata_type => type)) + else + where(:errata_type => type) + end end scope :security, -> { of_type(Erratum::SECURITY) } diff --git a/app/models/katello/host/content_facet.rb b/app/models/katello/host/content_facet.rb index ae25d2fd1e9..353c010c2a7 100644 --- a/app/models/katello/host/content_facet.rb +++ b/app/models/katello/host/content_facet.rb @@ -59,7 +59,7 @@ class ContentFacet < Katello::Model validates_associated :content_view_environment_content_facets, :message => _("invalid: The content source must sync the lifecycle environment assigned to the host. See the logs for more information.") validates :host, :presence => true, :allow_blank => false validates :bootc_booted_digest, :bootc_available_digest, :bootc_staged_digest, :bootc_rollback_digest, - format: { with: /\Asha256:[A-Fa-f0-9]{64}\z/, message: "must be a valid sha256 digest", allow_nil: true } + format: { with: /\Asha256:[A-Fa-f0-9]{64}\z/, message: "must be a valid sha256 digest", allow_blank: true } scope :with_environments, ->(lifecycle_environments) do joins(:content_view_environment_content_facets => :content_view_environment). @@ -136,7 +136,7 @@ def single_lifecycle_environment def content_view_environments=(new_cves) if new_cves.length > 1 && !Setting['allow_multiple_content_views'] fail ::Katello::Errors::MultiEnvironmentNotSupportedError, - _("Assigning a host to multiple content view environments is not enabled.") + _("Assigning a host to multiple content view environments is not enabled. To enable, set the allow_multiple_content_views setting.") end super(new_cves) Katello::ContentViewEnvironmentContentFacet.reprioritize_for_content_facet(self, new_cves) diff --git a/app/models/katello/repository.rb b/app/models/katello/repository.rb index 3abccdeb136..f1daefb7681 100644 --- a/app/models/katello/repository.rb +++ b/app/models/katello/repository.rb @@ -1059,10 +1059,15 @@ def deb_pulp_components(version_href = self.version_href) pulp_api.list({:repository_version => version_href}).results.map { |x| x.component }.uniq end + def deb_sanitize_pulp_distribution(distribution) + return "flat-repo" if distribution&.end_with?("/") + distribution + end + def deb_pulp_distributions(version_href = self.version_href) return [] if version_href.blank? pulp_api = Katello::Pulp3::Repository.instance_for_type(self, SmartProxy.pulp_primary).api.content_release_components_api - pulp_api.list({:repository_version => version_href}).results.map { |x| x.distribution }.uniq + pulp_api.list({:repository_version => version_href}).results.map { |x| deb_sanitize_pulp_distribution(x.distribution) }.uniq end def sync_status diff --git a/app/services/katello/pulp3/repository/apt.rb b/app/services/katello/pulp3/repository/apt.rb index 2673e5209a0..9a5ded6c651 100644 --- a/app/services/katello/pulp3/repository/apt.rb +++ b/app/services/katello/pulp3/repository/apt.rb @@ -226,23 +226,6 @@ def copy_content_from_mapping(repo_id_map, _options = {}) multi_copy_units(repo_id_map, dependency_solving) end - def copy_units(content_unit_hrefs, remove_all) - remove_all = true if remove_all.nil? - tasks = [] - - if content_unit_hrefs.sort!.any? - first_slice = remove_all - content_unit_hrefs.each_slice(UNIT_LIMIT) do |slice| - tasks << add_content(slice, first_slice) - first_slice = false - end - # If we're merging composite cv repositories, don't clear out the Pulp repository. - elsif remove_all - tasks << remove_all_content - end - tasks - end - def copy_content_for_source(source_repository, options = {}) # copy_units_by_href(source_repository.debs.pluck(:pulp_id)) filters = ContentViewDebFilter.where(:id => options[:filter_ids]) @@ -261,7 +244,22 @@ def copy_content_for_source(source_repository, options = {}) content_unit_hrefs = whitelist_ids - blacklist_ids - copy_units(content_unit_hrefs.uniq, options[:remove_all]) + pulp_deb_copy_serializer = PulpDebClient::Copy.new + pulp_deb_copy_serializer.dependency_solving = false + pulp_deb_copy_serializer.config = [{ + source_repo_version: source_repository.version_href, + dest_repo: repository_reference.repository_href, + content: content_unit_hrefs, + }] + + remove_all = options[:remove_all] + remove_all = true if remove_all.nil? + + if remove_all + remove_all_content_from_repo(repository_reference.repository_href) + end + + copy_content_chunked(pulp_deb_copy_serializer) end def regenerate_applicability diff --git a/app/views/foreman/job_templates/bootc_action.erb b/app/views/foreman/job_templates/bootc_action.erb new file mode 100644 index 00000000000..18007b0a3ee --- /dev/null +++ b/app/views/foreman/job_templates/bootc_action.erb @@ -0,0 +1,26 @@ +<%# +kind: job_template +name: Bootc Action - Script Default +model: JobTemplate +job_category: Bootc +description_format: 'bootc %{action} %{options} %{target}' +provider_type: script +feature: katello_bootc_action +template_inputs: +- name: action + description: 'The bootc action: upgrade, switch, rollback or status' + input_type: user + options: "upgrade\nswitch\nrollback\nstatus" + required: true +- name: options + description: Additional options for bootc action + input_type: user + required: false +- name: target + description: Target for bootc switch action + input_type: user + required: false +%> + +bootc <%= input('action') %> <%= input('options') %> <%= input('target') %> +subscription-manager facts --update diff --git a/app/views/foreman/job_templates/bootc_rollback.erb b/app/views/foreman/job_templates/bootc_rollback.erb new file mode 100644 index 00000000000..0ba6ea8332c --- /dev/null +++ b/app/views/foreman/job_templates/bootc_rollback.erb @@ -0,0 +1,13 @@ +<%# +kind: job_template +name: Bootc Rollback - Script Default +job_category: Bootc +description_format: 'bootc rollback' +feature: katello_bootc_rollback +provider_type: script +foreign_input_sets: +- template: Bootc Action - Script Default + exclude: action, options, target +%> + +<%= render_template('Bootc Action - Script Default', :action => 'rollback') %> diff --git a/app/views/foreman/job_templates/bootc_status.erb b/app/views/foreman/job_templates/bootc_status.erb new file mode 100644 index 00000000000..7a1204ad7cd --- /dev/null +++ b/app/views/foreman/job_templates/bootc_status.erb @@ -0,0 +1,13 @@ +<%# +kind: job_template +name: Bootc Status - Script Default +job_category: Bootc +description_format: 'bootc status %{options}' +feature: katello_bootc_status +provider_type: script +foreign_input_sets: +- template: Bootc Action - Script Default + exclude: action, target +%> + +<%= render_template('Bootc Action - Script Default', :action => 'status') %> diff --git a/app/views/foreman/job_templates/bootc_switch.erb b/app/views/foreman/job_templates/bootc_switch.erb new file mode 100644 index 00000000000..b10d1739f66 --- /dev/null +++ b/app/views/foreman/job_templates/bootc_switch.erb @@ -0,0 +1,13 @@ +<%# +kind: job_template +name: Bootc Switch - Script Default +job_category: Bootc +description_format: 'bootc switch %{options} %{target}' +feature: katello_bootc_switch +provider_type: script +foreign_input_sets: +- template: Bootc Action - Script Default + exclude: action +%> + +<%= render_template('Bootc Action - Script Default', :action => 'switch') %> diff --git a/app/views/foreman/job_templates/bootc_upgrade.erb b/app/views/foreman/job_templates/bootc_upgrade.erb new file mode 100644 index 00000000000..fc7be23ce8c --- /dev/null +++ b/app/views/foreman/job_templates/bootc_upgrade.erb @@ -0,0 +1,13 @@ +<%# +kind: job_template +name: Bootc Upgrade - Script Default +job_category: Bootc +description_format: 'bootc upgrade %{options}' +feature: katello_bootc_upgrade +provider_type: script +foreign_input_sets: +- template: Bootc Action - Script Default + exclude: action, target +%> + +<%= render_template('Bootc Action - Script Default', :action => 'upgrade') %> diff --git a/app/views/foreman/job_templates/flatpak_install.erb b/app/views/foreman/job_templates/flatpak_install.erb new file mode 100644 index 00000000000..f461ce663d2 --- /dev/null +++ b/app/views/foreman/job_templates/flatpak_install.erb @@ -0,0 +1,23 @@ +<%# +kind: job_template +name: Install Flatpak application on host +job_category: Katello +description_format: 'Install Flatpak application %{Application name} on host' +provider_type: script +template_inputs: +- name: Flatpak remote name + description: Name of remote to use on host + input_type: user + required: false +- name: Application name + description: Name of the application to install + input_type: user + required: true +%> + +<% + remote_name = input('Flatpak remote name') + app_name = input('Application name') +%> + +sudo dbus-launch flatpak install <%= remote_name %> <%= app_name %> --assumeyes \ No newline at end of file diff --git a/app/views/foreman/job_templates/flatpak_login_action.erb b/app/views/foreman/job_templates/flatpak_login_action.erb new file mode 100644 index 00000000000..407b52d25db --- /dev/null +++ b/app/views/foreman/job_templates/flatpak_login_action.erb @@ -0,0 +1,30 @@ +<%# +kind: job_template +name: Login to flatpak registry via podman +job_category: Katello +description_format: 'Login to flatpak registry via podman' +provider_type: script +template_inputs: +- name: Flatpak registry URL + description: URL of server/capsule + input_type: user + required: true +- name: Username + description: Username for container registry login + input_type: user + required: true +- name: Password + description: Password/Access token for container registry login + input_type: user + required: true + hidden_value: true +%> + +<% + server_url = input('Flatpak registry URL') + username = input('Username') + password = input('Password') +%> + +sudo podman login <%= server_url %> --username <%= username %> --password <%= password %> +sudo cp /run/containers/0/auth.json /etc/flatpak/oci-auth.json \ No newline at end of file diff --git a/app/views/foreman/job_templates/flatpak_setup.erb b/app/views/foreman/job_templates/flatpak_setup.erb new file mode 100644 index 00000000000..d4d5d9deaa1 --- /dev/null +++ b/app/views/foreman/job_templates/flatpak_setup.erb @@ -0,0 +1,27 @@ +<%# +kind: job_template +name: Set up Flatpak remote on host +job_category: Katello +description_format: 'Set up Flatpak remote on host' +provider_type: script +template_inputs: +- name: Remote Name + description: Remote name for Flatpak + input_type: user + required: true +- name: Flatpak registry URL + description: URL of server/capsule + input_type: user + required: true +foreign_input_sets: +- template: Login to flatpak registry via podman + exclude: Flatpak registry URL +%> + +<% + remote_name = input('Remote Name') + registry_url = input('Flatpak registry URL') +%> + +sudo flatpak remote-add --authenticator-name=org.flatpak.Authenticator.Oci <%= remote_name %> oci+<%= registry_url %>/ +<%= render_template('Login to flatpak registry via podman', 'Flatpak registry URL': registry_url) %> \ No newline at end of file diff --git a/app/views/foreman/job_templates/update_packages_by_search_query_-_katello_ansible_default.erb b/app/views/foreman/job_templates/update_packages_by_search_query_-_katello_ansible_default.erb index 855b1c4b270..0cd69d31ef3 100644 --- a/app/views/foreman/job_templates/update_packages_by_search_query_-_katello_ansible_default.erb +++ b/app/views/foreman/job_templates/update_packages_by_search_query_-_katello_ansible_default.erb @@ -22,7 +22,7 @@ template_inputs: versions: input('Selected update versions') ) -%> <% if package_names.empty? -%> -<%= render_template('Package Action - Ansible Default', :state => 'latest', :name => '"*"') %> +<%= render_template('Package Action - Ansible Default', :state => 'latest', :name => '*') %> <% else -%> --- - hosts: all diff --git a/app/views/katello/api/v2/content_view_filter_rules/show.json.rabl b/app/views/katello/api/v2/content_view_filter_rules/show.json.rabl index 38c1b04a2b1..d7024c206e7 100644 --- a/app/views/katello/api/v2/content_view_filter_rules/show.json.rabl +++ b/app/views/katello/api/v2/content_view_filter_rules/show.json.rabl @@ -13,6 +13,7 @@ attributes :start_date, :if => lambda { |rule| rule.respond_to?(:start_date) && attributes :end_date, :if => lambda { |rule| rule.respond_to?(:end_date) && !rule.end_date.blank? } attributes :architecture, :if => lambda { |rule| rule.respond_to?(:architecture) && !rule.architecture.blank? } attributes :types, :if => lambda { |rule| rule.respond_to?(:types) && !rule.types.blank? } +attributes :allow_other_types, :if => lambda { |rule| rule.respond_to?(:allow_other_types) } attributes :date_type, :if => lambda { |rule| rule.respond_to?(:date_type) } attributes :module_stream_id, :if => lambda { |rule| rule.respond_to?(:module_stream_id) && !rule.module_stream_id.blank? } if @resource&.try(:module_stream) diff --git a/app/views/katello/api/v2/flatpak_remotes/base.json.rabl b/app/views/katello/api/v2/flatpak_remotes/base.json.rabl index 95075ae85fa..425b06b772d 100644 --- a/app/views/katello/api/v2/flatpak_remotes/base.json.rabl +++ b/app/views/katello/api/v2/flatpak_remotes/base.json.rabl @@ -2,4 +2,4 @@ extends 'katello/api/v2/common/identifier' extends 'katello/api/v2/common/org_reference' attributes :name -attributes :url, :description, :username, :token, :seeded, :registry_url +attributes :url, :description, :username, :seeded, :registry_url diff --git a/app/views/katello/api/v2/hosts/base.json.rabl b/app/views/katello/api/v2/hosts/base.json.rabl index 4bdf894928d..21326cbea0d 100644 --- a/app/views/katello/api/v2/hosts/base.json.rabl +++ b/app/views/katello/api/v2/hosts/base.json.rabl @@ -5,14 +5,6 @@ object @resource attributes :id, :name, :description -node :operatingsystem_family do |resource| - resource.operatingsystem&.family -end - -node :operatingsystem_major do |resource| - resource.operatingsystem&.major -end - if @facet node :content_view do content_view = @facet&.single_content_view diff --git a/app/views/katello/api/v2/hosts/os_attributes.json.rabl b/app/views/katello/api/v2/hosts/os_attributes.json.rabl new file mode 100644 index 00000000000..963eb4e0207 --- /dev/null +++ b/app/views/katello/api/v2/hosts/os_attributes.json.rabl @@ -0,0 +1,13 @@ +object @resource + +@resource ||= @object + +attributes :id, :name, :description + +node :operatingsystem_family do |resource| + resource.operatingsystem&.family +end + +node :operatingsystem_major do |resource| + resource.operatingsystem&.major +end diff --git a/app/views/katello/api/v2/http_proxies/show.json.rabl b/app/views/katello/api/v2/http_proxies/show.json.rabl new file mode 100644 index 00000000000..9e41a1adf72 --- /dev/null +++ b/app/views/katello/api/v2/http_proxies/show.json.rabl @@ -0,0 +1 @@ +node(:content_default_http_proxy) { |sp| sp.content_default_http_proxy? } diff --git a/app/views/overrides/activation_keys/_host_synced_content_select.html.erb b/app/views/overrides/activation_keys/_host_synced_content_select.html.erb index a94e6833f67..068050cd177 100644 --- a/app/views/overrides/activation_keys/_host_synced_content_select.html.erb +++ b/app/views/overrides/activation_keys/_host_synced_content_select.html.erb @@ -23,9 +23,15 @@ :class => 'form-control', :name => ks_repo_select_name, :disabled => kickstart_options.empty? %> <% end %> -<% content_for(:javascripts) do -%> - -<% end -%> \ No newline at end of file + } + else { + $(document).on('ContentLoad', function(){ + KT.hosts.set_media_selection_bindings(); + KT.hosts.update_media_enablement(); + }); + } + diff --git a/app/views/overrides/http_proxies/_update_setting_input.html.erb b/app/views/overrides/http_proxies/_update_setting_input.html.erb index a9141f4bcde..991456abc43 100644 --- a/app/views/overrides/http_proxies/_update_setting_input.html.erb +++ b/app/views/overrides/http_proxies/_update_setting_input.html.erb @@ -1,16 +1,18 @@ -<% if @http_proxy.new_record? %> -
-
- -
- <%= check_box_tag 'http_proxy[default_content]', - '1', - params.dig('http_proxy', 'default_content') == '1', - id: 'http_proxy_default_content' %> - Set this proxy as the default for content, updating the 'Default HTTP Proxy' setting. -
+
+
+ +
+ <% if @http_proxy.new_record? %> + <%= check_box_tag 'http_proxy[content_default_http_proxy]', + '1', + params.dig('http_proxy', 'content_default_http_proxy') == '1', + id: 'content_default_http_proxy' %> + Set this proxy as the default for content, updating the 'Default HTTP Proxy' setting. + <% else %> + <%= @http_proxy.content_default_http_proxy? ? _('Yes') : _('No') %> + <% end %>
-<% end %> +
diff --git a/config/initializers/monkeys.rb b/config/initializers/monkeys.rb index 8ed5b9fe7a5..1cba332c8aa 100644 --- a/config/initializers/monkeys.rb +++ b/config/initializers/monkeys.rb @@ -1,4 +1,3 @@ #place where monkey patches are required require 'monkeys/ar_postgres_evr_t' -require 'monkeys/fx_sqlite_skip' require 'monkeys/remove_hidden_distribution' diff --git a/config/routes/api/registry.rb b/config/routes/api/registry.rb index e4a365ed80a..d5ff6ec475d 100644 --- a/config/routes/api/registry.rb +++ b/config/routes/api/registry.rb @@ -19,6 +19,7 @@ class ActionDispatch::Routing::Mapper match '/v2' => 'registry_proxies#ping', :via => :get match '/v1/_ping' => 'registry_proxies#v1_ping', :via => :get match '/v1/search' => 'registry_proxies#v1_search', :via => :get + match '/index/static' => 'registry_proxies#static_index', :via => :get end end end diff --git a/config/routes/api/v2.rb b/config/routes/api/v2.rb index c6c894a76fe..d3dd1fa9272 100644 --- a/config/routes/api/v2.rb +++ b/config/routes/api/v2.rb @@ -30,6 +30,10 @@ class ActionDispatch::Routing::Mapper end end + api_resources :host_bootc_images, :only => [:auto_complete_search] do + get :auto_complete_search, :on => :collection + end + api_resources :capsules, :only => [:index, :show] do member do resource :content, :only => [], :controller => 'capsule_content' do diff --git a/config/routes/overrides.rb b/config/routes/overrides.rb index 142312d6e8d..32bcf9d5fdb 100644 --- a/config/routes/overrides.rb +++ b/config/routes/overrides.rb @@ -59,6 +59,7 @@ def matches?(request) collection do match '/auto_complete_search' => 'host_autocomplete#auto_complete_search', :via => :get + match '/bootc_images' => 'host_bootc_images#bootc_images', :via => :get match '/bulk/add_host_collections' => 'hosts_bulk_actions#bulk_add_host_collections', :via => :put match '/bulk/remove_host_collections' => 'hosts_bulk_actions#bulk_remove_host_collections', :via => :put match '/bulk/remove_host_collections' => 'hosts_bulk_actions#bulk_remove_host_collections', :via => :put diff --git a/db/migrate/20200213184848_create_evr_type.rb b/db/migrate/20200213184848_create_evr_type.rb index 8bd6bfe9148..4426fd730ff 100644 --- a/db/migrate/20200213184848_create_evr_type.rb +++ b/db/migrate/20200213184848_create_evr_type.rb @@ -4,7 +4,132 @@ class CreateEvrType < ActiveRecord::Migration[5.2] def up unless connection.adapter_name.downcase.include?('sqlite') - enable_extension "evr" + execute <<~SQL + create type evr_array_item as ( + n NUMERIC, + s TEXT + ); + + create type evr_t as ( + epoch INT, + version evr_array_item[], + release evr_array_item[] + ); + + CREATE FUNCTION evr_trigger() RETURNS trigger AS $$ + BEGIN + NEW.evr = (select ROW(coalesce(NEW.epoch::numeric,0), + rpmver_array(coalesce(NEW.version,'empty'))::evr_array_item[], + rpmver_array(coalesce(NEW.release,'empty'))::evr_array_item[])::evr_t); + RETURN NEW; + END; + $$ language 'plpgsql'; + + create or replace FUNCTION empty(t TEXT) + RETURNS BOOLEAN as $$ + BEGIN + return t ~ '^[[:space:]]*$'; + END; + $$ language 'plpgsql'; + + create or replace FUNCTION isalpha(ch CHAR) + RETURNS BOOLEAN as $$ + BEGIN + if ascii(ch) between ascii('a') and ascii('z') or + ascii(ch) between ascii('A') and ascii('Z') + then + return TRUE; + end if; + return FALSE; + END; + $$ language 'plpgsql'; + + create or replace FUNCTION isalphanum(ch CHAR) + RETURNS BOOLEAN as $$ + BEGIN + if ascii(ch) between ascii('a') and ascii('z') or + ascii(ch) between ascii('A') and ascii('Z') or + ascii(ch) between ascii('0') and ascii('9') + then + return TRUE; + end if; + return FALSE; + END; + $$ language 'plpgsql'; + + create or replace function isdigit(ch CHAR) + RETURNS BOOLEAN as $$ + BEGIN + if ascii(ch) between ascii('0') and ascii('9') + then + return TRUE; + end if; + return FALSE; + END ; + $$ language 'plpgsql'; + + create or replace FUNCTION rpmver_array (string1 IN VARCHAR) + RETURNS evr_array_item[] as $$ + declare + str1 VARCHAR := string1; + digits VARCHAR(10) := '0123456789'; + lc_alpha VARCHAR(27) := 'abcdefghijklmnopqrstuvwxyz'; + uc_alpha VARCHAR(27) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + alpha VARCHAR(54) := lc_alpha || uc_alpha; + one VARCHAR; + isnum BOOLEAN; + ver_array evr_array_item[] := ARRAY[]::evr_array_item[]; + BEGIN + if str1 is NULL + then + RAISE EXCEPTION 'VALUE_ERROR.'; + end if; + + one := str1; + <> + while one <> '' + loop + declare + segm1 VARCHAR; + segm1_n NUMERIC := 0; + begin + -- Throw out all non-alphanum characters + while one <> '' and not isalphanum(one) + loop + one := substr(one, 2); + end loop; + str1 := one; + if str1 <> '' and isdigit(str1) + then + str1 := ltrim(str1, digits); + isnum := true; + else + str1 := ltrim(str1, alpha); + isnum := false; + end if; + if str1 <> '' + then segm1 := substr(one, 1, length(one) - length(str1)); + else segm1 := one; + end if; + + if segm1 = '' then return ver_array; end if; /* arbitrary */ + if isnum + then + segm1 := ltrim(segm1, '0'); + if segm1 <> '' then segm1_n := segm1::numeric; end if; + segm1 := NULL; + else + end if; + ver_array := array_append(ver_array, (segm1_n, segm1)::evr_array_item); + one := str1; + end; + end loop segment_loop; + + return ver_array; + END ; + $$ language 'plpgsql'; + + SQL add_column :katello_rpms, :evr, :evr_t add_column :katello_installed_packages, :evr, :evr_t diff --git a/db/migrate/20240924161240_katello_recreate_evr_constructs.rb b/db/migrate/20240924161240_katello_recreate_evr_constructs.rb new file mode 100644 index 00000000000..e0a28790d26 --- /dev/null +++ b/db/migrate/20240924161240_katello_recreate_evr_constructs.rb @@ -0,0 +1,160 @@ +class KatelloRecreateEvrConstructs < ActiveRecord::Migration[6.1] + def up + if !extension_enabled?('evr') + return + else + execute <<~SQL + DROP EXTENSION evr CASCADE; + SQL + + execute <<~SQL + create type evr_array_item as ( + n NUMERIC, + s TEXT + ); + + create type evr_t as ( + epoch INT, + version evr_array_item[], + release evr_array_item[] + ); + + CREATE FUNCTION evr_trigger() RETURNS trigger AS $$ + BEGIN + NEW.evr = (select ROW(coalesce(NEW.epoch::numeric,0), + rpmver_array(coalesce(NEW.version,'empty'))::evr_array_item[], + rpmver_array(coalesce(NEW.release,'empty'))::evr_array_item[])::evr_t); + RETURN NEW; + END; + $$ language 'plpgsql'; + + create or replace FUNCTION empty(t TEXT) + RETURNS BOOLEAN as $$ + BEGIN + return t ~ '^[[:space:]]*$'; + END; + $$ language 'plpgsql'; + + create or replace FUNCTION isalpha(ch CHAR) + RETURNS BOOLEAN as $$ + BEGIN + if ascii(ch) between ascii('a') and ascii('z') or + ascii(ch) between ascii('A') and ascii('Z') + then + return TRUE; + end if; + return FALSE; + END; + $$ language 'plpgsql'; + + create or replace FUNCTION isalphanum(ch CHAR) + RETURNS BOOLEAN as $$ + BEGIN + if ascii(ch) between ascii('a') and ascii('z') or + ascii(ch) between ascii('A') and ascii('Z') or + ascii(ch) between ascii('0') and ascii('9') + then + return TRUE; + end if; + return FALSE; + END; + $$ language 'plpgsql'; + + create or replace function isdigit(ch CHAR) + RETURNS BOOLEAN as $$ + BEGIN + if ascii(ch) between ascii('0') and ascii('9') + then + return TRUE; + end if; + return FALSE; + END ; + $$ language 'plpgsql'; + + create or replace FUNCTION rpmver_array (string1 IN VARCHAR) + RETURNS evr_array_item[] as $$ + declare + str1 VARCHAR := string1; + digits VARCHAR(10) := '0123456789'; + lc_alpha VARCHAR(27) := 'abcdefghijklmnopqrstuvwxyz'; + uc_alpha VARCHAR(27) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + alpha VARCHAR(54) := lc_alpha || uc_alpha; + one VARCHAR; + isnum BOOLEAN; + ver_array evr_array_item[] := ARRAY[]::evr_array_item[]; + BEGIN + if str1 is NULL + then + RAISE EXCEPTION 'VALUE_ERROR.'; + end if; + + one := str1; + <> + while one <> '' + loop + declare + segm1 VARCHAR; + segm1_n NUMERIC := 0; + begin + -- Throw out all non-alphanum characters + while one <> '' and not isalphanum(one) + loop + one := substr(one, 2); + end loop; + str1 := one; + if str1 <> '' and isdigit(str1) + then + str1 := ltrim(str1, digits); + isnum := true; + else + str1 := ltrim(str1, alpha); + isnum := false; + end if; + if str1 <> '' + then segm1 := substr(one, 1, length(one) - length(str1)); + else segm1 := one; + end if; + + if segm1 = '' then return ver_array; end if; /* arbitrary */ + if isnum + then + segm1 := ltrim(segm1, '0'); + if segm1 <> '' then segm1_n := segm1::numeric; end if; + segm1 := NULL; + else + end if; + ver_array := array_append(ver_array, (segm1_n, segm1)::evr_array_item); + one := str1; + end; + end loop segment_loop; + + return ver_array; + END ; + $$ language 'plpgsql'; + + SQL + + add_column :katello_rpms, :evr, :evr_t + add_column :katello_installed_packages, :evr, :evr_t + + execute <<-SQL + update katello_rpms SET evr = (ROW(coalesce(epoch::numeric,0), + rpmver_array(coalesce(version,'empty'))::evr_array_item[], + rpmver_array(coalesce(release,'empty'))::evr_array_item[])::evr_t); + + update katello_installed_packages SET evr = (ROW(coalesce(epoch::numeric,0), + rpmver_array(coalesce(version,'empty'))::evr_array_item[], + rpmver_array(coalesce(release,'empty'))::evr_array_item[])::evr_t); + SQL + + create_trigger :evr_insert_trigger_katello_rpms, on: :katello_rpms + create_trigger :evr_update_trigger_katello_rpms, on: :katello_rpms + create_trigger :evr_insert_trigger_katello_installed_packages, on: :katello_installed_packages + create_trigger :evr_update_trigger_katello_installed_packages, on: :katello_installed_packages + end + end + + def down + fail ActiveRecord::IrreversibleMigration + end +end diff --git a/db/migrate/20241120213713_add_allow_other_types_to_content_view_erratum_filter_rules.rb b/db/migrate/20241120213713_add_allow_other_types_to_content_view_erratum_filter_rules.rb new file mode 100644 index 00000000000..adac4544e52 --- /dev/null +++ b/db/migrate/20241120213713_add_allow_other_types_to_content_view_erratum_filter_rules.rb @@ -0,0 +1,6 @@ +class AddAllowOtherTypesToContentViewErratumFilterRules < ActiveRecord::Migration[6.1] + def change + add_column :katello_content_view_erratum_filter_rules, :allow_other_types, :boolean, + :default => false, :null => false + end +end diff --git a/db/seeds.d/75-job_templates.rb b/db/seeds.d/75-job_templates.rb index 385bc3f3ae6..17247eb9c39 100644 --- a/db/seeds.d/75-job_templates.rb +++ b/db/seeds.d/75-job_templates.rb @@ -1,8 +1,12 @@ User.as_anonymous_admin do JobTemplate.without_auditing do + # let's name root template as *_action.erb + root_action_files = Dir[File.join("#{Katello::Engine.root}/app/views/foreman/job_templates/**/*_action.erb")] template_files = Dir[File.join("#{Katello::Engine.root}/app/views/foreman/job_templates/**/*.erb")] template_files.reject! { |file| file.end_with?('_ansible_default.erb') } unless Katello.with_ansible? - template_files.each do |template| + + # root templates need to be imported first + (root_action_files + (template_files - root_action_files)).each do |template| sync = !Rails.env.test? && Setting[:remote_execution_sync_templates] template = JobTemplate.import_raw!(File.read(template), :default => true, :lock => true, :update => sync) diff --git a/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/debs.controller.js b/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/debs.controller.js index 4cf9adb0c7d..7a2e6ca390e 100644 --- a/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/debs.controller.js +++ b/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/debs.controller.js @@ -1,38 +1,52 @@ -(function () { - 'use strict'; - - /** - * @ngdoc controller - * @name Bastion.debs.controller:DebsController - * - * @description - * Handles fetching deb packages and populating Nutupane based on the current - * ui-router state. - * - * @requires translate - * - */ - function DebsController($scope, $location, translate, Nutupane, Deb, CurrentOrganization) { +/** + * @ngdoc controller + * @name Bastion.debs.controller:DebsController + * + * @description + * Handles fetching deb packages and populating Nutupane based on the current + * ui-router state. + * + * @requires translate + * + */ +angular.module('Bastion.debs').controller('DebsController', + ['$scope', '$location', 'translate', 'Nutupane', 'Deb', 'Repository', 'CurrentOrganization', + function DebsController($scope, $location, translate, Nutupane, Deb, Repository, CurrentOrganization) { var nutupane; var params = { 'organization_id': CurrentOrganization, 'search': $location.search().search || "", + 'repository_id': $location.search().repositoryId || null, 'paged': true, 'sort_by': 'name', 'sort_order': 'ASC' }; - nutupane = new Nutupane(Deb, params); + nutupane = $scope.nutupane = new Nutupane(Deb, params); nutupane.primaryOnly = true; $scope.table = nutupane.table; // Labels so breadcrumb strings can be translated $scope.label = translate('Debs'); + $scope.repositoriesLabel = translate('Repositories'); $scope.controllerName = 'katello_debs'; + $scope.repository = {name: translate('All Repositories'), id: 'all'}; + + Repository.queryUnpaged({'organization_id': CurrentOrganization, 'content_type': 'deb', 'with_content': 'deb'}, function (response) { + $scope.repositories = [$scope.repository]; + $scope.repositories = $scope.repositories.concat(response.results); + + if ($location.search().repositoryId) { + $scope.repository = _.find($scope.repositories, function (repository) { + return repository.id === parseInt($location.search().repositoryId, 10); + }); + } + }); + Deb.queryPaged({'organization_id': CurrentOrganization}, function (result) { $scope.packageCount = result.total; }); @@ -50,12 +64,22 @@ nutupane.refresh(); }; - } + $scope.$watch('repository', function (repository) { + var nutupaneParams = nutupane.getParams(); - angular - .module('Bastion.debs') - .controller('DebsController', DebsController); + if (repository.id === 'all') { + nutupaneParams['repository_id'] = null; + nutupane.setParams(nutupaneParams); + } else { + $location.search('repositoryId', repository.id); + nutupaneParams['repository_id'] = repository.id; + nutupane.setParams(nutupaneParams); + } - DebsController.$inject = ['$scope', '$location', 'translate', 'Nutupane', 'Deb', 'CurrentOrganization']; + if (!nutupane.table.initialLoad) { + nutupane.refresh(); + } + }); -})(); + }] +); diff --git a/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/views/debs.html b/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/views/debs.html index 935a718c314..01c2219bdc4 100644 --- a/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/views/debs.html +++ b/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/views/debs.html @@ -6,6 +6,10 @@

Deb Packages

+
+ +
+