Start a Conversation

Solved!

Go to Solution

1 Rookie

 • 

7 Posts

68

July 9th, 2024 11:33

Use Redfish to change RaidStatus of a physical disk

Hi,

NVME's in a new r660xs with H965i controller are delivered with those NVME's set to "Non-RAID":

I don't know why this is, but I need to create a RAID array on this server and to achieve that, I need to manually configure each disk to RAID, which takes 3 minutes per disk and a lot of clicking as each change results in a "job". While that runs, the other disk pull down menu's are greyed out....

We like to configure our servers using Redfish and I fail to find how I can change this setting on a disk. What worries me is that in documentation I read that this is GET and the setting is readonly. I find it hard to believe that there is no way to configure this using RedFish.

Who knows what I can do?
I stubbornly tried to write some code using Python Redfish and it shows no error:

# I have these two functions:def get_disks(self):response = wait_until(lambda: self.rf_session.conn.get(f'/redfish/v1/Systems/System.Embedded.1/Storage/{self.get_raid_controller()}'),lambda x: len(x.dict.get('Drives')) >= 1)disks = []for drive in response.dict.get('Drives'):properties = self.rf_session.conn.get(drive.get('@odata.id')).dictdisks.append({'DiskID': properties.get('Id'),'Name': properties.get('MediaType') + ':' + re.findall(r'\d:\d:\d', properties.get('Name'))[0],'PartNumber': properties.get('Model'),'SerialNumber': properties.get('SerialNumber'),'Size': f"{int(round(float(properties.get('CapacityBytes'))/1000000000))} GB",'RaidStatus': properties.get('Oem', {}).get('Dell', {}).get('DellPhysicalDisk', {}).get('RaidStatus')})sorted_disks = sorted(disks, key=lambda d: d['DiskID'])return sorted_disksdef change_physical_disk_raid_status(self, disk):disk_id = disk['DiskID']update_url = f"/redfish/v1/Systems/System.Embedded.1/Storage/{self.get_raid_controller()}/Drives/{disk_id}/Oem/Dell/DellDrives/{disk_id}"payload = {'RaidStatus': 'Ready'}self.rf_session.conn.patch(update_url, body=payload)print(f"Updated {disk_id} RaidStatus to Ready")# I left out the get_raid_controller_name function and a lot of other, this is how I use these functions:raid_controller_name = bmc.get_raid_controller_name()if raid_controller_name == 'PERC H965i Front':print(f'  - {raid_controller_name} found, check if the disks are configured as RAID or not')for disk in physical_disks:if disk['RaidStatus'] != 'Ready':print(f"   - Changing {disk['Name']} which is {disk['RaidStatus']}")bmc.change_physical_disk_raid_status(disk)

When I execute this against the Redfish API on the server from which I took the above screenshot (with only disk 7 in Non-RAID status, I mean):

Collect the physical disks from the device.For max 600 seconds check every 30 seconds until '<function dell.get_disks.<locals>.<lambda> at 0x7f71ae9c3240>' equals <function dell.get_disks.<locals>.<lambda> at 0x7f71ae9c1bc0>Try number: 0...Check virtual disks:- Check RAID controller- PERC H965i Front found, check if the disks are configured as RAID or not- Changing SSD:0:1:7 which is NonRAIDUpdated Disk.Bay.7:Enclosure.Internal.0-1:RAID.SL.5-1 RaidStatus to Ready

Now, I don't check `response` for the status code, but the fact it doesn't break surprises me as I normally run into "this variable can't be set" or whatever the exact error message is when I throw whatever patch at the wrong place. I expected that this object would return something similar.

Anyway, I don't really care about a missing error, but the setting isn't updated when I run this... So, does anyone know how I can automate this?

Moderator

 • 

3.7K Posts

July 9th, 2024 17:45

Hello,

 

I'm not too familiar with scripting Redfish.

I did find this. Maybe it could work for you:

 

https://dell.to/3VXrUij

- name: Convert physical disk to RAID

dellemc.openmanage.idrac_redfish_storage_controller:

   baseuri: "192.168.0.1:443"

   username: "user_name"

   password: "user_password"

   ca_path: "/path/to/ca_cert.pem"

   command: "ConvertToRAID"

   target: "Disk.Bay.0:Enclosure.Internal.0-1:RAID.Slot.1-1"

tags:

   - convert-raid

 

1 Rookie

 • 

7 Posts

July 9th, 2024 13:50

Excuse me for those horrible text field in my comment. I tried to include code... I don't know why it's malformed like this. I can't edit my post. So, I will try to paste the code again:

