module Actions module Katello module Host class HypervisorsUpdate < Actions::EntryAction middleware.use ::Actions::Middleware::RemoteAction input_format do param :hypervisors end def run output[:results] = input[:results] @hypervisors = input[:hypervisors] return unless @hypervisors User.as_anonymous_admin do ActiveRecord::Base.transaction do load_resources end ActiveRecord::Base.transaction do @hosts.each do |uuid, host| update_host(uuid, host) end end @hosts.each do |uuid, host| update_facts(uuid, host) end end end # Loads all resources needed for refreshing subscription facet def load_resources @organizations = ::Organization.where(label: hypervisors_field(:organization_label)).map { |org| [org.label, org] }.to_h candlepin_data = ::Katello::Resources::Candlepin::Consumer.get_all_with_facts(hypervisors_field(:uuid)) @candlepin_attributes = candlepin_data.map { |consumer| [consumer[:uuid], consumer] }.to_h @hosts = {} @hosts.merge!(load_hosts_by_uuid) @hosts.merge!(load_hosts_by_duplicate_name) @hosts.merge!(create_missing_hosts) end def load_hosts_by_uuid hosts_by_uuid = ::Host.eager_load(:subscription_facet).where(katello_subscription_facets: { uuid: hypervisors_field(:uuid) }) hosts_by_uuid.each do |host| validate_host_organization(host, host.organization.try(:id)) end hosts_by_uuid.map { |host| [host.subscription_facet.uuid, host] }.to_h end def load_hosts_by_duplicate_name duplicate_names, duplicate_name_orgs = generate_duplicates_list hosts_by_dup_name = ::Host.preload(:subscription_facet).where(name: duplicate_names.keys) hosts_by_dup_name.each do |host| validate_host_organization(host, duplicate_name_orgs[host.name].try(:id)) end hosts_by_dup_name.map { |host| [duplicate_names[host.name], host] }.to_h end def create_missing_hosts # remaining hypervisors new_hypervisors = {} @hypervisors.each do |hypervisor| next if @hosts.key?(hypervisor[:uuid]) duplicate_name, org = duplicate_name(hypervisor, @candlepin_attributes[hypervisor[:uuid]]) new_hypervisors[hypervisor[:uuid]] = create_host_for_hypervisor(duplicate_name, org) end new_hypervisors end def generate_duplicates_list duplicate_names = {} duplicate_name_orgs = {} @hypervisors.each do |hypervisor| next if @hosts.key?(hypervisor[:uuid]) duplicate_name, org = duplicate_name(hypervisor, @candlepin_attributes[hypervisor[:uuid]]) duplicate_names[duplicate_name] = hypervisor[:uuid] duplicate_name_orgs[duplicate_name] = org end [duplicate_names, duplicate_name_orgs] end def validate_host_organization(host, organization) if host.organization_id.nil? || host.organization_id != organization fail _("Host '%{name}' does not belong to an organization") % {:name => host.name} unless host.organization end end # extracts a single field from a given list og hypervisors data. def hypervisors_field(field, hypervisors = @hypervisors) hypervisors.map { |h| h[field] }.uniq end def name_for_host(organization, consumer) sanitized_name = ::Katello::Host::SubscriptionFacet.sanitize_name(consumer[:hypervisorId][:hypervisorId]) "virt-who-#{sanitized_name}-#{organization.id}" end def duplicate_name(hypervisor, consumer) organization = @organizations[hypervisor[:organization_label]] [name_for_host(organization, consumer), organization] end def create_host_for_hypervisor(name, organization, location = nil) location ||= Location.default_host_subscribe_location! host = ::Host::Managed.new(:name => name, :organization => organization, :location => location, :managed => false, :enabled => false) host.save! host end def update_host(uuid, host) update_subscription_facet(uuid, host) update_host_name(uuid, host) host.save! end def update_host_name(uuid, host) # if the hypervisorId name pattern does not match that of the host, update the name consumer = @candlepin_attributes[uuid] return unless consumer expected_name = name_for_host(host.organization, consumer) if host.name != expected_name host.name = expected_name end end def update_subscription_facet(uuid, host) host.subscription_facet ||= host.build_subscription_facet(uuid: uuid) if @candlepin_attributes.key?(uuid) host.subscription_facet.candlepin_consumer.consumer_attributes = @candlepin_attributes[uuid] host.subscription_facet.import_database_attributes host.subscription_facet.save! host.subscription_facet.update_subscription_status(@candlepin_attributes[uuid].try(:[], :entitlementStatus)) end end def update_facts(uuid, host) if @candlepin_attributes.key?(uuid) ::Katello::Host::SubscriptionFacet.update_facts(host, @candlepin_attributes[uuid][:facts]) unless @candlepin_attributes[uuid][:facts].blank? end end def rescue_strategy Dynflow::Action::Rescue::Skip end end end end end