Module: ForemanInventoryUpload::Generators::FactHelpers

Extended by:
ActiveSupport::Concern
Included in:
Metadata, Slice
Defined in:
lib/foreman_inventory_upload/generators/fact_helpers.rb

Constant Summary collapse

CLOUD_AMAZON =
'aws'
CLOUD_GOOGLE =
'gcp'
CLOUD_AZURE =
'azure'
CLOUD_ALIBABA =
'alibaba'
UUID_REGEX =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i

Instance Method Summary collapse

Instance Method Details

#account_id(organization) ⇒ Object



26
27
28
29
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 26

def (organization)
  @organization_accounts ||= {}
  @organization_accounts[organization.id] ||= organization.pools.where.not(account_number: nil).pluck(:account_number).first
end

#bios_uuid(host) ⇒ Object



176
177
178
179
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 176

def bios_uuid(host)
  value = fact_value(host, 'dmi::system::uuid') || ''
  uuid_value(value)
end

#cloud_provider(host) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 39

def cloud_provider(host)
  bios_version = fact_value(host, 'dmi::bios::version')

  if bios_version
    return CLOUD_AMAZON if bios_version.downcase['amazon']
    return CLOUD_GOOGLE if bios_version.downcase['google']
  end

  chassis_asset_tag = fact_value(host, 'dmi::chassis::asset_tag')
  return CLOUD_AZURE if chassis_asset_tag && chassis_asset_tag['7783-7084-3265-9085-8269-3286-77']

  system_manufacturer = fact_value(host, 'dmi::system::manufacturer')
  return CLOUD_ALIBABA if system_manufacturer && system_manufacturer.downcase['alibaba cloud']

  product_name = fact_value(host, 'dmi::system::product_name')
  return CLOUD_ALIBABA if product_name && product_name.downcase['alibaba cloud ecs']

  nil
end

#fact_value(host, fact_name) ⇒ Object



15
16
17
18
19
20
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 15

def fact_value(host, fact_name)
  value_record = host.fact_values.find do |fact_value|
    fact_value.fact_name_id == ForemanInventoryUpload::Generators::Queries.fact_names[fact_name]
  end
  value_record&.value
end

#fqdn(host) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 72

def fqdn(host)
  if obfuscate_hostname?(host)
    # If obfuscation is enabled, attempt to retrieve an already obfuscated hostname
    # from the 'insights_client::obfuscated_hostname' fact.
    # Example format of `parsed_insights_array`:
    # [{"original"=>"host.example.com", "obfuscated"=>"0dd449d0a027.example.com"},
    #  {"original"=>"satellite.example.com", "obfuscated"=>"host2.example.com"}]
    begin
      parsed_insights_array = JSON.parse(fact_value(host, 'insights_client::obfuscated_hostname') || '[]')
    rescue JSON::ParserError
      parsed_insights_array = []
    end
    # Obfuscate using the following hierarchy:
    # 1. the obfuscated_hostname fact sent by insights_client
    parsed_insights_item = parsed_insights_array.find { |item| item['original'] == host.fqdn }
    # 2. our own helper method
    parsed_insights_item&.[]('obfuscated') || obfuscate_fqdn(host.fqdn)
  else
    # If hostname obfuscation is not enabled for this host, return the host's original FQDN.
    host.fqdn
  end
end

#golden_ticket?(organization) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
35
36
37
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 31

def golden_ticket?(organization)
  result = organization.try(:golden_ticket?)
  result = organization.content_access_mode == 'org_environment' if result.nil?

  @organization_golden_tickets ||= {}
  @organization_golden_tickets[organization.id] ||= result
end

#host_ips(host) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 115

def host_ips(host)
  # Determines and returns the IP addresses associated with a host, applying obfuscation if enabled.

  # If IP obfuscation is enabled for the host return a representation of obfuscated IP addresses.
  return obfuscated_ips(host) if obfuscate_ips?(host)

  # If IP obfuscation is NOT needed, return a special kind of Hash.
  # where when you try to access a key in it
  # if the key doesn't exist, it simply returns the key itself.
  # This is useful because it means if you try to get an IP from this hash,
  # you'll just get the original IP back. It allows the calling code to
  # use the same interface whether obfuscation is applied or not.
  Hash.new { |h, k| k }
end

#hostname_matchObject



164
165
166
167
168
169
170
171
172
173
174
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 164

def hostname_match
  bash_hostname = `uname -n`.chomp
  foreman_hostname = ForemanRhCloud.foreman_host&.name
  if bash_hostname == foreman_hostname
    fqdn(ForemanRhCloud.foreman_host)
  elsif Setting[:obfuscate_inventory_hostnames]
    obfuscate_fqdn(bash_hostname)
  else
    bash_hostname
  end