These two functions:
  def get_disks(self):
    response = wait_until(lambda: self.rf_session.conn.get(f'/redfish/v1/Systems/System.Embedded.1/Storage/{self.get_raid_controller()}'),
                          lambda x: len(x.dict.get('Drives')) >= 1)
    disks = []
    for drive in response.dict.get('Drives'):
      properties = self.rf_session.conn.get(drive.get('@odata.id')).dict
      disks.append({
        'DiskID': properties.get('Id'),
        'Name': properties.get('MediaType') + ':' + re.findall(r'\d:\d:\d', properties.get('Name'))[0],
        'PartNumber': properties.get('Model'),
        'SerialNumber': properties.get('SerialNumber'),
        'Size': f"{int(round(float(properties.get('CapacityBytes'))/1000000000))} GB",
        'RaidStatus': properties.get('Oem', {}).get('Dell', {}).get('DellPhysicalDisk', {}).get('RaidStatus')
      })
    sorted_disks = sorted(disks, key=lambda d: d['DiskID'])
    return sorted_disks


  def change_physical_disk_raid_status(self, disk):
    disk_id = disk['DiskID']
    update_url = f"/redfish/v1/Systems/System.Embedded.1/Storage/{self.get_raid_controller()}/Drives/{disk_id}/Oem/Dell/DellDrives/{disk_id}"
    payload = {
      'RaidStatus': 'Ready'
    }
    self.rf_session.conn.patch(update_url, body=payload)
    print(f"Updated {disk_id} RaidStatus to Ready")

This code uses it:

  print(f'- Check RAID controller')
  raid_controller_name = bmc.get_raid_controller_name()
  if raid_controller_name == 'PERC H965i Front':
    print(f'  - {raid_controller_name} found, check if the disks are configured as RAID or not')
    for disk in physical_disks:
      if disk['RaidStatus'] != 'Ready':
        print(f"   - Changing {disk['Name']} which is {disk['RaidStatus']}")
        bmc.change_physical_disk_raid_status(disk)

When I execute this against the Redfish API on the server from which I took the above screenshot (with only disk 7 in Non-RAID status, I mean):

Collect the physical disks from the device.
For max 600 seconds check every 30 seconds until '<function dell.get_disks.<locals>.<lambda> at 0x7f71ae9c3240>' equals <function dell.get_disks.<locals>.<lambda> at 0x7f71ae9c1bc0>
Try number: 0...
Check virtual disks:
- Check RAID controller
  - PERC H965i Front found, check if the disks are configured as RAID or not
   - Changing SSD:0:1:7 which is NonRAID
Updated Disk.Bay.7:Enclosure.Internal.0-1:RAID.SL.5-1 RaidStatus to Ready

1 Rookie

 • 

7 Posts

July 10th, 2024 12:31

@DELL-Charles R Thanks! That is indeed the solution. I was made aware of this documentation about the ConvertToRAID action in RedFish, which does the task as I need it.

For those who wonder how to use it:


I created this function:

  def convert_physical_disks_to_raid(self, disk_ids):
    convert_url = f'/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/Actions/DellRaidService.ConvertToRAID'
    payload = {
      'PDArray': disk_ids
    }
    job_id = re.search("JID_.+",str(self.rf_session.conn.post(convert_url, body=payload))).group()
    self.check_job_status(job_id)
    print(f'Converted {disk_ids} to RAID')

And use it with this logic in my script:

  print(f'- Check RAID controller')
  raid_controller_name = bmc.get_raid_controller_name()
  if raid_controller_name == 'PERC H965i Front':
    print(f'  - {raid_controller_name} found, check if the disks are configured as RAID or not')
    disks_to_convert_to_raid = []
    for disk in physical_disks:
      if disk['RaidStatus'] != 'Ready':
        print(f"   - Adding {disk['Name']} to list of disks to be converted to RAID")
        disks_to_convert_to_raid.append(disk['DiskID'])
    if disks_to_convert_to_raid:
      print(f'   - Converting disks to RAID')
      bmc.convert_physical_disks_to_raid(disks_to_convert_to_raid)

And in case you wonder, here's the check_job_status function:

  def check_job_status(self, job_id):
    response = self.rf_session.conn.get(f'/redfish/v1/TaskService/Tasks/{job_id}')
    while response.dict['Oem']['Dell'].get('PercentComplete') != 100:
      pct = response.dict['Oem']['Dell'].get('PercentComplete')
      print(f'  Waiting for job {job_id} to complete: {pct}%')
      time.sleep(30)
      response = self.rf_session.conn.get(f'/redfish/v1/TaskService/Tasks/{job_id}')
    if "successfully" not in response.dict['Oem']['Dell'].get('Message').lower() and "matched" not in response.dict['Oem']['Dell'].get('Message'):
      print(f"ERROR: Job failed: {response.dict['Oem']['Dell'].get('Message')}")
      session.logout()
      del session
      sys.exit(1)
    else:
      print(f'  Job {job_id} done.')

(edited)

No Events found!

Top