@@ -1014,7 +1014,7 @@ async def reset_idrac(self):
10141014 _response = await self .post_request (_url , _payload , _headers )
10151015
10161016 status_code = _response .status
1017- if status_code == 204 :
1017+ if status_code in [ 200 , 204 ] :
10181018 self .logger .info ("Status code %s returned for POST command to reset iDRAC." % status_code )
10191019 else :
10201020 data = await _response .text ("utf-8" , "ignore" )
@@ -2193,6 +2193,216 @@ async def import_scp(self, file_path, targets="ALL"):
21932193 continue
21942194 return True
21952195
2196+ async def get_nic_fqdds (self ):
2197+ uri = "%s%s/NetworkAdapters" % (self .host_uri , self .system_resource )
2198+ resp = await self .get_request (uri )
2199+ if resp .status == 404 or self .vendor == "Supermicro" :
2200+ self .logger .error ("Operation not supported by vendor." )
2201+ return False
2202+
2203+ try :
2204+ raw = await resp .text ("utf-8" , "ignore" )
2205+ data = json .loads (raw .strip ())
2206+ nic_list = [[nic [1 ].split ("/" )[- 1 ] for nic in member .items ()][0 ] for member in data .get ("Members" )]
2207+ self .logger .debug ("Detected NIC FQDDs for existing network adapters." )
2208+ for nic in nic_list :
2209+ uri = "%s%s/NetworkAdapters/%s/NetworkDeviceFunctions" % (self .host_uri , self .system_resource , nic )
2210+ resp = await self .get_request (uri )
2211+ raw = await resp .text ("utf-8" , "ignore" )
2212+ data = json .loads (raw .strip ())
2213+ nic_fqqds = [[fqdd [1 ].split ("/" )[- 1 ] for fqdd in member .items ()][0 ] for member in data .get ("Members" )]
2214+ self .logger .info (f"{ nic } :" )
2215+ for i , fqdd in enumerate (nic_fqqds , start = 1 ):
2216+ self .logger .info (f" { i } : { fqdd } " )
2217+ except (AttributeError , IndexError , KeyError , TypeError , ValueError ):
2218+ self .logger .error ("Was unable to get NIC FQDDs, invalid server response." )
2219+ return False
2220+ return True
2221+
2222+ async def get_nic_attribute (self , fqdd , log = True ):
2223+ uri = "%s/Chassis/%s/NetworkAdapters/%s/NetworkDeviceFunctions/%s/Oem/Dell/DellNetworkAttributes/%s" % (
2224+ self .root_uri ,
2225+ self .system_resource .split ("/" )[- 1 ],
2226+ fqdd .split ("-" )[0 ],
2227+ fqdd ,
2228+ fqdd ,
2229+ )
2230+ resp = await self .get_request (uri )
2231+ if resp .status == 404 or self .vendor == "Supermicro" :
2232+ self .logger .error ("Operation not supported by vendor." )
2233+ return False
2234+
2235+ try :
2236+ raw = await resp .text ("utf-8" , "ignore" )
2237+ data = json .loads (raw .strip ())
2238+ attributes_list = [(key , value ) for key , value in data .get ("Attributes" ).items ()]
2239+ if not log :
2240+ return attributes_list
2241+ self .logger .debug (f"All NIC attributes of { fqdd } ." )
2242+ self .logger .info (f"{ fqdd } " )
2243+ for key , value in attributes_list :
2244+ self .logger .info (f" { key } : { value } " )
2245+ except (AttributeError , KeyError , TypeError , ValueError ):
2246+ self .logger .error ("Was unable to get NIC attribute(s) info, invalid server response." )
2247+ return False
2248+ return True
2249+
2250+ async def get_idrac_fw_version (self ):
2251+ idrac_fw_version = 0
2252+ try :
2253+ uri = "%s%s/" % (self .host_uri , self .manager_resource )
2254+ resp = await self .get_request (uri )
2255+ if resp .status == 404 or self .vendor == "Supermicro" :
2256+ self .logger .error ("Operation not supported by vendor." )
2257+ return 0
2258+ raw = await resp .text ("utf-8" , "ignore" )
2259+ data = json .loads (raw .strip ())
2260+ idrac_fw_version = int (data ["FirmwareVersion" ].replace ("." , "" ))
2261+ except (AttributeError , ValueError , StopIteration ):
2262+ self .logger .error ("Was unable to get iDRAC Firmware Version." )
2263+ return 0
2264+ return idrac_fw_version
2265+
2266+ async def get_nic_attribute_registry (self , fqdd = None ):
2267+ registry = []
2268+ idrac_fw_version = await self .get_idrac_fw_version ()
2269+ if not idrac_fw_version or idrac_fw_version < 5100000 :
2270+ self .logger .error ("Unsupported iDRAC version." )
2271+ return []
2272+ try :
2273+ uri = "%s/Registries/NetworkAttributesRegistry_%s/NetworkAttributesRegistry_%s.json" % (
2274+ self .root_uri ,
2275+ fqdd ,
2276+ fqdd ,
2277+ )
2278+ resp = await self .get_request (uri )
2279+ if resp .status == 404 :
2280+ self .logger .error ("Was unable to get network attribute registry." )
2281+ return []
2282+ raw = await resp .text ("utf-8" , "ignore" )
2283+ data = json .loads (raw .strip ())
2284+ registry = [attr for attr in data .get ("RegistryEntries" ).get ("Attributes" )]
2285+ except (AttributeError , KeyError , TypeError , ValueError ):
2286+ self .logger .error ("Was unable to get network attribute registry." )
2287+ return []
2288+ return registry
2289+
2290+ async def get_nic_attribute_info (self , fqdd , attribute , log = True ):
2291+ if self .vendor == "Supermicro" :
2292+ self .logger .error ("Operation not supported by vendor." )
2293+ return False
2294+ registry = await self .get_nic_attribute_registry (fqdd )
2295+ if not registry :
2296+ self .logger .error ("Was unable to get network attribute info." )
2297+ return False
2298+ try :
2299+ registry = [attr_dict for attr_dict in registry if attr_dict .get ("AttributeName" ) == attribute ][0 ]
2300+ current_value = await self .get_nic_attribute (fqdd , False )
2301+ current_value = [tup [1 ] for tup in current_value if tup [0 ] == attribute ][0 ]
2302+ registry .update ({"CurrentValue" : current_value })
2303+ if not log :
2304+ return registry
2305+ for key , value in registry .items ():
2306+ self .logger .info (f"{ key } : { value } " )
2307+ except (AttributeError , IndexError , KeyError , TypeError ):
2308+ self .logger .error ("Was unable to get network attribute info." )
2309+ return False
2310+ return True
2311+
2312+ async def set_nic_attribute (self , fqdd , attribute , value ):
2313+ if self .vendor == "Supermicro" :
2314+ self .logger .error ("Operation not supported by vendor." )
2315+ return False
2316+
2317+ attr_info = await self .get_nic_attribute_info (fqdd , attribute , False )
2318+ if not attr_info :
2319+ self .logger .error ("Was unable to set a network attribute. Attribute most likely doesn't exist." )
2320+ return False
2321+
2322+ try :
2323+ type = attr_info .get ("Type" )
2324+ current_value = attr_info .get ("CurrentValue" )
2325+ if value == current_value :
2326+ self .logger .warning ("This attribute already is set to this value. Skipping." )
2327+ return True
2328+ if type == "Enumeration" :
2329+ allowed_values = [value_spec .get ("ValueName" ) for value_spec in attr_info .get ("Value" )]
2330+ if value not in allowed_values :
2331+ self .logger .error ("Value not allowed for this attribute." )
2332+ self .logger .error ("Was unable to set a network attribute." )
2333+ return False
2334+ if type == "String" :
2335+ max , min = int (attr_info .get ("MaxLength" )), int (attr_info .get ("MinLength" ))
2336+ if len (value ) > max or len (value ) < min :
2337+ self .logger .error ("Value not allowed for this attribute. (Incorrect string length)" )
2338+ self .logger .error ("Was unable to set a network attribute." )
2339+ return False
2340+ if type == "Integer" :
2341+ max , min = int (attr_info .get ("UpperBound" )), int (attr_info .get ("LowerBound" ))
2342+ value = int (value )
2343+ if value > max or value < min :
2344+ self .logger .error ("Value not allowed for this attribute. (Incorrect number bounds)" )
2345+ self .logger .error ("Was unable to set a network attribute." )
2346+ return False
2347+ except (AttributeError , IndexError , KeyError , TypeError ):
2348+ self .logger .error ("Was unable to set a network attribute." )
2349+ return False
2350+
2351+ try :
2352+ uri = (
2353+ "%s/Chassis/System.Embedded.1/NetworkAdapters/%s/NetworkDeviceFunctions/%s/Oem/Dell/DellNetworkAttributes/%s/Settings"
2354+ % (
2355+ self .root_uri ,
2356+ fqdd .split ("-" )[0 ],
2357+ fqdd ,
2358+ fqdd ,
2359+ )
2360+ )
2361+ self .logger .debug (uri )
2362+ except (IndexError , ValueError ):
2363+ self .logger .error ("Invalid FQDD suplied." )
2364+ return False
2365+
2366+ headers = {"content-type" : "application/json" }
2367+ payload = {
2368+ "@Redfish.SettingsApplyTime" : {"ApplyTime" : "OnReset" },
2369+ "Attributes" : {attribute : value },
2370+ }
2371+ first_reset = False
2372+ try :
2373+ for i in range (self .retries ):
2374+ response = await self .patch_request (uri , payload , headers )
2375+ status_code = response .status
2376+ if status_code in [200 , 202 ]:
2377+ self .logger .info ("Patch command to set network attribute values and create next reboot job PASSED." )
2378+ break
2379+ else :
2380+ self .logger .error (
2381+ "Patch command to set network attribute values and create next reboot job FAILED, error code is: %s."
2382+ % status_code
2383+ )
2384+ if status_code == 503 and i - 1 != self .retries :
2385+ self .logger .info ("Retrying to send the patch command." )
2386+ continue
2387+ elif status_code == 400 :
2388+ self .logger .info ("Retrying to send the patch command." )
2389+ await self .clear_job_queue ()
2390+ if not first_reset :
2391+ await self .reset_idrac ()
2392+ await asyncio .sleep (10 )
2393+ first_reset = True
2394+ continue
2395+ self .logger .error (
2396+ "Patch command to set network attribute values and create next reboot job FAILED, error code is: %s."
2397+ % status_code
2398+ )
2399+ self .logger .error ("Was unable to set a network attribute." )
2400+ return False
2401+ except (AttributeError , ValueError ):
2402+ self .logger .error ("Was unable to set a network attribute." )
2403+
2404+ await self .reboot_server ()
2405+
21962406
21972407async def execute_badfish (_host , _args , logger , format_handler = None ):
21982408 _username = _args ["u" ]
@@ -2249,6 +2459,9 @@ async def execute_badfish(_host, _args, logger, format_handler=None):
22492459 scp_include_read_only = _args ["scp_include_read_only" ]
22502460 export_scp = _args ["export_scp" ]
22512461 import_scp = _args ["import_scp" ]
2462+ get_nic_fqdds = _args ["get_nic_fqdds" ]
2463+ get_nic_attribute = _args ["get_nic_attribute" ]
2464+ set_nic_attribute = _args ["set_nic_attribute" ]
22522465 result = True
22532466
22542467 try :
@@ -2355,6 +2568,15 @@ async def execute_badfish(_host, _args, logger, format_handler=None):
23552568 await badfish .export_scp (export_scp , scp_targets , scp_include_read_only )
23562569 elif import_scp :
23572570 await badfish .import_scp (import_scp , scp_targets )
2571+ elif get_nic_fqdds :
2572+ await badfish .get_nic_fqdds ()
2573+ elif get_nic_attribute :
2574+ if attribute :
2575+ await badfish .get_nic_attribute_info (get_nic_attribute , attribute )
2576+ else :
2577+ await badfish .get_nic_attribute (get_nic_attribute )
2578+ elif set_nic_attribute :
2579+ await badfish .set_nic_attribute (set_nic_attribute , attribute , value )
23582580
23592581 if pxe and not host_type :
23602582 await badfish .set_next_boot_pxe ()
@@ -2632,6 +2854,21 @@ def main(argv=None):
26322854 "imported." ,
26332855 default = "" ,
26342856 )
2857+ parser .add_argument (
2858+ "--get-nic-fqdds" ,
2859+ help = "List FQDDs for all NICs." ,
2860+ action = "store_true" ,
2861+ )
2862+ parser .add_argument (
2863+ "--get-nic-attribute" ,
2864+ help = "Get a NIC attribute values, specify a NIC FQDD." ,
2865+ default = "" ,
2866+ )
2867+ parser .add_argument (
2868+ "--set-nic-attribute" ,
2869+ help = "Set a NIC attribute value" ,
2870+ default = "" ,
2871+ )
26352872
26362873 _args = vars (parser .parse_args (argv ))
26372874
0 commit comments