Skip to content

Commit

Permalink
Fixes #37888 - add host bootc information to API
Browse files Browse the repository at this point in the history
  • Loading branch information
ianballou committed Oct 10, 2024
1 parent eba327d commit fd1b623
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 1 deletion.
26 changes: 26 additions & 0 deletions app/models/katello/concerns/content_facet_host_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ module ContentFacetHostExtensions
scoped_search :relation => :bound_root_repositories, :on => :name, :rename => :repository, :complete_value => true, :ext_method => :find_by_repository_name, :only_explicit => true
scoped_search :relation => :bound_content, :on => :label, :rename => :repository_content_label, :complete_value => true, :ext_method => :find_by_repository_content_label, :only_explicit => true

scoped_search relation: :content_facet, on: :bootc_booted_image, complete_value: true, only_explicit: true
scoped_search relation: :content_facet, on: :bootc_booted_digest, complete_value: true, only_explicit: true
scoped_search relation: :content_facet, on: :bootc_available_image, complete_value: true, only_explicit: true
scoped_search relation: :content_facet, on: :bootc_available_digest, complete_value: true, only_explicit: true
scoped_search relation: :content_facet, on: :bootc_staged_image, complete_value: true, only_explicit: true
scoped_search relation: :content_facet, on: :bootc_staged_digest, complete_value: true, only_explicit: true
scoped_search relation: :content_facet, on: :bootc_rollback_image, complete_value: true, only_explicit: true
scoped_search relation: :content_facet, on: :bootc_rollback_digest, complete_value: true, only_explicit: true
scoped_search relation: :content_facet, on: :bootc_booted_image, rename: :image_mode, only_explicit: true, ext_method: :find_by_image_mode,
operators: ['='], complete_value: { true: true, false: false}

# preserve options set by facets framework, but add new :reject_if statement
accepts_nested_attributes_for(
:content_facet,
Expand All @@ -77,6 +88,21 @@ def content_facet_ignore_update?(attributes)
end

module ClassMethods
def find_by_image_mode(_key, _operator, value)
# operator is always '='
state = ::Foreman::Cast.to_bool(value)
if state
hosts = ::Host::Managed.joins(:content_facet).where.not("#{::Katello::Host::ContentFacet.table_name}.bootc_booted_image" => nil)
else
hosts = ::Host::Managed.joins(:content_facet).where("#{::Katello::Host::ContentFacet.table_name}.bootc_booted_image" => nil)
end
if hosts.empty?
{ :conditions => "1=0" }
else
{ :conditions => "#{::Host::Managed.table_name}.id IN (#{hosts.pluck(:id).join(',')})" }
end
end

def find_by_applicable_errata(_key, operator, value)
conditions = sanitize_sql_for_conditions(["#{Katello::Erratum.table_name}.errata_id #{operator} ?", value_to_sql(operator, value)])
hosts = ::Host::Managed.joins(:applicable_errata).where(conditions)
Expand Down
6 changes: 5 additions & 1 deletion app/models/katello/concerns/host_managed_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def remote_execution_proxies(provider, *_rest)
prepend Overrides

delegate :content_source_id, :single_content_view, :single_lifecycle_environment, :default_environment?, :single_content_view_environment?, :multi_content_view_environment?, :kickstart_repository_id, :bound_repositories,
:installable_errata, :installable_rpms, to: :content_facet, allow_nil: true
:installable_errata, :installable_rpms, :image_mode_host?, to: :content_facet, allow_nil: true

delegate :release_version, :purpose_role, :purpose_usage, to: :subscription_facet, allow_nil: true

Expand Down Expand Up @@ -128,6 +128,10 @@ def remote_execution_proxies(provider, *_rest)

scope :with_pools_expiring_in_days, ->(days) { joins(:pools).merge(Katello::Pool.expiring_in_days(days)).distinct }

scope :image_mode, -> do
joins(:content_facet).where.not("#{::Katello::Host::ContentFacet.table_name}.bootc_booted_image" => nil)
end

scoped_search :relation => :host_collections, :on => :id, :complete_value => false, :rename => :host_collection_id, :only_explicit => true, :validator => ScopedSearch::Validators::INTEGER
scoped_search :relation => :host_collections, :on => :name, :complete_value => true, :rename => :host_collection
scoped_search :relation => :installed_packages, :on => :nvra, :complete_value => true, :rename => :installed_package, :only_explicit => true
Expand Down
6 changes: 6 additions & 0 deletions app/models/katello/host/content_facet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class ContentFacet < Katello::Model
validates_with Katello::Validators::GeneratedContentViewValidator
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 }

scope :with_environments, ->(lifecycle_environments) do
joins(:content_view_environment_content_facets => :content_view_environment).
Expand Down Expand Up @@ -88,6 +90,10 @@ def mark_cves_unchanged
self.cves_changed = false
end

def image_mode_host?
bootc_booted_image.present?
end

def cves_changed?
cves_changed
end
Expand Down
6 changes: 6 additions & 0 deletions app/views/katello/api/v2/content_facet/show.json.rabl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ child :content_facet => :content_facet_attributes do
node(:view_products) { user.can?("view_products") }
node(:create_bookmarks) { user.can?("create_bookmarks") }
end

node :image_mode_host do |content_facet|
content_facet.image_mode_host?
end
attributes :bootc_booted_image, :bootc_booted_digest, :bootc_available_image, :bootc_available_digest,
:bootc_staged_image, :bootc_staged_digest, :bootc_rollback_image, :bootc_rollback_digest
end

