1""" 2Manage Dell DRAC. 3 4.. versionadded:: 2015.8.2 5""" 6 7 8import logging 9import os 10import re 11 12import salt.utils.path 13from salt.exceptions import CommandExecutionError 14 15log = logging.getLogger(__name__) 16 17__proxyenabled__ = ["fx2"] 18 19try: 20 run_all = __salt__["cmd.run_all"] 21except (NameError, KeyError): 22 import salt.modules.cmdmod 23 24 __salt__ = {"cmd.run_all": salt.modules.cmdmod.run_all} 25 26 27def __virtual__(): 28 if salt.utils.path.which("racadm"): 29 return True 30 31 return ( 32 False, 33 "The drac execution module cannot be loaded: racadm binary not in path.", 34 ) 35 36 37def __parse_drac(output): 38 """ 39 Parse Dell DRAC output 40 """ 41 drac = {} 42 section = "" 43 44 for i in output.splitlines(): 45 if i.strip().endswith(":") and "=" not in i: 46 section = i[0:-1] 47 drac[section] = {} 48 if i.rstrip() and "=" in i: 49 if section in drac: 50 drac[section].update(dict([[prop.strip() for prop in i.split("=")]])) 51 else: 52 section = i.strip() 53 if section not in drac and section: 54 drac[section] = {} 55 56 return drac 57 58 59def __execute_cmd( 60 command, host=None, admin_username=None, admin_password=None, module=None 61): 62 """ 63 Execute rac commands 64 """ 65 if module: 66 # -a takes 'server' or 'switch' to represent all servers 67 # or all switches in a chassis. Allow 68 # user to say 'module=ALL_SERVER' or 'module=ALL_SWITCH' 69 if module.startswith("ALL_"): 70 modswitch = "-a " + module[module.index("_") + 1 : len(module)].lower() 71 else: 72 modswitch = "-m {}".format(module) 73 else: 74 modswitch = "" 75 if not host: 76 # This is a local call 77 cmd = __salt__["cmd.run_all"]("racadm {} {}".format(command, modswitch)) 78 else: 79 cmd = __salt__["cmd.run_all"]( 80 "racadm -r {} -u {} -p {} {} {}".format( 81 host, admin_username, admin_password, command, modswitch 82 ), 83 output_loglevel="quiet", 84 ) 85 86 if cmd["retcode"] != 0: 87 log.warning("racadm returned an exit code of %s", cmd["retcode"]) 88 return False 89 90 return True 91 92 93def __execute_ret( 94 command, host=None, admin_username=None, admin_password=None, module=None 95): 96 """ 97 Execute rac commands 98 """ 99 if module: 100 if module == "ALL": 101 modswitch = "-a " 102 else: 103 modswitch = "-m {}".format(module) 104 else: 105 modswitch = "" 106 if not host: 107 # This is a local call 108 cmd = __salt__["cmd.run_all"]("racadm {} {}".format(command, modswitch)) 109 else: 110 cmd = __salt__["cmd.run_all"]( 111 "racadm -r {} -u {} -p {} {} {}".format( 112 host, admin_username, admin_password, command, modswitch 113 ), 114 output_loglevel="quiet", 115 ) 116 117 if cmd["retcode"] != 0: 118 log.warning("racadm returned an exit code of %s", cmd["retcode"]) 119 else: 120 fmtlines = [] 121 for l in cmd["stdout"].splitlines(): 122 if l.startswith("Security Alert"): 123 continue 124 if l.startswith("RAC1168:"): 125 break 126 if l.startswith("RAC1169:"): 127 break 128 if l.startswith("Continuing execution"): 129 continue 130 131 if not l.strip(): 132 continue 133 fmtlines.append(l) 134 if "=" in l: 135 continue 136 cmd["stdout"] = "\n".join(fmtlines) 137 138 return cmd 139 140 141def get_dns_dracname(host=None, admin_username=None, admin_password=None): 142 143 ret = __execute_ret( 144 "get iDRAC.NIC.DNSRacName", 145 host=host, 146 admin_username=admin_username, 147 admin_password=admin_password, 148 ) 149 parsed = __parse_drac(ret["stdout"]) 150 return parsed 151 152 153def set_dns_dracname(name, host=None, admin_username=None, admin_password=None): 154 155 ret = __execute_ret( 156 "set iDRAC.NIC.DNSRacName {}".format(name), 157 host=host, 158 admin_username=admin_username, 159 admin_password=admin_password, 160 ) 161 return ret 162 163 164def system_info(host=None, admin_username=None, admin_password=None, module=None): 165 """ 166 Return System information 167 168 CLI Example: 169 170 .. code-block:: bash 171 172 salt dell dracr.system_info 173 """ 174 cmd = __execute_ret( 175 "getsysinfo", 176 host=host, 177 admin_username=admin_username, 178 admin_password=admin_password, 179 module=module, 180 ) 181 182 if cmd["retcode"] != 0: 183 log.warning("racadm returned an exit code of %s", cmd["retcode"]) 184 return cmd 185 186 return __parse_drac(cmd["stdout"]) 187 188 189def set_niccfg( 190 ip=None, 191 netmask=None, 192 gateway=None, 193 dhcp=False, 194 host=None, 195 admin_username=None, 196 admin_password=None, 197 module=None, 198): 199 200 cmdstr = "setniccfg " 201 202 if dhcp: 203 cmdstr += "-d " 204 else: 205 cmdstr += "-s " + ip + " " + netmask + " " + gateway 206 207 return __execute_cmd( 208 cmdstr, 209 host=host, 210 admin_username=admin_username, 211 admin_password=admin_password, 212 module=module, 213 ) 214 215 216def set_nicvlan( 217 vlan=None, host=None, admin_username=None, admin_password=None, module=None 218): 219 220 cmdstr = "setniccfg -v " 221 222 if vlan: 223 cmdstr += vlan 224 225 ret = __execute_cmd( 226 cmdstr, 227 host=host, 228 admin_username=admin_username, 229 admin_password=admin_password, 230 module=module, 231 ) 232 233 return ret 234 235 236def network_info(host=None, admin_username=None, admin_password=None, module=None): 237 """ 238 Return Network Configuration 239 240 CLI Example: 241 242 .. code-block:: bash 243 244 salt dell dracr.network_info 245 """ 246 247 inv = inventory( 248 host=host, admin_username=admin_username, admin_password=admin_password 249 ) 250 if inv is None: 251 cmd = {} 252 cmd["retcode"] = -1 253 cmd["stdout"] = "Problem getting switch inventory" 254 return cmd 255 256 if module not in inv.get("switch") and module not in inv.get("server"): 257 cmd = {} 258 cmd["retcode"] = -1 259 cmd["stdout"] = "No module {} found.".format(module) 260 return cmd 261 262 cmd = __execute_ret( 263 "getniccfg", 264 host=host, 265 admin_username=admin_username, 266 admin_password=admin_password, 267 module=module, 268 ) 269 270 if cmd["retcode"] != 0: 271 log.warning("racadm returned an exit code of %s", cmd["retcode"]) 272 273 cmd["stdout"] = "Network:\n" + "Device = " + module + "\n" + cmd["stdout"] 274 return __parse_drac(cmd["stdout"]) 275 276 277def nameservers(ns, host=None, admin_username=None, admin_password=None, module=None): 278 """ 279 Configure the nameservers on the DRAC 280 281 CLI Example: 282 283 .. code-block:: bash 284 285 salt dell dracr.nameservers [NAMESERVERS] 286 salt dell dracr.nameservers ns1.example.com ns2.example.com 287 admin_username=root admin_password=calvin module=server-1 288 host=192.168.1.1 289 """ 290 if len(ns) > 2: 291 log.warning("racadm only supports two nameservers") 292 return False 293 294 for i in range(1, len(ns) + 1): 295 if not __execute_cmd( 296 "config -g cfgLanNetworking -o cfgDNSServer{} {}".format(i, ns[i - 1]), 297 host=host, 298 admin_username=admin_username, 299 admin_password=admin_password, 300 module=module, 301 ): 302 return False 303 304 return True 305 306 307def syslog( 308 server, 309 enable=True, 310 host=None, 311 admin_username=None, 312 admin_password=None, 313 module=None, 314): 315 """ 316 Configure syslog remote logging, by default syslog will automatically be 317 enabled if a server is specified. However, if you want to disable syslog 318 you will need to specify a server followed by False 319 320 CLI Example: 321 322 .. code-block:: bash 323 324 salt dell dracr.syslog [SYSLOG IP] [ENABLE/DISABLE] 325 salt dell dracr.syslog 0.0.0.0 False 326 """ 327 if enable and __execute_cmd( 328 "config -g cfgRemoteHosts -o cfgRhostsSyslogEnable 1", 329 host=host, 330 admin_username=admin_username, 331 admin_password=admin_password, 332 module=None, 333 ): 334 return __execute_cmd( 335 "config -g cfgRemoteHosts -o cfgRhostsSyslogServer1 {}".format(server), 336 host=host, 337 admin_username=admin_username, 338 admin_password=admin_password, 339 module=module, 340 ) 341 342 return __execute_cmd( 343 "config -g cfgRemoteHosts -o cfgRhostsSyslogEnable 0", 344 host=host, 345 admin_username=admin_username, 346 admin_password=admin_password, 347 module=module, 348 ) 349 350 351def email_alerts(action, host=None, admin_username=None, admin_password=None): 352 """ 353 Enable/Disable email alerts 354 355 CLI Example: 356 357 .. code-block:: bash 358 359 salt dell dracr.email_alerts True 360 salt dell dracr.email_alerts False 361 """ 362 363 if action: 364 return __execute_cmd( 365 "config -g cfgEmailAlert -o cfgEmailAlertEnable -i 1 1", 366 host=host, 367 admin_username=admin_username, 368 admin_password=admin_password, 369 ) 370 else: 371 return __execute_cmd("config -g cfgEmailAlert -o cfgEmailAlertEnable -i 1 0") 372 373 374def list_users(host=None, admin_username=None, admin_password=None, module=None): 375 """ 376 List all DRAC users 377 378 CLI Example: 379 380 .. code-block:: bash 381 382 salt dell dracr.list_users 383 """ 384 users = {} 385 _username = "" 386 387 for idx in range(1, 17): 388 cmd = __execute_ret( 389 "getconfig -g cfgUserAdmin -i {}".format(idx), 390 host=host, 391 admin_username=admin_username, 392 admin_password=admin_password, 393 ) 394 395 if cmd["retcode"] != 0: 396 log.warning("racadm returned an exit code of %s", cmd["retcode"]) 397 398 for user in cmd["stdout"].splitlines(): 399 if not user.startswith("cfg"): 400 continue 401 402 (key, val) = user.split("=") 403 404 if key.startswith("cfgUserAdminUserName"): 405 _username = val.strip() 406 407 if val: 408 users[_username] = {"index": idx} 409 else: 410 break 411 else: 412 if _username: 413 users[_username].update({key: val}) 414 415 return users 416 417 418def delete_user( 419 username, uid=None, host=None, admin_username=None, admin_password=None 420): 421 """ 422 Delete a user 423 424 CLI Example: 425 426 .. code-block:: bash 427 428 salt dell dracr.delete_user [USERNAME] [UID - optional] 429 salt dell dracr.delete_user diana 4 430 """ 431 if uid is None: 432 user = list_users() 433 uid = user[username]["index"] 434 435 if uid: 436 return __execute_cmd( 437 "config -g cfgUserAdmin -o cfgUserAdminUserName -i {} ".format(uid), 438 host=host, 439 admin_username=admin_username, 440 admin_password=admin_password, 441 ) 442 443 else: 444 log.warning("User '%s' does not exist", username) 445 return False 446 447 448def change_password( 449 username, 450 password, 451 uid=None, 452 host=None, 453 admin_username=None, 454 admin_password=None, 455 module=None, 456): 457 """ 458 Change user's password 459 460 CLI Example: 461 462 .. code-block:: bash 463 464 salt dell dracr.change_password [USERNAME] [PASSWORD] uid=[OPTIONAL] 465 host=<remote DRAC> admin_username=<DRAC user> 466 admin_password=<DRAC PW> 467 salt dell dracr.change_password diana secret 468 469 Note that if only a username is specified then this module will look up 470 details for all 16 possible DRAC users. This is time consuming, but might 471 be necessary if one is not sure which user slot contains the one you want. 472 Many late-model Dell chassis have 'root' as UID 1, so if you can depend 473 on that then setting the password is much quicker. 474 Raises an error if the supplied password is greater than 20 chars. 475 """ 476 if len(password) > 20: 477 raise CommandExecutionError("Supplied password should be 20 characters or less") 478 479 if uid is None: 480 user = list_users( 481 host=host, 482 admin_username=admin_username, 483 admin_password=admin_password, 484 module=module, 485 ) 486 uid = user[username]["index"] 487 488 if uid: 489 return __execute_cmd( 490 "config -g cfgUserAdmin -o cfgUserAdminPassword -i {} {}".format( 491 uid, password 492 ), 493 host=host, 494 admin_username=admin_username, 495 admin_password=admin_password, 496 module=module, 497 ) 498 else: 499 log.warning("racadm: user '%s' does not exist", username) 500 return False 501 502 503def deploy_password( 504 username, password, host=None, admin_username=None, admin_password=None, module=None 505): 506 """ 507 Change the QuickDeploy password, used for switches as well 508 509 CLI Example: 510 511 .. code-block:: bash 512 513 salt dell dracr.deploy_password [USERNAME] [PASSWORD] 514 host=<remote DRAC> admin_username=<DRAC user> 515 admin_password=<DRAC PW> 516 salt dell dracr.change_password diana secret 517 518 Note that if only a username is specified then this module will look up 519 details for all 16 possible DRAC users. This is time consuming, but might 520 be necessary if one is not sure which user slot contains the one you want. 521 Many late-model Dell chassis have 'root' as UID 1, so if you can depend 522 on that then setting the password is much quicker. 523 """ 524 return __execute_cmd( 525 "deploy -u {} -p {}".format(username, password), 526 host=host, 527 admin_username=admin_username, 528 admin_password=admin_password, 529 module=module, 530 ) 531 532 533def deploy_snmp(snmp, host=None, admin_username=None, admin_password=None, module=None): 534 """ 535 Change the QuickDeploy SNMP community string, used for switches as well 536 537 CLI Example: 538 539 .. code-block:: bash 540 541 salt dell dracr.deploy_snmp SNMP_STRING 542 host=<remote DRAC or CMC> admin_username=<DRAC user> 543 admin_password=<DRAC PW> 544 salt dell dracr.deploy_password diana secret 545 546 """ 547 return __execute_cmd( 548 "deploy -v SNMPv2 {} ro".format(snmp), 549 host=host, 550 admin_username=admin_username, 551 admin_password=admin_password, 552 module=module, 553 ) 554 555 556def create_user( 557 username, 558 password, 559 permissions, 560 users=None, 561 host=None, 562 admin_username=None, 563 admin_password=None, 564): 565 """ 566 Create user accounts 567 568 CLI Example: 569 570 .. code-block:: bash 571 572 salt dell dracr.create_user [USERNAME] [PASSWORD] [PRIVILEGES] 573 salt dell dracr.create_user diana secret login,test_alerts,clear_logs 574 575 DRAC Privileges 576 * login : Login to iDRAC 577 * drac : Configure iDRAC 578 * user_management : Configure Users 579 * clear_logs : Clear Logs 580 * server_control_commands : Execute Server Control Commands 581 * console_redirection : Access Console Redirection 582 * virtual_media : Access Virtual Media 583 * test_alerts : Test Alerts 584 * debug_commands : Execute Debug Commands 585 """ 586 _uids = set() 587 588 if users is None: 589 users = list_users() 590 591 if username in users: 592 log.warning("racadm: user '%s' already exists", username) 593 return False 594 595 for idx in users.keys(): 596 _uids.add(users[idx]["index"]) 597 598 uid = sorted(list(set(range(2, 12)) - _uids), reverse=True).pop() 599 600 # Create user account first 601 if not __execute_cmd( 602 "config -g cfgUserAdmin -o cfgUserAdminUserName -i {} {}".format(uid, username), 603 host=host, 604 admin_username=admin_username, 605 admin_password=admin_password, 606 ): 607 delete_user(username, uid) 608 return False 609 610 # Configure users permissions 611 if not set_permissions(username, permissions, uid): 612 log.warning("unable to set user permissions") 613 delete_user(username, uid) 614 return False 615 616 # Configure users password 617 if not change_password(username, password, uid): 618 log.warning("unable to set user password") 619 delete_user(username, uid) 620 return False 621 622 # Enable users admin 623 if not __execute_cmd( 624 "config -g cfgUserAdmin -o cfgUserAdminEnable -i {} 1".format(uid) 625 ): 626 delete_user(username, uid) 627 return False 628 629 return True 630 631 632def set_permissions( 633 username, permissions, uid=None, host=None, admin_username=None, admin_password=None 634): 635 """ 636 Configure users permissions 637 638 CLI Example: 639 640 .. code-block:: bash 641 642 salt dell dracr.set_permissions [USERNAME] [PRIVILEGES] 643 [USER INDEX - optional] 644 salt dell dracr.set_permissions diana login,test_alerts,clear_logs 4 645 646 DRAC Privileges 647 * login : Login to iDRAC 648 * drac : Configure iDRAC 649 * user_management : Configure Users 650 * clear_logs : Clear Logs 651 * server_control_commands : Execute Server Control Commands 652 * console_redirection : Access Console Redirection 653 * virtual_media : Access Virtual Media 654 * test_alerts : Test Alerts 655 * debug_commands : Execute Debug Commands 656 """ 657 privileges = { 658 "login": "0x0000001", 659 "drac": "0x0000002", 660 "user_management": "0x0000004", 661 "clear_logs": "0x0000008", 662 "server_control_commands": "0x0000010", 663 "console_redirection": "0x0000020", 664 "virtual_media": "0x0000040", 665 "test_alerts": "0x0000080", 666 "debug_commands": "0x0000100", 667 } 668 669 permission = 0 670 671 # When users don't provide a user ID we need to search for this 672 if uid is None: 673 user = list_users() 674 uid = user[username]["index"] 675 676 # Generate privilege bit mask 677 for i in permissions.split(","): 678 perm = i.strip() 679 680 if perm in privileges: 681 permission += int(privileges[perm], 16) 682 683 return __execute_cmd( 684 "config -g cfgUserAdmin -o cfgUserAdminPrivilege -i {} 0x{:08X}".format( 685 uid, permission 686 ), 687 host=host, 688 admin_username=admin_username, 689 admin_password=admin_password, 690 ) 691 692 693def set_snmp(community, host=None, admin_username=None, admin_password=None): 694 """ 695 Configure CMC or individual iDRAC SNMP community string. 696 Use ``deploy_snmp`` for configuring chassis switch SNMP. 697 698 CLI Example: 699 700 .. code-block:: bash 701 702 salt dell dracr.set_snmp [COMMUNITY] 703 salt dell dracr.set_snmp public 704 """ 705 return __execute_cmd( 706 "config -g cfgOobSnmp -o cfgOobSnmpAgentCommunity {}".format(community), 707 host=host, 708 admin_username=admin_username, 709 admin_password=admin_password, 710 ) 711 712 713def set_network( 714 ip, netmask, gateway, host=None, admin_username=None, admin_password=None 715): 716 """ 717 Configure Network on the CMC or individual iDRAC. 718 Use ``set_niccfg`` for blade and switch addresses. 719 720 CLI Example: 721 722 .. code-block:: bash 723 724 salt dell dracr.set_network [DRAC IP] [NETMASK] [GATEWAY] 725 salt dell dracr.set_network 192.168.0.2 255.255.255.0 192.168.0.1 726 admin_username=root admin_password=calvin host=192.168.1.1 727 """ 728 return __execute_cmd( 729 "setniccfg -s {} {} {}".format( 730 ip, 731 netmask, 732 gateway, 733 host=host, 734 admin_username=admin_username, 735 admin_password=admin_password, 736 ) 737 ) 738 739 740def server_power( 741 status, host=None, admin_username=None, admin_password=None, module=None 742): 743 """ 744 status 745 One of 'powerup', 'powerdown', 'powercycle', 'hardreset', 746 'graceshutdown' 747 748 host 749 The chassis host. 750 751 admin_username 752 The username used to access the chassis. 753 754 admin_password 755 The password used to access the chassis. 756 757 module 758 The element to reboot on the chassis such as a blade. If not provided, 759 the chassis will be rebooted. 760 761 CLI Example: 762 763 .. code-block:: bash 764 765 salt dell dracr.server_reboot 766 salt dell dracr.server_reboot module=server-1 767 768 """ 769 return __execute_cmd( 770 "serveraction {}".format(status), 771 host=host, 772 admin_username=admin_username, 773 admin_password=admin_password, 774 module=module, 775 ) 776 777 778def server_reboot(host=None, admin_username=None, admin_password=None, module=None): 779 """ 780 Issues a power-cycle operation on the managed server. This action is 781 similar to pressing the power button on the system's front panel to 782 power down and then power up the system. 783 784 host 785 The chassis host. 786 787 admin_username 788 The username used to access the chassis. 789 790 admin_password 791 The password used to access the chassis. 792 793 module 794 The element to reboot on the chassis such as a blade. If not provided, 795 the chassis will be rebooted. 796 797 CLI Example: 798 799 .. code-block:: bash 800 801 salt dell dracr.server_reboot 802 salt dell dracr.server_reboot module=server-1 803 804 """ 805 return __execute_cmd( 806 "serveraction powercycle", 807 host=host, 808 admin_username=admin_username, 809 admin_password=admin_password, 810 module=module, 811 ) 812 813 814def server_poweroff(host=None, admin_username=None, admin_password=None, module=None): 815 """ 816 Powers down the managed server. 817 818 host 819 The chassis host. 820 821 admin_username 822 The username used to access the chassis. 823 824 admin_password 825 The password used to access the chassis. 826 827 module 828 The element to power off on the chassis such as a blade. 829 If not provided, the chassis will be powered off. 830 831 CLI Example: 832 833 .. code-block:: bash 834 835 salt dell dracr.server_poweroff 836 salt dell dracr.server_poweroff module=server-1 837 """ 838 return __execute_cmd( 839 "serveraction powerdown", 840 host=host, 841 admin_username=admin_username, 842 admin_password=admin_password, 843 module=module, 844 ) 845 846 847def server_poweron(host=None, admin_username=None, admin_password=None, module=None): 848 """ 849 Powers up the managed server. 850 851 host 852 The chassis host. 853 854 admin_username 855 The username used to access the chassis. 856 857 admin_password 858 The password used to access the chassis. 859 860 module 861 The element to power on located on the chassis such as a blade. If 862 not provided, the chassis will be powered on. 863 864 CLI Example: 865 866 .. code-block:: bash 867 868 salt dell dracr.server_poweron 869 salt dell dracr.server_poweron module=server-1 870 """ 871 return __execute_cmd( 872 "serveraction powerup", 873 host=host, 874 admin_username=admin_username, 875 admin_password=admin_password, 876 module=module, 877 ) 878 879 880def server_hardreset(host=None, admin_username=None, admin_password=None, module=None): 881 """ 882 Performs a reset (reboot) operation on the managed server. 883 884 host 885 The chassis host. 886 887 admin_username 888 The username used to access the chassis. 889 890 admin_password 891 The password used to access the chassis. 892 893 module 894 The element to hard reset on the chassis such as a blade. If 895 not provided, the chassis will be reset. 896 897 CLI Example: 898 899 .. code-block:: bash 900 901 salt dell dracr.server_hardreset 902 salt dell dracr.server_hardreset module=server-1 903 """ 904 return __execute_cmd( 905 "serveraction hardreset", 906 host=host, 907 admin_username=admin_username, 908 admin_password=admin_password, 909 module=module, 910 ) 911 912 913def server_powerstatus( 914 host=None, admin_username=None, admin_password=None, module=None 915): 916 """ 917 return the power status for the passed module 918 919 CLI Example: 920 921 .. code-block:: bash 922 923 salt dell drac.server_powerstatus 924 """ 925 ret = __execute_ret( 926 "serveraction powerstatus", 927 host=host, 928 admin_username=admin_username, 929 admin_password=admin_password, 930 module=module, 931 ) 932 933 result = {"retcode": 0} 934 if ret["stdout"] == "ON": 935 result["status"] = True 936 result["comment"] = "Power is on" 937 if ret["stdout"] == "OFF": 938 result["status"] = False 939 result["comment"] = "Power is on" 940 if ret["stdout"].startswith("ERROR"): 941 result["status"] = False 942 result["comment"] = ret["stdout"] 943 944 return result 945 946 947def server_pxe(host=None, admin_username=None, admin_password=None): 948 """ 949 Configure server to PXE perform a one off PXE boot 950 951 CLI Example: 952 953 .. code-block:: bash 954 955 salt dell dracr.server_pxe 956 """ 957 if __execute_cmd( 958 "config -g cfgServerInfo -o cfgServerFirstBootDevice PXE", 959 host=host, 960 admin_username=admin_username, 961 admin_password=admin_password, 962 ): 963 if __execute_cmd( 964 "config -g cfgServerInfo -o cfgServerBootOnce 1", 965 host=host, 966 admin_username=admin_username, 967 admin_password=admin_password, 968 ): 969 return server_reboot 970 else: 971 log.warning("failed to set boot order") 972 return False 973 974 log.warning("failed to configure PXE boot") 975 return False 976 977 978def list_slotnames(host=None, admin_username=None, admin_password=None): 979 """ 980 List the names of all slots in the chassis. 981 982 host 983 The chassis host. 984 985 admin_username 986 The username used to access the chassis. 987 988 admin_password 989 The password used to access the chassis. 990 991 CLI Example: 992 993 .. code-block:: bash 994 995 salt-call --local dracr.list_slotnames host=111.222.333.444 996 admin_username=root admin_password=secret 997 998 """ 999 slotraw = __execute_ret( 1000 "getslotname", 1001 host=host, 1002 admin_username=admin_username, 1003 admin_password=admin_password, 1004 ) 1005 1006 if slotraw["retcode"] != 0: 1007 return slotraw 1008 slots = {} 1009 stripheader = True 1010 for l in slotraw["stdout"].splitlines(): 1011 if l.startswith("<"): 1012 stripheader = False 1013 continue 1014 if stripheader: 1015 continue 1016 fields = l.split() 1017 slots[fields[0]] = {} 1018 slots[fields[0]]["slot"] = fields[0] 1019 if len(fields) > 1: 1020 slots[fields[0]]["slotname"] = fields[1] 1021 else: 1022 slots[fields[0]]["slotname"] = "" 1023 if len(fields) > 2: 1024 slots[fields[0]]["hostname"] = fields[2] 1025 else: 1026 slots[fields[0]]["hostname"] = "" 1027 1028 return slots 1029 1030 1031def get_slotname(slot, host=None, admin_username=None, admin_password=None): 1032 """ 1033 Get the name of a slot number in the chassis. 1034 1035 slot 1036 The number of the slot for which to obtain the name. 1037 1038 host 1039 The chassis host. 1040 1041 admin_username 1042 The username used to access the chassis. 1043 1044 admin_password 1045 The password used to access the chassis. 1046 1047 CLI Example: 1048 1049 .. code-block:: bash 1050 1051 salt-call --local dracr.get_slotname 0 host=111.222.333.444 1052 admin_username=root admin_password=secret 1053 1054 """ 1055 slots = list_slotnames( 1056 host=host, admin_username=admin_username, admin_password=admin_password 1057 ) 1058 # The keys for this dictionary are strings, not integers, so convert the 1059 # argument to a string 1060 slot = str(slot) 1061 return slots[slot]["slotname"] 1062 1063 1064def set_slotname(slot, name, host=None, admin_username=None, admin_password=None): 1065 """ 1066 Set the name of a slot in a chassis. 1067 1068 slot 1069 The slot number to change. 1070 1071 name 1072 The name to set. Can only be 15 characters long. 1073 1074 host 1075 The chassis host. 1076 1077 admin_username 1078 The username used to access the chassis. 1079 1080 admin_password 1081 The password used to access the chassis. 1082 1083 CLI Example: 1084 1085 .. code-block:: bash 1086 1087 salt '*' dracr.set_slotname 2 my-slotname host=111.222.333.444 1088 admin_username=root admin_password=secret 1089 1090 """ 1091 return __execute_cmd( 1092 "config -g cfgServerInfo -o cfgServerName -i {} {}".format(slot, name), 1093 host=host, 1094 admin_username=admin_username, 1095 admin_password=admin_password, 1096 ) 1097 1098 1099def set_chassis_name(name, host=None, admin_username=None, admin_password=None): 1100 """ 1101 Set the name of the chassis. 1102 1103 name 1104 The name to be set on the chassis. 1105 1106 host 1107 The chassis host. 1108 1109 admin_username 1110 The username used to access the chassis. 1111 1112 admin_password 1113 The password used to access the chassis. 1114 1115 CLI Example: 1116 1117 .. code-block:: bash 1118 1119 salt '*' dracr.set_chassis_name my-chassis host=111.222.333.444 1120 admin_username=root admin_password=secret 1121 1122 """ 1123 return __execute_cmd( 1124 "setsysinfo -c chassisname {}".format(name), 1125 host=host, 1126 admin_username=admin_username, 1127 admin_password=admin_password, 1128 ) 1129 1130 1131def get_chassis_name(host=None, admin_username=None, admin_password=None): 1132 """ 1133 Get the name of a chassis. 1134 1135 host 1136 The chassis host. 1137 1138 admin_username 1139 The username used to access the chassis. 1140 1141 admin_password 1142 The password used to access the chassis. 1143 1144 CLI Example: 1145 1146 .. code-block:: bash 1147 1148 salt '*' dracr.get_chassis_name host=111.222.333.444 1149 admin_username=root admin_password=secret 1150 1151 """ 1152 return bare_rac_cmd( 1153 "getchassisname", 1154 host=host, 1155 admin_username=admin_username, 1156 admin_password=admin_password, 1157 ) 1158 1159 1160def inventory(host=None, admin_username=None, admin_password=None): 1161 def mapit(x, y): 1162 return {x: y} 1163 1164 fields = {} 1165 fields["server"] = ["name", "idrac_version", "blade_type", "gen", "updateable"] 1166 fields["switch"] = ["name", "model_name", "hw_version", "fw_version"] 1167 fields["cmc"] = ["name", "cmc_version", "updateable"] 1168 fields["chassis"] = ["name", "fw_version", "fqdd"] 1169 1170 rawinv = __execute_ret( 1171 "getversion", 1172 host=host, 1173 admin_username=admin_username, 1174 admin_password=admin_password, 1175 ) 1176 1177 if rawinv["retcode"] != 0: 1178 return rawinv 1179 1180 in_server = False 1181 in_switch = False 1182 in_cmc = False 1183 in_chassis = False 1184 ret = {} 1185 ret["server"] = {} 1186 ret["switch"] = {} 1187 ret["cmc"] = {} 1188 ret["chassis"] = {} 1189 for l in rawinv["stdout"].splitlines(): 1190 if l.startswith("<Server>"): 1191 in_server = True 1192 in_switch = False 1193 in_cmc = False 1194 in_chassis = False 1195 continue 1196 1197 if l.startswith("<Switch>"): 1198 in_server = False 1199 in_switch = True 1200 in_cmc = False 1201 in_chassis = False 1202 continue 1203 1204 if l.startswith("<CMC>"): 1205 in_server = False 1206 in_switch = False 1207 in_cmc = True 1208 in_chassis = False 1209 continue 1210 1211 if l.startswith("<Chassis Infrastructure>"): 1212 in_server = False 1213 in_switch = False 1214 in_cmc = False 1215 in_chassis = True 1216 continue 1217 1218 if not l: 1219 continue 1220 1221 line = re.split(" +", l.strip()) 1222 1223 if in_server: 1224 ret["server"][line[0]] = { 1225 k: v for d in map(mapit, fields["server"], line) for (k, v) in d.items() 1226 } 1227 if in_switch: 1228 ret["switch"][line[0]] = { 1229 k: v for d in map(mapit, fields["switch"], line) for (k, v) in d.items() 1230 } 1231 if in_cmc: 1232 ret["cmc"][line[0]] = { 1233 k: v for d in map(mapit, fields["cmc"], line) for (k, v) in d.items() 1234 } 1235 if in_chassis: 1236 ret["chassis"][line[0]] = { 1237 k: v for d in map(mapit, fields["chassis"], line) for k, v in d.items() 1238 } 1239 1240 return ret 1241 1242 1243def set_chassis_location(location, host=None, admin_username=None, admin_password=None): 1244 """ 1245 Set the location of the chassis. 1246 1247 location 1248 The name of the location to be set on the chassis. 1249 1250 host 1251 The chassis host. 1252 1253 admin_username 1254 The username used to access the chassis. 1255 1256 admin_password 1257 The password used to access the chassis. 1258 1259 CLI Example: 1260 1261 .. code-block:: bash 1262 1263 salt '*' dracr.set_chassis_location location-name host=111.222.333.444 1264 admin_username=root admin_password=secret 1265 1266 """ 1267 return __execute_cmd( 1268 "setsysinfo -c chassislocation {}".format(location), 1269 host=host, 1270 admin_username=admin_username, 1271 admin_password=admin_password, 1272 ) 1273 1274 1275def get_chassis_location(host=None, admin_username=None, admin_password=None): 1276 """ 1277 Get the location of the chassis. 1278 1279 host 1280 The chassis host. 1281 1282 admin_username 1283 The username used to access the chassis. 1284 1285 admin_password 1286 The password used to access the chassis. 1287 1288 CLI Example: 1289 1290 .. code-block:: bash 1291 1292 salt '*' dracr.set_chassis_location host=111.222.333.444 1293 admin_username=root admin_password=secret 1294 1295 """ 1296 return system_info( 1297 host=host, admin_username=admin_username, admin_password=admin_password 1298 )["Chassis Information"]["Chassis Location"] 1299 1300 1301def set_chassis_datacenter( 1302 location, host=None, admin_username=None, admin_password=None 1303): 1304 """ 1305 Set the location of the chassis. 1306 1307 location 1308 The name of the datacenter to be set on the chassis. 1309 1310 host 1311 The chassis host. 1312 1313 admin_username 1314 The username used to access the chassis. 1315 1316 admin_password 1317 The password used to access the chassis. 1318 1319 CLI Example: 1320 1321 .. code-block:: bash 1322 1323 salt '*' dracr.set_chassis_datacenter datacenter-name host=111.222.333.444 1324 admin_username=root admin_password=secret 1325 1326 """ 1327 return set_general( 1328 "cfgLocation", 1329 "cfgLocationDatacenter", 1330 location, 1331 host=host, 1332 admin_username=admin_username, 1333 admin_password=admin_password, 1334 ) 1335 1336 1337def get_chassis_datacenter(host=None, admin_username=None, admin_password=None): 1338 """ 1339 Get the datacenter of the chassis. 1340 1341 host 1342 The chassis host. 1343 1344 admin_username 1345 The username used to access the chassis. 1346 1347 admin_password 1348 The password used to access the chassis. 1349 1350 CLI Example: 1351 1352 .. code-block:: bash 1353 1354 salt '*' dracr.set_chassis_location host=111.222.333.444 1355 admin_username=root admin_password=secret 1356 1357 """ 1358 return get_general( 1359 "cfgLocation", 1360 "cfgLocationDatacenter", 1361 host=host, 1362 admin_username=admin_username, 1363 admin_password=admin_password, 1364 ) 1365 1366 1367def set_general( 1368 cfg_sec, cfg_var, val, host=None, admin_username=None, admin_password=None 1369): 1370 return __execute_cmd( 1371 "config -g {} -o {} {}".format(cfg_sec, cfg_var, val), 1372 host=host, 1373 admin_username=admin_username, 1374 admin_password=admin_password, 1375 ) 1376 1377 1378def get_general(cfg_sec, cfg_var, host=None, admin_username=None, admin_password=None): 1379 ret = __execute_ret( 1380 "getconfig -g {} -o {}".format(cfg_sec, cfg_var), 1381 host=host, 1382 admin_username=admin_username, 1383 admin_password=admin_password, 1384 ) 1385 1386 if ret["retcode"] == 0: 1387 return ret["stdout"] 1388 else: 1389 return ret 1390 1391 1392def idrac_general( 1393 blade_name, 1394 command, 1395 idrac_password=None, 1396 host=None, 1397 admin_username=None, 1398 admin_password=None, 1399): 1400 """ 1401 Run a generic racadm command against a particular 1402 blade in a chassis. Blades are usually named things like 1403 'server-1', 'server-2', etc. If the iDRAC has a different 1404 password than the CMC, then you can pass it with the 1405 idrac_password kwarg. 1406 1407 :param blade_name: Name of the blade to run the command on 1408 :param command: Command like to pass to racadm 1409 :param idrac_password: Password for the iDRAC if different from the CMC 1410 :param host: Chassis hostname 1411 :param admin_username: CMC username 1412 :param admin_password: CMC password 1413 :return: stdout if the retcode is 0, otherwise a standard cmd.run_all dictionary 1414 1415 CLI Example: 1416 1417 .. code-block:: bash 1418 1419 salt fx2 chassis.cmd idrac_general server-1 'get BIOS.SysProfileSettings' 1420 1421 """ 1422 1423 module_network = network_info(host, admin_username, admin_password, blade_name) 1424 1425 if idrac_password is not None: 1426 password = idrac_password 1427 else: 1428 password = admin_password 1429 1430 idrac_ip = module_network["Network"]["IP Address"] 1431 1432 ret = __execute_ret( 1433 command, host=idrac_ip, admin_username="root", admin_password=password 1434 ) 1435 1436 if ret["retcode"] == 0: 1437 return ret["stdout"] 1438 else: 1439 return ret 1440 1441 1442def _update_firmware(cmd, host=None, admin_username=None, admin_password=None): 1443 1444 if not admin_username: 1445 admin_username = __pillar__["proxy"]["admin_username"] 1446 if not admin_username: 1447 admin_password = __pillar__["proxy"]["admin_password"] 1448 1449 ret = __execute_ret( 1450 cmd, host=host, admin_username=admin_username, admin_password=admin_password 1451 ) 1452 1453 if ret["retcode"] == 0: 1454 return ret["stdout"] 1455 else: 1456 return ret 1457 1458 1459def bare_rac_cmd(cmd, host=None, admin_username=None, admin_password=None): 1460 ret = __execute_ret( 1461 "{}".format(cmd), 1462 host=host, 1463 admin_username=admin_username, 1464 admin_password=admin_password, 1465 ) 1466 1467 if ret["retcode"] == 0: 1468 return ret["stdout"] 1469 else: 1470 return ret 1471 1472 1473def update_firmware(filename, host=None, admin_username=None, admin_password=None): 1474 """ 1475 Updates firmware using local firmware file 1476 1477 .. code-block:: bash 1478 1479 salt dell dracr.update_firmware firmware.exe 1480 1481 This executes the following command on your FX2 1482 (using username and password stored in the pillar data) 1483 1484 .. code-block:: bash 1485 1486 racadm update –f firmware.exe -u user –p pass 1487 1488 """ 1489 if os.path.exists(filename): 1490 return _update_firmware( 1491 "update -f {}".format(filename), 1492 host=None, 1493 admin_username=None, 1494 admin_password=None, 1495 ) 1496 else: 1497 raise CommandExecutionError("Unable to find firmware file {}".format(filename)) 1498 1499 1500def update_firmware_nfs_or_cifs( 1501 filename, share, host=None, admin_username=None, admin_password=None 1502): 1503 """ 1504 Executes the following for CIFS 1505 (using username and password stored in the pillar data) 1506 1507 .. code-block:: bash 1508 1509 racadm update -f <updatefile> -u user –p pass -l //IP-Address/share 1510 1511 Or for NFS 1512 (using username and password stored in the pillar data) 1513 1514 .. code-block:: bash 1515 1516 racadm update -f <updatefile> -u user –p pass -l IP-address:/share 1517 1518 1519 Salt command for CIFS: 1520 1521 .. code-block:: bash 1522 1523 salt dell dracr.update_firmware_nfs_or_cifs \ 1524 firmware.exe //IP-Address/share 1525 1526 1527 Salt command for NFS: 1528 1529 .. code-block:: bash 1530 1531 salt dell dracr.update_firmware_nfs_or_cifs \ 1532 firmware.exe IP-address:/share 1533 """ 1534 if os.path.exists(filename): 1535 return _update_firmware( 1536 "update -f {} -l {}".format(filename, share), 1537 host=None, 1538 admin_username=None, 1539 admin_password=None, 1540 ) 1541 else: 1542 raise CommandExecutionError("Unable to find firmware file {}".format(filename)) 1543 1544 1545# def get_idrac_nic() 1546