Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ The following parameters are available in the `ipmi::network` defined type:
* [`gateway`](#-ipmi--network--gateway)
* [`type`](#-ipmi--network--type)
* [`lan_channel`](#-ipmi--network--lan_channel)
* [`interface_type`](#-ipmi--network--interface_type)

##### <a name="-ipmi--network--ip"></a>`ip`

Expand Down Expand Up @@ -170,6 +171,17 @@ Defaults to the first detected lan channel, starting at 1 ending at 11

Default value: `undef`

##### <a name="-ipmi--network--interface_type"></a>`interface_type`

Data type: `Optional[Enum['dedicated', 'shared', 'failover']]`

Controls the NIC selection mode for the BMC.
Supported values: 'dedicated', 'shared', 'failover'.
Only applied when the manufacturer is known (Supermicro or Dell).
Leave undef to skip interface type configuration.

Default value: `undef`

### <a name="ipmi--snmp"></a>`ipmi::snmp`

Manage SNMP community strings
Expand Down
66 changes: 60 additions & 6 deletions manifests/network.pp
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,24 @@
# @param lan_channel
# Controls the lan channel of the IPMI network to be configured.
# Defaults to the first detected lan channel, starting at 1 ending at 11
# @param interface_type
# Controls the NIC selection mode for the BMC.
# Supported values: 'dedicated', 'shared', 'failover'.
# Only applied when the manufacturer is known (Supermicro or Dell).
# Leave undef to skip interface type configuration.
#
define ipmi::network (
Stdlib::IP::Address $ip = '0.0.0.0',
Stdlib::IP::Address $netmask = '255.255.255.0',
Stdlib::IP::Address $gateway = '0.0.0.0',
Enum['dhcp', 'static'] $type = 'dhcp',
Optional[Integer] $lan_channel = undef
Stdlib::IP::Address $ip = '0.0.0.0',
Stdlib::IP::Address $netmask = '255.255.255.0',
Stdlib::IP::Address $gateway = '0.0.0.0',
Enum['dhcp', 'static'] $type = 'dhcp',
Optional[Integer] $lan_channel = undef,
Optional[Enum['dedicated', 'shared', 'failover']] $interface_type = undef,
) {
require ipmi::install

$_real_lan_channel = $lan_channel ? {
undef => $ipmi::default_channel,
undef => $ipmi::default_channel,
default => $lan_channel,
}

Expand Down Expand Up @@ -62,4 +68,52 @@
'Subnet Mask' | sed -e 's/.* : //g')\" != \"${netmask}\"",
}
}

if $interface_type != undef {
$_manufacturer = $facts.dig('ipmitool_mc_info', 'Manufacturer Name')
if $_manufacturer != undef {
case $_manufacturer {
'Supermicro': {
$_raw_check = '0x30 0x70 0x0c'
case $interface_type {
'dedicated': { $_iface_code = 0 }
'shared': { $_iface_code = 1 }
'failover': { $_iface_code = 2 }
default: { $_iface_code = undef }
}
if $_iface_code != undef {
# lint:ignore:140chars
exec { "ipmi_set_interface_type_${_real_lan_channel}":
command => "/usr/bin/ipmitool raw ${_raw_check} 1 ${_iface_code}",
onlyif => "/usr/bin/test $(/usr/bin/ipmitool raw ${_raw_check} 0) -ne ${_iface_code}",
}
# lint:endignore
}
}
'Dell': {
$_raw_set = '0x30 0x24'
$_raw_check = '0x30 0x25'
case $interface_type {
'dedicated': { $_iface_code = 2 }
'shared': { $_iface_code = 0 }
'failover': { $_iface_code = 1 }
default: { $_iface_code = undef }
}
if $_iface_code != undef {
# lint:ignore:140chars
exec { "ipmi_set_interface_type_${_real_lan_channel}":
command => "/usr/bin/ipmitool raw ${_raw_set} ${_iface_code}",
onlyif => "/usr/bin/test $(/usr/bin/ipmitool raw ${_raw_check}) -ne ${_iface_code}",
}
# lint:endignore
}
}
default: {
# lint:ignore:140chars
warning("${_manufacturer} does not have interface type behavior defined in this module. Can you submit it?")
# lint:endignore
}
}
}
}
}
120 changes: 113 additions & 7 deletions spec/defines/ipmi_network_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@
describe 'ipmi::network', type: :define do
on_supported_os.each do |os, facts|
context "on #{os}" do
let(:title) { 'example' }

# Base facts without manufacturer — used by most existing tests.

Check failure on line 10 in spec/defines/ipmi_network_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Style/AsciiComments: Use only ascii symbols in comments. (https://rubystyle.guide#english-comments)
# Interface type tests override this via subject-level let(:facts).
let(:facts) do
facts.merge(
{
ipmitool_mc_info: { IPMI_Puppet_Service_Recommend: 'running' },
ipmi: { default: { channel: 1 } }
ipmi: { default: { channel: 1 } },
}
)
end
let(:title) { 'example' }

describe 'when deploying as dhcp with minimal params' do
let(:params) do
{
type: 'dhcp',
}
end
let(:params) { { type: 'dhcp' } }

it { is_expected.to contain_exec('ipmi_set_dhcp_1') }
it { is_expected.not_to contain_exec('ipmi_set_interface_type_1') }
end

describe 'when deploying as dhcp with all params' do
Expand All @@ -37,6 +37,7 @@
end

it { is_expected.to contain_exec('ipmi_set_dhcp_1') }
it { is_expected.not_to contain_exec('ipmi_set_interface_type_1') }
end

describe 'when deploying as static with minimal params' do
Expand All @@ -52,6 +53,7 @@
it { is_expected.to contain_exec('ipmi_set_static_1').that_notifies('Exec[ipmi_set_ipaddr_1]') }
it { is_expected.to contain_exec('ipmi_set_static_1').that_notifies('Exec[ipmi_set_defgw_1]') }
it { is_expected.to contain_exec('ipmi_set_static_1').that_notifies('Exec[ipmi_set_netmask_1]') }
it { is_expected.not_to contain_exec('ipmi_set_interface_type_1') }
end

describe 'when deploying as static with all params' do
Expand All @@ -68,6 +70,110 @@
it { is_expected.to contain_exec('ipmi_set_static_2').that_notifies('Exec[ipmi_set_ipaddr_2]') }
it { is_expected.to contain_exec('ipmi_set_static_2').that_notifies('Exec[ipmi_set_defgw_2]') }
it { is_expected.to contain_exec('ipmi_set_static_2').that_notifies('Exec[ipmi_set_netmask_2]') }
it { is_expected.not_to contain_exec('ipmi_set_interface_type_2') }
end

describe 'interface_type' do
# Shared params for all interface_type tests — type itself is irrelevant

Check failure on line 77 in spec/defines/ipmi_network_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Style/AsciiComments: Use only ascii symbols in comments. (https://rubystyle.guide#english-comments)
# to interface configuration, so use dhcp to keep tests focused.
let(:base_params) { { type: 'dhcp', lan_channel: 1 } }

describe 'when manufacturer fact is absent' do
let(:params) { base_params.merge(interface_type: 'dedicated') }

# ipmitool_mc_info present but no Manufacturer Name key
it { is_expected.not_to contain_exec('ipmi_set_interface_type_1') }
end

describe 'when manufacturer is unknown' do
let(:facts) do
facts.merge(
{
ipmitool_mc_info: {
IPMI_Puppet_Service_Recommend: 'running',
'Manufacturer Name' => 'HPE',
},
ipmi: { default: { channel: 1 } },
}
)
end
let(:params) { base_params.merge(interface_type: 'dedicated') }

it { is_expected.not_to contain_exec('ipmi_set_interface_type_1') }
it { is_expected.to compile.with_warnings }
end

describe 'Supermicro' do
let(:facts) do
facts.merge(
{
ipmitool_mc_info: {
IPMI_Puppet_Service_Recommend: 'running',
'Manufacturer Name' => 'Supermicro',
},
ipmi: { default: { channel: 1 } },
}
)
end

{ 'dedicated' => 0, 'shared' => 1, 'failover' => 2 }.each do |iface_type, code|
describe "interface_type => #{iface_type}" do
let(:params) { base_params.merge(interface_type: iface_type) }

it { is_expected.to contain_exec('ipmi_set_interface_type_1')

Check failure on line 123 in spec/defines/ipmi_network_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Layout/MultilineBlockLayout: Block body expression is on the same line as the block start.
.with_command("/usr/bin/ipmitool raw 0x30 0x70 0x0c 1 #{code}")

Check failure on line 124 in spec/defines/ipmi_network_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Layout/DotPosition: Place the . on the previous line, together with the method call receiver. (https://rubystyle.guide#consistent-multi-line-chains)
.with_onlyif("/usr/bin/test $(/usr/bin/ipmitool raw 0x30 0x70 0x0c 0) -ne #{code}") }

Check failure on line 125 in spec/defines/ipmi_network_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Layout/BlockEndNewline: Expression at 125, 101 should be on its own line.

Check failure on line 125 in spec/defines/ipmi_network_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Layout/DotPosition: Place the . on the previous line, together with the method call receiver. (https://rubystyle.guide#consistent-multi-line-chains)
end
end
end

describe 'Dell' do
let(:facts) do
facts.merge(
{
ipmitool_mc_info: {
IPMI_Puppet_Service_Recommend: 'running',
'Manufacturer Name' => 'Dell',
},
ipmi: { default: { channel: 1 } },
}
)
end

{ 'dedicated' => 2, 'shared' => 0, 'failover' => 1 }.each do |iface_type, code|
describe "interface_type => #{iface_type}" do
let(:params) { base_params.merge(interface_type: iface_type) }

it { is_expected.to contain_exec('ipmi_set_interface_type_1')

Check failure on line 147 in spec/defines/ipmi_network_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Layout/MultilineBlockLayout: Block body expression is on the same line as the block start.
.with_command("/usr/bin/ipmitool raw 0x30 0x24 #{code}")

Check failure on line 148 in spec/defines/ipmi_network_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Layout/DotPosition: Place the . on the previous line, together with the method call receiver. (https://rubystyle.guide#consistent-multi-line-chains)
.with_onlyif("/usr/bin/test $(/usr/bin/ipmitool raw 0x30 0x25) -ne #{code}") }

Check failure on line 149 in spec/defines/ipmi_network_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Layout/BlockEndNewline: Expression at 149, 94 should be on its own line.

Check failure on line 149 in spec/defines/ipmi_network_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Layout/DotPosition: Place the . on the previous line, together with the method call receiver. (https://rubystyle.guide#consistent-multi-line-chains)
end
end
end

describe 'when interface_type is undef' do
let(:facts) do
facts.merge(
{
ipmitool_mc_info: {
IPMI_Puppet_Service_Recommend: 'running',
'Manufacturer Name' => 'Supermicro',
},
ipmi: { default: { channel: 1 } },
}
)
end
let(:params) { base_params }

# Manufacturer present but interface_type not requested — no exec created
it { is_expected.not_to contain_exec('ipmi_set_interface_type_1') }
end

describe 'invalid interface_type value' do
let(:params) { base_params.merge(interface_type: 'bonded') }

it { is_expected.to compile.and_raise_error(%r{interface_type}) }
end
end
end
end
Expand Down
Loading