Skip to content

Commit

Permalink
Add option to specify ID of System/Manager/Chassis to modify (ansible…
Browse files Browse the repository at this point in the history
…#62921)

* add option to specify ID of System/Manager/Chassis to modify

* added version to deprecate() call

* fix merge TODOs to use new self.systems_uri variable
  • Loading branch information
billdodd authored and gundalow committed Oct 31, 2019
1 parent c3838b5 commit 4349ab5
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 38 deletions.
113 changes: 83 additions & 30 deletions lib/ansible/module_utils/redfish_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,24 @@
'OData-Version': '4.0'}
DELETE_HEADERS = {'accept': 'application/json', 'OData-Version': '4.0'}

DEPRECATE_MSG = 'Issuing a data modification command without specifying the '\
'ID of the target %(resource)s resource when there is more '\
'than one %(resource)s will use the first one in the '\
'collection. Use the `resource_id` option to specify the '\
'target %(resource)s ID'


class RedfishUtils(object):

def __init__(self, creds, root_uri, timeout, module):
def __init__(self, creds, root_uri, timeout, module, resource_id=None,
data_modification=False):
self.root_uri = root_uri
self.creds = creds
self.timeout = timeout
self.module = module
self.service_root = '/redfish/v1/'
self.resource_id = resource_id
self.data_modification = data_modification
self._init_session()

# The following functions are to send GET/POST/PATCH/DELETE requests
Expand Down Expand Up @@ -198,6 +207,16 @@ def _find_sessionservice_resource(self):
self.sessions_uri = sessions
return {'ret': True}

def _get_resource_uri_by_id(self, uris, id_prop):
for uri in uris:
response = self.get_request(self.root_uri + uri)
if response['ret'] is False:
continue
data = response['data']
if id_prop == data.get('Id'):
return uri
return None

def _find_systems_resource(self):
response = self.get_request(self.root_uri + self.service_root)
if response['ret'] is False:
Expand All @@ -214,6 +233,18 @@ def _find_systems_resource(self):
return {
'ret': False,
'msg': "ComputerSystem's Members array is either empty or missing"}
self.systems_uri = self.systems_uris[0]
if self.data_modification:
if self.resource_id:
self.systems_uri = self._get_resource_uri_by_id(self.systems_uris,
self.resource_id)
if not self.systems_uri:
return {
'ret': False,
'msg': "System resource %s not found" % self.resource_id}
elif len(self.systems_uris) > 1:
self.module.deprecate(DEPRECATE_MSG % {'resource': 'System'},
version='2.13')
return {'ret': True}

def _find_updateservice_resource(self):
Expand Down Expand Up @@ -245,16 +276,28 @@ def _find_chassis_resource(self):
data = response['data']
if 'Chassis' not in data:
return {'ret': False, 'msg': "Chassis resource not found"}
else:
chassis = data["Chassis"]["@odata.id"]
response = self.get_request(self.root_uri + chassis)
if response['ret'] is False:
return response
data = response['data']
for member in data[u'Members']:
chassis_service.append(member[u'@odata.id'])
self.chassis_uri_list = chassis_service
return {'ret': True}
chassis = data["Chassis"]["@odata.id"]
response = self.get_request(self.root_uri + chassis)
if response['ret'] is False:
return response
self.chassis_uri_list = [
i['@odata.id'] for i in response['data'].get('Members', [])]
if not self.chassis_uri_list:
return {'ret': False,
'msg': "Chassis Members array is either empty or missing"}
self.chassis_uri = self.chassis_uri_list[0]
if self.data_modification:
if self.resource_id:
self.chassis_uri = self._get_resource_uri_by_id(self.chassis_uri_list,
self.resource_id)
if not self.chassis_uri:
return {
'ret': False,
'msg': "Chassis resource %s not found" % self.resource_id}
elif len(self.chassis_uri_list) > 1:
self.module.deprecate(DEPRECATE_MSG % {'resource': 'Chassis'},
version='2.13')
return {'ret': True}

def _find_managers_resource(self):
response = self.get_request(self.root_uri + self.service_root)
Expand All @@ -263,16 +306,28 @@ def _find_managers_resource(self):
data = response['data']
if 'Managers' not in data:
return {'ret': False, 'msg': "Manager resource not found"}
else:
manager = data["Managers"]["@odata.id"]
response = self.get_request(self.root_uri + manager)
if response['ret'] is False:
return response
data = response['data']
for member in data[u'Members']:
manager_service = member[u'@odata.id']
self.manager_uri = manager_service
return {'ret': True}
manager = data["Managers"]["@odata.id"]
response = self.get_request(self.root_uri + manager)
if response['ret'] is False:
return response
self.manager_uri_list = [
i['@odata.id'] for i in response['data'].get('Members', [])]
if not self.manager_uri_list:
return {'ret': False,
'msg': "Managers Members array is either empty or missing"}
self.manager_uri = self.manager_uri_list[0]
if self.data_modification:
if self.resource_id:
self.manager_uri = self._get_resource_uri_by_id(self.manager_uri_list,
self.resource_id)
if not self.manager_uri:
return {
'ret': False,
'msg': "Manager resource %s not found" % self.resource_id}
elif len(self.manager_uri_list) > 1:
self.module.deprecate(DEPRECATE_MSG % {'resource': 'Manager'},
version='2.13')
return {'ret': True}

