Is there an "easy" way to allow casing (upcasing) in Foreman?

I believe foreman normalizes and downcases every host/fqdn. Is there an easy way to allow for upcased hostnames?

As far as I can tell, unfortunately no.

The host name validation is defined by this regular expression here:

Putting that into the Ruby regular expression tester, I don’t think it allows for any capitals:

Thats kinda what I thought. Plus looks like there is downcasing and normalizing in other bits of code.

Ultimately, Im trying to figure out how in the world I can pass a fact into:

The problem is that since all hosts in foreman are downcased, the name it sends to the proxy is also downcased. Except we have minions/hosts that are upcased as well. So of course it fails because the salt master has no idea who the minion with the downcased name is. Been trying to figure it out for hours if not days, but having a heck of a time trying to figure out where it gets the options var from the initialize block:

Anywho, Im doing some monkey patching with Foreman, so I didnt want to really ask on here because its probably so far out of the ordinary, I didnt want to waste anyones times.

Thanks for the reply!

It goes through remote execution here[1] with salt-specific overrides here[2]. Then there’s a lot of behind the scenes machinery that transfers it to the proxy, but what you set there should be available in @options.

[1] - foreman_remote_execution/app/models/remote_execution_provider.rb at ca0645a03a3181d3a05ab73fc2ac440abac99a7a · theforeman/foreman_remote_execution · GitHub
[2] - foreman_salt/app/models/foreman_salt/salt_provider.rb at master · theforeman/foreman_salt · GitHub

Thank you again for your reply.

I see that host gets set in [1] here? foreman_remote_execution/app/lib/actions/remote_execution/run_host_job.rb at master · theforeman/foreman_remote_execution · GitHub
At least I think… I havent touched Ruby in about 7 years, so trying to refresh my brain.

However, Im not quite sure I understand how to literally pass a fact value into this? Does the remote_execution_provider, at this point in the chain, even know what a fact is? It seems like I would need to possibly add additional def’s to pull them into this all. If this is outside of your assistance, just ignore me :slight_smile: . Like I said, I know what Im trying to do here is way way out of the ordinary and probably doesnt even fall under any sort of reasonable support request. In the meantime, Im trying to find if there is some other easier way to handle this, maybe on the salt master side with -E regex’s to downcase the name:

def generate_command
  saltfile_path = ::Proxy::Salt::Plugin.settings[:saltfile]
  command = %w[salt --show-jid]
  command << "--saltfile=#{saltfile_path}" if File.file?(saltfile_path)
  command << '-E'
  raw_minion_id = @options['name'] 
  escaped_minion_id = raw_minion_id.gsub('.', '\.')
  regex_target = "^(?i)#{escaped_minion_id}$"
  command << regex_target
  command << 'state.template_str'
  command << @options['script']
  command
end

But thats causing its own issues… Thanks again for taking the time to at least point me in some sort of direction!

Yes, but that’s pretty far away from where you want to get the value :confused:

A little bit, but I can at least try pointing you in the right direction

Luckily, it does. The proxy_command_options method gets the host in question passed in as an argument and you can pull the facts from that. Changing the method to something like this should do the trick

def proxy_command_options(template_invocation, host)
  fact_name = 'disks::vda::size_bytes' # This fact comes from puppet
  fact = host.facts[fact_name]
  super(template_invocation, host).merge(name: host.name, disk_size: fact)
end

Then on the proxy side, you should be able to access it with @options['disk_size']

2 Likes

This is absolutely amazing. Thank you so much for the guidance and direction. Been setting up Foreman at various places for almost 10 years now, and still doing it today. In this case, a 90,000 node salt infrastructure, to replace SaltStack UI. Always amazes me what I can do with this thing, and always appreciate the help and work you all continue to do!

3 Likes

This was the final answer. Its working perfectly now.
(The salt module didnt allow for super)

    def proxy_command_options(template_invocation, host)
      fact_name = 'id'
      fact = host.facts[fact_name]

      unless fact
        raise "Missing required fact '#{fact_name}' for host '#{host.name}'"
      end

      {
        proxy_operation_name: proxy_operation_name,
        time_to_pickup: time_to_pickup(template_invocation.job_invocation, host),
      }.merge(proxy_command_provider_inputs(template_invocation))
        .merge(name: host.name, id: fact)
    end

Thanks again.

1 Like