From b58b5b4294f277b930f744925cc7597ed89a6829 Mon Sep 17 00:00:00 2001 From: Susumu Sakamoto Date: Fri, 30 Jan 2026 04:50:53 +0000 Subject: [PATCH] Fixes #38973 - SSH API of BMC now resolves FQDN to IP Previously, Smart Proxy's ip() method for SSH API of BMC directly returned the :host parameter to Foreman. Now, if :host is an FQDN, it is resolved to an IP address before being returned. If :host is already an IP, it's returned directly. Co-Authored-By: Yusuke Hirota --- modules/bmc/ssh.rb | 13 ++++++++++++- test/bmc/bmc_api_ssh_test.rb | 32 +++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/modules/bmc/ssh.rb b/modules/bmc/ssh.rb index 8468a92b1..c1e9e9031 100644 --- a/modules/bmc/ssh.rb +++ b/modules/bmc/ssh.rb @@ -1,3 +1,6 @@ +require 'ipaddr' +require 'resolv' + module Proxy module BMC class SSH < Base @@ -62,7 +65,15 @@ def powercycle end def ip - host + IPAddr.new(host).to_s + rescue IPAddr::InvalidAddressError + begin + logger.debug("Host '#{host}' is not an IP address, attempting to resolve as FQDN.") + Resolv.getaddress(host) + rescue Resolv::ResolvError => e + logger.warn("Failed to resolve FQDN '#{host}': #{e.class} - #{e.message}") + '' + end end # the following are dummy implementations diff --git a/test/bmc/bmc_api_ssh_test.rb b/test/bmc/bmc_api_ssh_test.rb index 97dd84ee2..0c8fb00bb 100644 --- a/test/bmc/bmc_api_ssh_test.rb +++ b/test/bmc/bmc_api_ssh_test.rb @@ -2,6 +2,7 @@ require 'json' require 'bmc/bmc_api' require 'bmc/ssh' +require 'bmc/bmc_plugin' ENV['RACK_ENV'] = 'test' @@ -47,10 +48,35 @@ def test_powercycle assert_equal 200, last_response.status end - def test_lan_ip - Proxy::BMC::SSH.any_instance.expects(:ip).returns('') - get "/#{@host}/lan/ip", @args + def test_lan_ip_when_host_is_ip + host = "192.168.1.1" + get "/#{host}/lan/ip", @args assert_equal 200, last_response.status + assert_equal host, JSON.parse(last_response.body)["result"] + end + + def test_lan_ip_when_host_is_ipv6 + host = '2001:db8::1' + get "/#{host}/lan/ip", @args + assert_equal 200, last_response.status + assert_equal host, JSON.parse(last_response.body)['result'] + end + + def test_lan_ip_when_host_is_resolvable_fqdn + host = "resolvable.example.com" + resolved_ip = "192.168.1.2" + Resolv.expects(:getaddress).with(host).returns(resolved_ip) + get "/#{host}/lan/ip", @args + assert_equal 200, last_response.status + assert_equal resolved_ip, JSON.parse(last_response.body)["result"] + end + + def test_lan_ip_when_host_is_unresolvable_fqdn + host = "unresolvable.example.com" + Resolv.expects(:getaddress).with(host).raises(Resolv::ResolvError.new("no address for #{host}")) + get "/#{host}/lan/ip", @args + assert_equal 200, last_response.status + assert_equal "", JSON.parse(last_response.body)["result"] end def test_lan_mac