def get_logs(self):
log_svcs_uri_list = []
Expand Down Expand Up @@ -696,7 +751,7 @@ def manage_system_power(self, command):
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])
response = self.get_request(self.root_uri + self.systems_uri)
if response['ret'] is False:
return response
data = response['data']
Expand Down Expand Up @@ -1317,7 +1372,7 @@ def set_bios_default_settings(self):
key = "Bios"

# Search for 'key' entry and extract URI from it
response = self.get_request(self.root_uri + self.systems_uris[0])
response = self.get_request(self.root_uri + self.systems_uri)
if response['ret'] is False:
return response
result['ret'] = True
Expand Down Expand Up @@ -1350,7 +1405,7 @@ def set_one_time_boot_device(self, bootdevice, uefi_target, boot_next):
'msg': "bootdevice option required for SetOneTimeBoot"}

# Search for 'key' entry and extract URI from it
response = self.get_request(self.root_uri + self.systems_uris[0])
response = self.get_request(self.root_uri + self.systems_uri)
if response['ret'] is False:
return response
result['ret'] = True
Expand Down Expand Up @@ -1414,7 +1469,7 @@ def set_one_time_boot_device(self, bootdevice, uefi_target, boot_next):
}
}

response = self.patch_request(self.root_uri + self.systems_uris[0], payload)
response = self.patch_request(self.root_uri + self.systems_uri, payload)
if response['ret'] is False:
return response
return {'ret': True, 'changed': True}
Expand All @@ -1424,7 +1479,7 @@ def set_bios_attributes(self, attributes):
key = "Bios"

# Search for 'key' entry and extract URI from it
response = self.get_request(self.root_uri + self.systems_uris[0])
response = self.get_request(self.root_uri + self.systems_uri)
if response['ret'] is False:
return response
result['ret'] = True
Expand Down Expand Up @@ -1473,8 +1528,7 @@ def set_boot_order(self, boot_list):
return {'ret': False,
'msg': "boot_order list required for SetBootOrder command"}

# TODO(billdodd): change to self.systems_uri after PR 62921 merged
systems_uri = self.systems_uris[0]
systems_uri = self.systems_uri
response = self.get_request(self.root_uri + systems_uri)
if response['ret'] is False:
return response
Expand Down Expand Up @@ -1512,8 +1566,7 @@ def set_boot_order(self, boot_list):
return {'ret': True, 'changed': True, 'msg': "BootOrder set"}