attributes :description, :facts
27 changes: 27 additions & 0 deletions db/migrate/20241007212705_add_bootc_facts_to_content_facet.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class AddBootcFactsToContentFacet < ActiveRecord::Migration[6.1]
def change
add_column :katello_content_facets, :bootc_booted_image, :string
add_column :katello_content_facets, :bootc_booted_digest, :string

add_column :katello_content_facets, :bootc_available_image, :string
add_column :katello_content_facets, :bootc_available_digest, :string

add_column :katello_content_facets, :bootc_staged_image, :string
add_column :katello_content_facets, :bootc_staged_digest, :string

add_column :katello_content_facets, :bootc_rollback_image, :string
add_column :katello_content_facets, :bootc_rollback_digest, :string

add_index :katello_content_facets, :bootc_booted_image
add_index :katello_content_facets, :bootc_booted_digest

add_index :katello_content_facets, :bootc_available_image
add_index :katello_content_facets, :bootc_available_digest

add_index :katello_content_facets, :bootc_staged_image
add_index :katello_content_facets, :bootc_staged_digest

add_index :katello_content_facets, :bootc_rollback_image
add_index :katello_content_facets, :bootc_rollback_digest
end
end
22 changes: 22 additions & 0 deletions test/models/concerns/host_managed_extensions_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ def setup
end

class HostManagedExtensionsTest < HostManagedExtensionsTestBase
def test_image_mode_host_positive
Support::HostSupport.attach_content_facet(@foreman_host, @view, @library)
@foreman_host.content_facet.update(bootc_booted_image: 'quay.io/salami/salad')
assert @foreman_host.content_facet.image_mode_host?
end

def test_image_mode_host_negative
Support::HostSupport.attach_content_facet(@foreman_host, @view, @library)
@foreman_host.content_facet.update(bootc_booted_image: nil)
refute @foreman_host.content_facet.image_mode_host?
end

def test_update_organization
host = FactoryBot.create(:host, :with_subscription)
assert_raises ::Katello::Errors::HostRegisteredException do
Expand Down Expand Up @@ -58,6 +70,16 @@ def test_pools_expiring_in_days
assert_includes ::Host.search_for('pools_expiring_in_days = 30'), host_with_pool
end

def test_image_mode_search
host_no_image = FactoryBot.create(:host, :with_content, :with_subscription, :content_view => @library_view, :lifecycle_environment => @library)
Support::HostSupport.attach_content_facet(@foreman_host, @view, @library)
@foreman_host.content_facet.update(bootc_booted_image: 'quay.io/salami/soup')
assert_includes ::Host.search_for('image_mode = true'), @foreman_host
refute_includes ::Host.search_for('image_mode = true'), host_no_image
assert_includes ::Host.search_for('image_mode = false'), host_no_image
refute_includes ::Host.search_for('image_mode = false'), @foreman_host
end

def test_smart_proxy_ids_with_katello
content_source = FactoryBot.create(:smart_proxy,
:features => [Feature.where(:name => "Pulp Node").first_or_create])
Expand Down
52 changes: 52 additions & 0 deletions test/models/host/content_facet_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,58 @@ def test_content_view_version
assert_equal view.version(library), host.content_facet.content_view_environments.reload.first.content_view_version
end

def test_bootc_booted_digest_validation
error = assert_raises(ActiveRecord::RecordInvalid) do
host.content_facet.update!(bootc_booted_digest: "blah")
end
assert_includes error.message, "Bootc booted digest must be a valid sha256 digest"
end

def test_bootc_available_digest_validation
error = assert_raises(ActiveRecord::RecordInvalid) do
host.content_facet.update!(bootc_available_digest: "blah")
end
assert_includes error.message, "Bootc available digest must be a valid sha256 digest"
end

def test_bootc_staged_digest_validation
error = assert_raises(ActiveRecord::RecordInvalid) do
host.content_facet.update!(bootc_staged_digest: "blah")
end
assert_includes error.message, "Bootc staged digest must be a valid sha256 digest"
end

def test_bootc_rollback_digest_validation
error = assert_raises(ActiveRecord::RecordInvalid) do
host.content_facet.update!(bootc_rollback_digest: "blah")
end
assert_includes error.message, "Bootc rollback digest must be a valid sha256 digest"
end

def test_bootc_booted_digest_valid
valid_digest = "sha256:dcfb2965cda67bd3731408ace23dd07ff3116168c2b832e16bba8234525724a3"
host.content_facet.update!(bootc_booted_digest: valid_digest)
assert_equal valid_digest, host.content_facet.bootc_booted_digest
end

def test_bootc_available_digest_valid
valid_digest = "sha256:dcfb2965cda67bd3731408ace23dd07ff3116168c2b832e16bba8234525724a3"
host.content_facet.update!(bootc_available_digest: valid_digest)
assert_equal valid_digest, host.content_facet.bootc_available_digest
end

def test_bootc_staged_digest_valid
valid_digest = "sha256:dcfb2965cda67bd3731408ace23dd07ff3116168c2b832e16bba8234525724a3"
host.content_facet.update!(bootc_staged_digest: valid_digest)
assert_equal valid_digest, host.content_facet.bootc_staged_digest
end

def test_bootc_rollback_digest_valid
valid_digest = "sha256:dcfb2965cda67bd3731408ace23dd07ff3116168c2b832e16bba8234525724a3"
host.content_facet.update!(bootc_rollback_digest: valid_digest)
assert_equal valid_digest, host.content_facet.bootc_rollback_digest
end

def test_tracer_installed?
refute host.content_facet.tracer_installed?

Expand Down

0 comments on commit fd1b623

Please sign in to comment.