Skip to content

Commit a5780bc

Browse files
spesnova717stejskalleos
authored andcommitted
Fixes #38914 - Use ETag-aware patch_if_match for Redfish operations
Some Redfish implementations reject PATCH requests without If-Match. This change updates boot device operations to use patch_if_match, enabling ETag-based conditional PATCH when needed.
1 parent b16c32a commit a5780bc

3 files changed

Lines changed: 133 additions & 8 deletions

File tree

bundler.d/bmc.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
group :bmc do
22
gem 'rubyipmi', '>= 0.12.1'
3-
gem 'redfish_client', '>= 0.6.0'
3+
gem 'redfish_client', '>= 0.8.0'
44
end

modules/bmc/redfish.rb

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,12 @@ def bootdevice=(args = { :device => nil, :reboot => false, :persistent => false
131131
'disk' => 'Hdd',
132132
'pxe' => 'Pxe' }
133133

134-
system.patch(
135-
payload: {
136-
'Boot' => {
137-
'BootSourceOverrideTarget' => devmap[args[:device]],
138-
'BootSourceOverrideEnabled' => args[:persistent] ? 'Enabled' : 'Once',
139-
},
140-
})
134+
system.patch_if_match({
135+
'Boot' => {
136+
'BootSourceOverrideTarget' => devmap[args[:device]],
137+
'BootSourceOverrideEnabled' => args[:persistent] ? 'Enabled' : 'Once',
138+
},
139+
})
141140
powercycle if args[:reboot]
142141
end
143142

test/bmc/bmc_redfish_test.rb

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,130 @@ def test_redfish_provider_reboot
3535
to_return(status: 200, body: JSON.generate({}))
3636
assert @bmc.powerreboot
3737
end
38+
39+
def test_bootdevice_pxe_uses_patch_if_match
40+
# Test that bootdevice uses patch_if_match for PXE boot
41+
system_mock = mock('system')
42+
43+
system_mock.expects(:patch_if_match).with(
44+
'Boot' => {
45+
'BootSourceOverrideTarget' => 'Pxe',
46+
'BootSourceOverrideEnabled' => 'Once',
47+
}
48+
).returns(true)
49+
50+
@bmc.expects(:system).returns(system_mock)
51+
@bmc.expects(:powercycle).never
52+
53+
result = @bmc.bootdevice = { :device => 'pxe', :reboot => false, :persistent => false }
54+
assert_not_nil result
55+
end
56+
57+
def test_bootdevice_disk_persistent_uses_patch_if_match
58+
# Test that bootdevice uses patch_if_match with persistent boot
59+
system_mock = mock('system')
60+
61+
system_mock.expects(:patch_if_match).with(
62+
'Boot' => {
63+
'BootSourceOverrideTarget' => 'Hdd',
64+
'BootSourceOverrideEnabled' => 'Enabled',
65+
}
66+
).returns(true)
67+
68+
@bmc.expects(:system).returns(system_mock)
69+
@bmc.expects(:powercycle).never
70+
71+
result = @bmc.bootdevice = { :device => 'disk', :reboot => false, :persistent => true }
72+
assert_not_nil result
73+
end
74+
75+
def test_bootdevice_with_reboot
76+
# Test bootdevice with reboot option
77+
system_mock = mock('system')
78+
79+
system_mock.expects(:patch_if_match).with(
80+
'Boot' => {
81+
'BootSourceOverrideTarget' => 'Pxe',
82+
'BootSourceOverrideEnabled' => 'Enabled',
83+
}
84+
).returns(true)
85+
86+
@bmc.expects(:system).returns(system_mock)
87+
@bmc.expects(:powercycle).once
88+
89+
result = @bmc.bootdevice = { :device => 'pxe', :reboot => true, :persistent => true }
90+
assert_not_nil result
91+
end
92+
93+
def test_bootpxe_calls_bootdevice
94+
# Test that convenience method bootpxe works
95+
system_mock = mock('system')
96+
97+
system_mock.expects(:patch_if_match).with(
98+
'Boot' => {
99+
'BootSourceOverrideTarget' => 'Pxe',
100+
'BootSourceOverrideEnabled' => 'Once',
101+
}
102+
).returns(true)
103+
104+
@bmc.expects(:system).returns(system_mock)
105+
@bmc.expects(:powercycle).never
106+
107+
result = @bmc.bootpxe(false, false)
108+
assert_not_nil result
109+
end
110+
111+
def test_bootdisk_calls_bootdevice
112+
# Test that convenience method bootdisk works
113+
system_mock = mock('system')
114+
115+
system_mock.expects(:patch_if_match).with(
116+
'Boot' => {
117+
'BootSourceOverrideTarget' => 'Hdd',
118+
'BootSourceOverrideEnabled' => 'Once',
119+
}
120+
).returns(true)
121+
122+
@bmc.expects(:system).returns(system_mock)
123+
@bmc.expects(:powercycle).never
124+
125+
result = @bmc.bootdisk(false, false)
126+
assert_not_nil result
127+
end
128+
129+
def test_bootbios_calls_bootdevice
130+
# Test that convenience method bootbios works
131+
system_mock = mock('system')
132+
133+
system_mock.expects(:patch_if_match).with(
134+
'Boot' => {
135+
'BootSourceOverrideTarget' => 'BiosSetup',
136+
'BootSourceOverrideEnabled' => 'Once',
137+
}
138+
).returns(true)
139+
140+
@bmc.expects(:system).returns(system_mock)
141+
@bmc.expects(:powercycle).never
142+
143+
result = @bmc.bootbios(false, false)
144+
assert_not_nil result
145+
end
146+
147+
def test_bootcdrom_calls_bootdevice
148+
# Test that convenience method bootcdrom works
149+
system_mock = mock('system')
150+
151+
system_mock.expects(:patch_if_match).with(
152+
'Boot' => {
153+
'BootSourceOverrideTarget' => 'Cd',
154+
'BootSourceOverrideEnabled' => 'Once',
155+
}
156+
).returns(true)
157+
158+
@bmc.expects(:system).returns(system_mock)
159+
@bmc.expects(:powercycle).never
160+
161+
result = @bmc.bootcdrom(false, false)
162+
assert_not_nil result
163+
end
38164
end

0 commit comments

Comments
 (0)