def set_default_boot_order(self):
# TODO(billdodd): change to self.systems_uri after PR 62921 merged
systems_uri = self.systems_uris[0]
systems_uri = self.systems_uri
response = self.get_request(self.root_uri + systems_uri)
if response['ret'] is False:
return response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@
default: 10
type: int
version_added: '2.8'
resource_id:
required: false
description:
- The ID of the System, Manager or Chassis to modify
type: str
version_added: '2.10'
author: "Jose Delarosa (@jose-delarosa)"
'''
Expand All @@ -61,6 +67,7 @@
idrac_redfish_command:
category: Systems
command: CreateBiosConfigJob
resource_id: System.Embedded.1
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
Expand Down Expand Up @@ -137,7 +144,8 @@ def main():
baseuri=dict(required=True),
username=dict(required=True),
password=dict(required=True, no_log=True),
timeout=dict(type='int', default=10)
timeout=dict(type='int', default=10),
resource_id=dict()
),
supports_check_mode=False
)
Expand All @@ -152,9 +160,13 @@ def main():
# timeout
timeout = module.params['timeout']

# System, Manager or Chassis ID to modify
resource_id = module.params['resource_id']

# Build root URI
root_uri = "https://" + module.params['baseuri']
rf_utils = IdracRedfishUtils(creds, root_uri, timeout, module)
rf_utils = IdracRedfishUtils(creds, root_uri, timeout, module,
resource_id=resource_id, data_modification=True)

# Check that Category is valid
if category not in CATEGORY_COMMANDS_ALL:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@
- Timeout in seconds for URL requests to iDRAC controller
default: 10
type: int
resource_id:
required: false
description:
- The ID of the System, Manager or Chassis to modify
type: str
version_added: '2.10'
author: "Jose Delarosa (@jose-delarosa)"
'''
Expand All @@ -72,6 +78,7 @@
idrac_redfish_config:
category: Manager
command: SetManagerAttributes
resource_id: iDRAC.Embedded.1
manager_attribute_name: NTPConfigGroup.1.NTPEnable
manager_attribute_value: Enabled
baseuri: "{{ baseuri }}"
Expand All @@ -81,6 +88,7 @@
idrac_redfish_config:
category: Manager
command: SetManagerAttributes
resource_id: iDRAC.Embedded.1
manager_attribute_name: NTPConfigGroup.1.NTP1
manager_attribute_value: "{{ ntpserver1 }}"
baseuri: "{{ baseuri }}"
Expand All @@ -90,6 +98,7 @@
idrac_redfish_config:
category: Manager
command: SetManagerAttributes
resource_id: iDRAC.Embedded.1
manager_attribute_name: Time.1.Timezone
manager_attribute_value: "{{ timezone }}"
baseuri: "{{ baseuri }}"
Expand Down Expand Up @@ -168,7 +177,8 @@ def main():
password=dict(required=True, no_log=True),
manager_attribute_name=dict(default='null'),
manager_attribute_value=dict(default='null'),
timeout=dict(type='int', default=10)
timeout=dict(type='int', default=10),
resource_id=dict()
),
supports_check_mode=False
)
Expand All @@ -187,9 +197,13 @@ def main():
mgr_attributes = {'mgr_attr_name': module.params['manager_attribute_name'],
'mgr_attr_value': module.params['manager_attribute_value']}

# System, Manager or Chassis ID to modify
resource_id = module.params['resource_id']

# Build root URI
root_uri = "https://" + module.params['baseuri']
rf_utils = IdracRedfishUtils(creds, root_uri, timeout, module)
rf_utils = IdracRedfishUtils(creds, root_uri, timeout, module,
resource_id=resource_id, data_modification=True)

# Check that Category is valid
if category not in CATEGORY_COMMANDS_ALL:
Expand Down
21 changes: 19 additions & 2 deletions lib/ansible/modules/remote_management/redfish/redfish_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@
- properties of account service to update
type: dict
version_added: "2.10"
resource_id:
required: false
description:
- The ID of the System, Manager or Chassis to modify
type: str
version_added: "2.10"
author: "Jose Delarosa (@jose-delarosa)"
'''
Expand All @@ -122,6 +128,7 @@
redfish_command:
category: Systems
command: PowerGracefulRestart
resource_id: 437XR1138R2
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
Expand All @@ -130,6 +137,7 @@
redfish_command:
category: Systems
command: SetOneTimeBoot
resource_id: 437XR1138R2
bootdevice: "{{ bootdevice }}"
baseuri: "{{ baseuri }}"
username: "{{ username }}"
Expand All @@ -139,6 +147,7 @@
redfish_command:
category: Systems
command: SetOneTimeBoot
resource_id: 437XR1138R2
bootdevice: "UefiTarget"
uefi_target: "/0x31/0x33/0x01/0x01"
baseuri: "{{ baseuri }}"
Expand All @@ -149,6 +158,7 @@
redfish_command:
category: Systems
command: SetOneTimeBoot
resource_id: 437XR1138R2
bootdevice: "UefiBootNext"
boot_next: "Boot0001"
baseuri: "{{ baseuri }}"
Expand All @@ -159,6 +169,7 @@
redfish_command:
category: Chassis
command: IndicatorLedBlink
resource_id: 1U
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
Expand Down Expand Up @@ -278,6 +289,7 @@
redfish_command:
category: Manager
command: ClearLogs
resource_id: BMC
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
Expand Down Expand Up @@ -327,7 +339,8 @@ def main():
bootdevice=dict(),
timeout=dict(type='int', default=10),
uefi_target=dict(),
boot_next=dict()
boot_next=dict(),
resource_id=dict()
),
supports_check_mode=False
)
Expand All @@ -350,9 +363,13 @@ def main():
# timeout
timeout = module.params['timeout']

# System, Manager or Chassis ID to modify
resource_id = module.params['resource_id']

# Build root URI
root_uri = "https://" + module.params['baseuri']
rf_utils = RedfishUtils(creds, root_uri, timeout, module)
rf_utils = RedfishUtils(creds, root_uri, timeout, module,
resource_id=resource_id, data_modification=True)

# Check that Category is valid
if category not in CATEGORY_COMMANDS_ALL:
Expand Down
Loading

0 comments on commit 4349ab5

Please sign in to comment.