DMTF Redfish, veri merkezi donanımlarını yönetmek için tasarlanmış, REST tabanlı, JSON formatında bir API standardıdır. Dell iDRAC9, Redfish 1.15+ standardına uyumlu tam bir implementasyon sunar. Her Redfish kaynağı, hiyerarşik bir URI yapısıyla erişilebilir ve kendini açıklayan (self-describing) JSON şemaları içerir.
iDRAC Redfish API'nin kök URI'si /redfish/v1'dir. Bu endpoint, sistemde mevcut tüm kaynakları (Systems, Chassis, Managers, UpdateService vb.) listeler. Her kaynak kendi altında bağlantılı alt kaynakları barındırır; bu yapı Hypermedia as the Engine of Application State (HATEOAS) prensibine dayanır.
| Kaynak |
URI |
Açıklama |
| Servis Kökü | /redfish/v1 | Tüm kaynakların giriş noktası |
| Sistem | /redfish/v1/Systems/System.Embedded.1 | Host sistem bilgisi, güç, boot |
| BIOS | /redfish/v1/Systems/System.Embedded.1/Bios | BIOS ayarları okuma/yazma |
| Depolama | /redfish/v1/Systems/System.Embedded.1/Storage | RAID, disk envanteri |
| Yöneticiler | /redfish/v1/Managers/iDRAC.Embedded.1 | iDRAC yapılandırması |
| Güncelleme | /redfish/v1/UpdateService | Firmware yükleme ve envanter |
| Olay Servisi | /redfish/v1/EventService | Olay abonelikleri |
| Görev Servisi | /redfish/v1/TaskService/Tasks | Arka plan görevleri |
curl -sk -u root:PASSWORD \
https://10.10.1.50/redfish/v1 \
| python3 -m json.tool
curl -sk -u root:PASSWORD \
https://10.10.1.50/redfish/v1 \
| python3 -c "
import sys, json
data = json.load(sys.stdin)
for k, v in data.items():
if isinstance(v, dict) and '@odata.id' in v:
print(f'{k}: {v[\"@odata.id\"]}')
"
ℹ️
iDRAC Redfish API'si varsayılan olarak TLS 1.2+ kullanır. Python requests kütüphanesiyle verify=False kullanıldığında InsecureRequestWarning uyarısı alırsınız. Üretim scriptlerinde kurumsal CA sertifikasını verify="/path/to/ca.crt" ile belirtin.
Dell, python-redfish-library ve iDRAC-Redfish-Scripting adlı iki resmi Python kütüphanesi sağlar. Bunların yanı sıra DMTF'nin redfish kütüphanesi de kullanılabilir. Pratik otomasyon scriptleri için requests kütüphanesi en esnek yaklaşımı sunar; çünkü iDRAC'a özgü Dell OEM extension'larına doğrudan erişim sağlar.
Yeniden kullanılabilir bir Redfish istemci sınıfı oluşturmak, birden fazla sunucu üzerinde aynı operasyonları çalıştırmayı kolaylaştırır. Aşağıda temel operasyonları kapsayan bir Python sınıfı verilmiştir:
import requests
import json
import time
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class DellRedfishClient:
def __init__(self, host, username, password, verify=False):
self.base_url = f"https://{host}"
self.auth = (username, password)
self.verify = verify
self.session_token = None
self.session_uri = None
def create_session(self):
"""Oturum tabanlı kimlik doğrulama"""
resp = requests.post(
f"{self.base_url}/redfish/v1/Sessions",
json={"UserName": self.auth[0], "Password": self.auth[1]},
verify=self.verify
)
resp.raise_for_status()
self.session_token = resp.headers["X-Auth-Token"]
self.session_uri = resp.json()["@odata.id"]
return self.session_token
def get(self, uri):
headers = {"X-Auth-Token": self.session_token} if self.session_token else {}
resp = requests.get(
f"{self.base_url}{uri}",
auth=None if self.session_token else self.auth,
headers=headers,
verify=self.verify
)
resp.raise_for_status()
return resp.json()
def patch(self, uri, payload):
headers = {
"Content-Type": "application/json",
"X-Auth-Token": self.session_token
}
resp = requests.patch(
f"{self.base_url}{uri}",
json=payload, headers=headers, verify=self.verify
)
resp.raise_for_status()
return resp
def post(self, uri, payload=None):
headers = {
"Content-Type": "application/json",
"X-Auth-Token": self.session_token
}
resp = requests.post(
f"{self.base_url}{uri}",
json=payload, headers=headers, verify=self.verify
)
return resp
def wait_for_task(self, task_uri, timeout=600, poll_interval=10):
"""Görev tamamlanana kadar bekle"""
start = time.time()
while time.time() - start < timeout:
task = self.get(task_uri)
status = task.get("TaskState")
pct = task.get("PercentComplete", 0)
print(f"\r [{pct:3}%] {status}", end="", flush=True)
if status in ["Completed", "Exception", "Killed"]:
print()
return task
time.sleep(poll_interval)
raise TimeoutError(f"Görev {timeout}s içinde tamamlanmadı")
def close_session(self):
if self.session_uri:
requests.delete(
f"{self.base_url}{self.session_uri}",
headers={"X-Auth-Token": self.session_token},
verify=self.verify
)
from redfish_client import DellRedfishClient
client = DellRedfishClient("10.10.1.50", "root", "PASSWORD")
client.create_session()
system = client.get("/redfish/v1/Systems/System.Embedded.1")
print(f"Model: {system['Model']}")
print(f"Güç: {system['PowerState']}")
print(f"Seri No: {system['SKU']}")
fw_inv = client.get("/redfish/v1/UpdateService/FirmwareInventory")
for member in fw_inv["Members"]:
fw = client.get(member["@odata.id"])
print(f" {fw['Name']}: {fw['Version']}")
client.close_session()
curl, CI/CD pipeline'larında ve bash scriptlerinde Redfish API çağrıları için yaygın olarak tercih edilir. Aşağıda en sık kullanılan iDRAC operasyonları için hazır curl komutları verilmiştir. Bu komutlar doğrudan script içine gömülebilir veya test amaçlı terminal'den çalıştırılabilir.
IDRAC_HOST="10.10.1.50"
IDRAC_USER="root"
IDRAC_PASS="PASSWORD"
BASE="https://$IDRAC_HOST"
AUTH="-u $IDRAC_USER:$IDRAC_PASS"
HEADERS="-H 'Content-Type: application/json'"
curl -sk $AUTH "$BASE/redfish/v1/Systems/System.Embedded.1" \
| python3 -c "
import sys, json; d=json.load(sys.stdin)
print('Model:', d.get('Model'))
print('Güç:', d.get('PowerState'))
print('İşlemci:', d.get('ProcessorSummary',{}).get('Count'), 'x', d.get('ProcessorSummary',{}).get('Model',''))
print('RAM:', d.get('MemorySummary',{}).get('TotalSystemMemoryGiB'), 'GiB')
"
curl -sk $AUTH "$BASE/redfish/v1/Chassis/System.Embedded.1/Thermal" \
| python3 -c "
import sys, json; d=json.load(sys.stdin)
print('=== Sıcaklıklar ===')
for t in d.get('Temperatures', []):
print(f\" {t['Name']}: {t.get('ReadingCelsius','N/A')} C\")
print('=== Fanlar ===')
for f in d.get('Fans', []):
print(f\" {f['FanName']}: {f.get('Reading','N/A')} RPM\")
"
curl -sk $AUTH -X POST \
-H "Content-Type: application/json" \
-d '{"ResetType":"GracefulRestart"}' \
"$BASE/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset"
curl -sk $AUTH -X POST \
-H "Content-Type: application/json" \
-d '{"ResetType":"ForceOff"}' \
"$BASE/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset"
curl -sk $AUTH -X POST \
-H "Content-Type: application/json" \
-d '{"ResetType":"GracefulRestart"}' \
"$BASE/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Manager.Reset"
curl -sk $AUTH "$BASE/redfish/v1/Systems/System.Embedded.1/Storage" \
| python3 -c "
import sys, json, requests, urllib3
urllib3.disable_warnings()
d=json.load(sys.stdin)
for m in d.get('Members', []):
print('Kontrolör:', m['@odata.id'].split('/')[-1])
"
curl -sk $AUTH \
"$BASE/redfish/v1/Systems/System.Embedded.1/Storage/RAID.Integrated.1-1/Drives" \
| python3 -m json.tool | grep -E '"@odata.id"|"Name"'
Redfish üzerinden firmware güncelleme, MultipartUpload endpoint'ine DUP dosyasını yükleyerek veya uzak bir HTTP/CIFS/NFS sunucusundaki DUP dosyasına referans vererek yapılır. Güncelleme işlemi arka planda bir task olarak çalışır; task tamamlanana kadar poll edilmesi gerekir.
Toplu güncellemeler için önce firmware envanteri alınır, mevcut versiyonlar hedef versiyonlarla karşılaştırılır ve güncelleme gerektiren bileşenler için sıralı veya paralel güncelleme görevleri oluşturulur. BIOS ve iDRAC güncellemeleri yeniden başlatma gerektirdiğinden bunlar ayrı bir gruba alınmalıdır.
import requests, os, sys, time, json
import urllib3
urllib3.disable_warnings()
def upload_firmware(host, user, password, dup_file):
base = f"https://{host}"
auth = (user, password)
print(f"Yükleniyor: {os.path.basename(dup_file)}")
with open(dup_file, "rb") as f:
resp = requests.post(
f"{base}/redfish/v1/UpdateService/MultipartUpload",
files={"file": (os.path.basename(dup_file), f, "application/octet-stream")},
data={"UpdateParameters": json.dumps({
"Targets": [],
"@Redfish.OperationApplyTime": "OnReset"
})},
auth=auth, verify=False
)
if resp.status_code not in [200, 202]:
print(f"HATA: {resp.status_code} - {resp.text}")
return None
task_uri = resp.headers.get("Location", "").replace(base, "")
print(f"Görev oluşturuldu: {task_uri}")
return task_uri
def wait_task(host, user, password, task_uri, timeout=600):
base = f"https://{host}"
auth = (user, password)
start = time.time()
while time.time() - start < timeout:
r = requests.get(f"{base}{task_uri}", auth=auth, verify=False)
t = r.json()
state = t.get("TaskState", "Unknown")
pct = t.get("PercentComplete", 0)
print(f"\r [{pct:3d}%] {state}", end="", flush=True)
if state in ["Completed", "Exception"]:
print()
return state == "Completed"
time.sleep(15)
return False
HOST = "10.10.1.50"
task = upload_firmware(HOST, "root", "PASSWORD", "/tmp/BIOS_XYR9K_WN64_2.20.0.EXE")
if task:
success = wait_task(HOST, "root", "PASSWORD", task)
print("Güncelleme başarılı!" if success else "Güncelleme başarısız!")
⚠️
Dikkat: @Redfish.OperationApplyTime değeri OnReset olarak ayarlandığında firmware, sunucu bir sonraki yeniden başlatmada uygulanır. Immediate kullanıldığında ise bazı bileşenler (örn. NIC firmware) anlık güncelleme sırasında kısa süreli bağlantı keser.
Redfish üzerinden BIOS ayarları okuma ve yazma işlemi, /redfish/v1/Systems/System.Embedded.1/Bios endpoint'i üzerinden gerçekleştirilir. BIOS ayarları pending settings mekanizmasıyla çalışır: değişiklikler önce Bios/Settings endpoint'ine yazılır, ardından sunucu yeniden başlatıldığında Lifecycle Controller tarafından uygulanır.
curl -sk -u root:PASSWORD \
"https://10.10.1.50/redfish/v1/Systems/System.Embedded.1/Bios" \
| python3 -c "
import sys, json
d = json.load(sys.stdin)
attrs = d.get('Attributes', {})
virt_keys = [k for k in attrs if 'virt' in k.lower() or 'proc' in k.lower()]
for k in sorted(virt_keys):
print(f'{k}: {attrs[k]}')
"
curl -sk -u root:PASSWORD \
-X PATCH \
-H "Content-Type: application/json" \
-d '{
"Attributes": {
"ProcVirtualization": "Enabled",
"SysProfile": "PerfOptimized",
"LogicalProc": "Enabled",
"NodeInterleave": "Disabled",
"ProcCStates": "Disabled",
"MemTest": "Disabled",
"BootMode": "Uefi"
}
}' \
"https://10.10.1.50/redfish/v1/Systems/System.Embedded.1/Bios/Settings" \
| python3 -m json.tool
curl -sk -u root:PASSWORD \
-X POST \
-H "Content-Type: application/json" \
-d '{
"TargetSettingsURI": "/redfish/v1/Systems/System.Embedded.1/Bios/Settings",
"Oem": {
"Dell": {
"JobType": "BIOSConfiguration"
}
}
}' \
"https://10.10.1.50/redfish/v1/Managers/iDRAC.Embedded.1/Jobs" \
| python3 -m json.tool
from redfish_client import DellRedfishClient
STANDARD_BIOS = {
"ProcVirtualization": "Enabled",
"SysProfile": "PerfOptimized",
"LogicalProc": "Enabled",
"BootMode": "Uefi",
"NodeInterleave": "Disabled",
}
SERVERS = ["10.10.1.50", "10.10.1.51", "10.10.1.52"]
for server in SERVERS:
print(f"\n=== {server} ===")
try:
c = DellRedfishClient(server, "root", "PASSWORD")
c.create_session()
bios = c.get("/redfish/v1/Systems/System.Embedded.1/Bios")
attrs = bios.get("Attributes", {})
drift = {k: v for k, v in STANDARD_BIOS.items() if attrs.get(k) != v}
if drift:
print(f" Drift tespit edildi: {drift}")
c.patch("/redfish/v1/Systems/System.Embedded.1/Bios/Settings",
{"Attributes": drift})
print(f" Değişiklikler uygulandı (yeniden başlatma bekleniyor)")
else:
print(" BIOS uyumlu, değişiklik gerekmedi")
c.close_session()
except Exception as e:
print(f" HATA: {e}")
Dell, dellemc.openmanage Ansible koleksiyonunu resmi olarak destekler. Bu koleksiyon, iDRAC Redfish ve RACADM üzerinden sunucu yönetimini Ansible playbook'larına entegre eder. 80'den fazla modül içerir: firmware güncelleme, BIOS yapılandırma, RAID kurulumu, kullanıcı yönetimi ve daha fazlası.
ansible-galaxy collection install dellemc.openmanage
pip3 install omsdk requests
cat > /tmp/dell_inventory.yml <<'EOF'
all:
children:
idrac_hosts:
hosts:
r760-01:
ansible_host: 10.10.1.50
idrac_user: root
idrac_password: "PASSWORD"
r760-02:
ansible_host: 10.10.1.51
idrac_user: root
idrac_password: "PASSWORD"
EOF
cat > /tmp/playbook_firmware_update.yml <<'EOF'
---
- name: Dell iDRAC Firmware Güncelleme
hosts: idrac_hosts
gather_facts: no
tasks:
- name: Mevcut firmware versiyonlarını al
dellemc.openmanage.idrac_firmware_info:
idrac_ip: "{{ ansible_host }}"
idrac_user: "{{ idrac_user }}"
idrac_password: "{{ idrac_password }}"
validate_certs: false
register: fw_info
- name: Firmware versiyonlarını göster
debug:
msg: "{{ fw_info.firmware_info.ComponentType }}"
- name: BIOS firmware güncelle (catalog bazlı)
dellemc.openmanage.idrac_firmware:
idrac_ip: "{{ ansible_host }}"
idrac_user: "{{ idrac_user }}"
idrac_password: "{{ idrac_password }}"
validate_certs: false
share_name: "10.10.1.200:/firmware-catalog"
share_type: NFS
catalog_file_name: "Catalog.xml"
apply_update: true
reboot: false
job_wait: true
register: update_result
- name: Güncelleme sonucunu raporla
debug:
msg: "Güncelleme durumu: {{ update_result.update_status }}"
EOF
ansible-playbook -i /tmp/dell_inventory.yml /tmp/playbook_firmware_update.yml
cat > /tmp/playbook_bios_config.yml <<'EOF'
---
- name: Dell PowerEdge BIOS Standardizasyonu
hosts: idrac_hosts
gather_facts: no
vars:
bios_attributes:
ProcVirtualization: "Enabled"
SysProfile: "PerfOptimized"
LogicalProc: "Enabled"
NodeInterleave: "Disabled"
BootMode: "Uefi"
tasks:
- name: BIOS özniteliklerini uygula
dellemc.openmanage.idrac_bios:
idrac_ip: "{{ ansible_host }}"
idrac_user: "{{ idrac_user }}"
idrac_password: "{{ idrac_password }}"
validate_certs: false
attributes: "{{ bios_attributes }}"
register: bios_result
- name: Sonucu göster
debug:
msg: "{{ bios_result.msg }}"
EOF
ansible-playbook -i /tmp/dell_inventory.yml /tmp/playbook_bios_config.yml
Onlarca veya yüzlerce sunucuda aynı operasyonu gerçekleştirmek için eşzamanlı (concurrent) bir Python pipeline oluşturmak hem zaman hem de iş yükü açısından büyük avantaj sağlar. concurrent.futures.ThreadPoolExecutor kullanılarak paralel Redfish çağrıları yapılabilir.
import concurrent.futures
import requests, json, urllib3, csv
from datetime import datetime
urllib3.disable_warnings()
def get_server_info(server):
"""Tek sunucu için bilgi toplama"""
host, user, password = server["ip"], server["user"], server["password"]
base = f"https://{host}"
auth = (user, password)
try:
r = requests.get(
f"{base}/redfish/v1/Systems/System.Embedded.1",
auth=auth, verify=False, timeout=30
)
d = r.json()
mgr = requests.get(
f"{base}/redfish/v1/Managers/iDRAC.Embedded.1",
auth=auth, verify=False, timeout=30
).json()
return {
"ip": host,
"hostname": d.get("HostName", "N/A"),
"model": d.get("Model", "N/A"),
"serial": d.get("SKU", "N/A"),
"power": d.get("PowerState", "N/A"),
"health": d.get("Status", {}).get("Health", "N/A"),
"idrac_fw": mgr.get("FirmwareVersion", "N/A"),
"error": None
}
except Exception as e:
return {"ip": host, "error": str(e)}
SERVERS = []
with open("/tmp/servers.csv") as f:
for row in csv.DictReader(f):
SERVERS.append(row)
print(f"Toplam {len(SERVERS)} sunucu taranıyor...")
results = []
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
futures = {executor.submit(get_server_info, s): s for s in SERVERS}
for future in concurrent.futures.as_completed(futures):
result = future.result()
results.append(result)
status = "✓" if not result.get("error") else "✗"
print(f" {status} {result['ip']}: {result.get('model','HATA')}")
output_file = f"/tmp/server_inventory_{datetime.now().strftime('%Y%m%d_%H%M')}.csv"
with open(output_file, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=results[0].keys())
writer.writeheader()
writer.writerows(results)
print(f"\nRapor kaydedildi: {output_file}")
Otomasyon scriptlerinde hata yönetimi, özellikle toplu operasyonlarda kritik önem taşır. Ağ zaman aşımları, kimlik doğrulama hataları, iDRAC meşgul durumları ve görev başarısızlıkları için uygun retry mekanizmaları ve loglama eklenmelidir.
Uzun süren görevlerin (firmware güncelleme, BIOS yapılandırma) durumu düzenli aralıklarla poll edilmeli ve sonuçlar hem terminal'e hem de bir log dosyasına yazılmalıdır. Kritik hatalar için e-posta veya Slack webhook bildirimleri eklenebilir.
import time, functools, logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
handlers=[
logging.FileHandler('/tmp/idrac_automation.log'),
logging.StreamHandler()
]
)
def retry(max_attempts=3, delay=5, backoff=2, exceptions=(Exception,)):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
attempt = 1
wait = delay
while attempt <= max_attempts:
try:
return func(*args, **kwargs)
except exceptions as e:
if attempt == max_attempts:
logging.error(f"Son deneme başarısız: {func.__name__} - {e}")
raise
logging.warning(f"Deneme {attempt} başarısız, {wait}s sonra tekrar: {e}")
time.sleep(wait)
wait *= backoff
attempt += 1
return wrapper
return decorator
@retry(max_attempts=3, delay=10, backoff=2)
def safe_get_system_info(client, server_ip):
return client.get("/redfish/v1/Systems/System.Embedded.1")
import requests
def notify_webhook(webhook_url, message, level="info"):
color_map = {
"info": "#007db8",
"success": "#22c55e",
"warning": "#f0a500",
"error": "#ff6b35"
}
payload = {
"attachments": [{
"color": color_map.get(level, "#007db8"),
"text": message,
"footer": "Dell iDRAC Automation"
}]
}
requests.post(webhook_url, json=payload, timeout=10)
SLACK_WEBHOOK = "https://hooks.slack.com/services/XXX/YYY/ZZZ"
notify_webhook(SLACK_WEBHOOK,
"10.10.1.50 - BIOS firmware güncelleme tamamlandı (v2.20.0)",
"success")
- ✓Python Redfish istemci sınıfı oluşturuldu ve test edildi
- ✓Oturum yönetimi (token tabanlı) ve güvenli kapatma uygulandı
- ✓Firmware güncelleme pipeline'ı task polling ile tamamlandı
- ✓BIOS drift detection ve standart uygulama scripti hazırlandı
- ✓Ansible playbook'ları dellemc.openmanage ile test edildi
- ✓Toplu operasyonlar ThreadPoolExecutor ile paralel çalışıyor
- ✓Retry mekanizması ve merkezi loglama eklendi
- ✓Kritik hatalar için webhook bildirimleri yapılandırıldı