end

#kilobytes_to_bytes(kilobytes) ⇒ Object



22
23
24
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 22

def kilobytes_to_bytes(kilobytes)
  kilobytes * 1024
end

#obfuscate_fqdn(fqdn) ⇒ Object



95
96
97
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 95

def obfuscate_fqdn(fqdn)
  "#{Digest::SHA1.hexdigest(fqdn)}.example.com"
end

#obfuscate_hostname?(host) ⇒ Boolean

Returns:

  • (Boolean)


59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 59

def obfuscate_hostname?(host)
  # Returns true if hostname obfuscation should be applied for a given host, based on hierarchy:
  # 1. Global setting for hostname obfuscation.
  return true if Setting[:obfuscate_inventory_hostnames] && !ForemanRhCloud.with_iop_smart_proxy?

  insights_client_setting = fact_value(host, 'insights_client::obfuscate_hostname_enabled')
  insights_client_setting = ActiveModel::Type::Boolean.new.cast(insights_client_setting)

  # 2. host fact reported by insights_client
  # 3. if neither of the above, don't obfuscate.
  insights_client_setting.nil? ? false : insights_client_setting
end

#obfuscate_ip(ip, ips_dict) ⇒ Object



156
157
158
159
160
161
162
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 156

def obfuscate_ip(ip, ips_dict)
  # Produce a new, unique obfuscated IP that is
  # numerically one greater than the highest existing obfuscated IP
  max_obfuscated = ips_dict.values.map { |v| IPAddr.new(v).to_i }.max || IPAddr.new('10.230.230.0').to_i

  IPAddr.new(max_obfuscated + 1, Socket::AF_INET).to_s
end

#obfuscate_ips?(host) ⇒ Boolean

Returns:

  • (Boolean)


99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 99

def obfuscate_ips?(host)
  # Returns true if IP obfuscation should be applied for a given host, based on hierarchy:
  # 1. Global setting for IP obfuscation.
  return true if Setting[:obfuscate_inventory_ips] && !ForemanRhCloud.with_iop_smart_proxy?

  insights_client_ipv4_setting = fact_value(host, 'insights_client::obfuscate_ipv4_enabled')
  insights_client_ipv6_setting = fact_value(host, 'insights_client::obfuscate_ipv6_enabled')

  cast_ipv4_setting = ActiveModel::Type::Boolean.new.cast(insights_client_ipv4_setting)
  cast_ipv6_setting = ActiveModel::Type::Boolean.new.cast(insights_client_ipv6_setting)

  # 2. The host's IPv4 or IPv6 obfuscation fact value is true
  # 3. If neither of the above, don't obfuscate.
  cast_ipv4_setting || cast_ipv6_setting || false
end

#obfuscated_ips(host) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 130

def obfuscated_ips(host)
  # Example format of `parsed_insights_array`:
  # [{"original": "192.168.1.10", "obfuscated": "10.230.230.1"},
  #  {"original": "192.168.1.11", "obfuscated": "10.230.230.2"}]
  begin
    parsed_insights_array = JSON.parse(fact_value(host, 'insights_client::obfuscated_ipv4') || '[]')
  rescue JSON::ParserError
    parsed_insights_array = []
  end

  # Create a new Hash to store the mapping from original IP addresses to their obfuscated versions.
  # where the 'original' IP is the key and the 'obfuscated' IP is the value.
  obfuscated_ips = Hash[
    parsed_insights_array.map { |ip_record| [ip_record['original'], ip_record['obfuscated']] }
  ]

  # Sets a default proc for the obfuscated_ips hash.
  # When a key is accessed that does not exist in the hash, this proc is called.
  # It assigns the result of obfuscate_ip(key, hash) to the missing key in the hash.
  # This ensures that any missing IP address key will be obfuscated and stored automatically.
  obfuscated_ips.default_proc = proc do |hash, key|
    hash[key] = obfuscate_ip(key, hash)
  end
  obfuscated_ips
end

#uuid_value(value) ⇒ Object



181
182
183
184
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 181

def uuid_value(value)
  uuid_match = UUID_REGEX.match(value)
  uuid_match&.to_s
end

#uuid_value!(value) ⇒ Object

Raises:

  • (Foreman::Exception)


186
187
188
189
190
191
# File 'lib/foreman_inventory_upload/generators/fact_helpers.rb', line 186

def uuid_value!(value)
  uuid = uuid_value(value)
  raise Foreman::Exception.new(N_('Value %{value} is not a valid UUID') % { value: value }) if value && uuid.empty?

  uuid
end