Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix power command ResetType mapping logic #59927

Merged
merged 2 commits into from
Sep 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
bugfixes:
- redfish_command - fix power ResetType mapping logic (https://github.com/ansible/ansible/issues/59804)
103 changes: 73 additions & 30 deletions lib/ansible/module_utils/redfish_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,48 +628,91 @@ def manage_indicator_led(self, command):

return result

def _map_reset_type(self, reset_type, allowable_values):
equiv_types = {
'On': 'ForceOn',
'ForceOn': 'On',
'ForceOff': 'GracefulShutdown',
'GracefulShutdown': 'ForceOff',
'GracefulRestart': 'ForceRestart',
'ForceRestart': 'GracefulRestart'
}

if reset_type in allowable_values:
return reset_type
if reset_type not in equiv_types:
return reset_type
mapped_type = equiv_types[reset_type]
if mapped_type in allowable_values:
return mapped_type
return reset_type

def manage_system_power(self, command):
key = "Actions"
reset_type_values = ['On', 'ForceOff', 'GracefulShutdown',
'GracefulRestart', 'ForceRestart', 'Nmi',
'ForceOn', 'PushPowerButton', 'PowerCycle']

# Search for 'key' entry and extract URI from it
# command should be PowerOn, PowerForceOff, etc.
if not command.startswith('Power'):
return {'ret': False, 'msg': 'Invalid Command (%s)' % command}
reset_type = command[5:]

# map Reboot to a ResetType that does a reboot
if reset_type == 'Reboot':
reset_type = 'GracefulRestart'

if reset_type not in reset_type_values:
return {'ret': False, 'msg': 'Invalid Command (%s)' % command}

# read the system resource and get the current power state
response = self.get_request(self.root_uri + self.systems_uris[0])
if response['ret'] is False:
return response
data = response['data']
power_state = data["PowerState"]
power_state = data.get('PowerState')

if power_state == "On" and command == 'PowerOn':
# if power is already in target state, nothing to do
if power_state == "On" and reset_type in ['On', 'ForceOn']:
return {'ret': True, 'changed': False}

if power_state == "Off" and command in ['PowerGracefulShutdown', 'PowerForceOff']:
if power_state == "Off" and reset_type in ['GracefulShutdown', 'ForceOff']:
return {'ret': True, 'changed': False}

reset_action = data[key]["#ComputerSystem.Reset"]
action_uri = reset_action["target"]
allowable_vals = reset_action.get("ResetType@Redfish.AllowableValues", [])
restart_cmd = "GracefulRestart"
if "ForceRestart" in allowable_vals and "GracefulRestart" not in allowable_vals:
restart_cmd = "ForceRestart"

# Define payload accordingly
if command == "PowerOn":
payload = {'ResetType': 'On'}
elif command == "PowerForceOff":
payload = {'ResetType': 'ForceOff'}
elif command == "PowerForceRestart":
payload = {'ResetType': "ForceRestart"}
elif command == "PowerGracefulRestart":
payload = {'ResetType': 'GracefulRestart'}
elif command == "PowerGracefulShutdown":
payload = {'ResetType': 'GracefulShutdown'}
elif command == "PowerReboot":
if power_state == "On":
payload = {'ResetType': restart_cmd}
else:
payload = {'ResetType': "On"}
else:
return {'ret': False, 'msg': 'Invalid Command'}
# get the #ComputerSystem.Reset Action and target URI
if key not in data or '#ComputerSystem.Reset' not in data[key]:
return {'ret': False, 'msg': 'Action #ComputerSystem.Reset not found'}
reset_action = data[key]['#ComputerSystem.Reset']
if 'target' not in reset_action:
return {'ret': False,
'msg': 'target URI missing from Action #ComputerSystem.Reset'}
action_uri = reset_action['target']

# get AllowableValues from ActionInfo
allowable_values = None
if '@Redfish.ActionInfo' in reset_action:
action_info_uri = reset_action.get('@Redfish.ActionInfo')
response = self.get_request(self.root_uri + action_info_uri)
if response['ret'] is True:
data = response['data']
if 'Parameters' in data:
params = data['Parameters']
for param in params:
if param.get('Name') == 'ResetType':
allowable_values = param.get('AllowableValues')
break

# fallback to @Redfish.AllowableValues annotation
if allowable_values is None:
allowable_values = reset_action.get('ResetType@Redfish.AllowableValues', [])

# map ResetType to an allowable value if needed
if reset_type not in allowable_values:
reset_type = self._map_reset_type(reset_type, allowable_values)

# define payload
payload = {'ResetType': reset_type}

# POST to Action URI
response = self.post_request(self.root_uri + action_uri, payload)
if response['ret'] is False:
return response
Expand Down