1"""
2Support IPMI commands over LAN. This module does not talk to the local
3systems hardware through IPMI drivers. It uses a python module `pyghmi`.
4
5:depends: Python module pyghmi.
6    You can install pyghmi using pip:
7
8    .. code-block:: bash
9
10        pip install pyghmi
11
12:configuration: The following configuration defaults can be
13    define (pillar or config files):
14
15    .. code-block:: python
16
17        ipmi.config:
18            api_host: 127.0.0.1
19            api_user: admin
20            api_pass: apassword
21            api_port: 623
22            api_kg: None
23
24    Usage can override the config defaults:
25
26    .. code-block:: bash
27
28            salt-call ipmi.get_user api_host=myipmienabled.system
29                                    api_user=admin api_pass=pass
30                                    uid=1
31"""
32
33
34IMPORT_ERR = None
35try:
36    from pyghmi.ipmi import command
37    from pyghmi.ipmi.private import session
38except Exception as ex:  # pylint: disable=broad-except
39    IMPORT_ERR = str(ex)
40
41__virtualname__ = "ipmi"
42
43
44def __virtual__():
45    return (IMPORT_ERR is None, IMPORT_ERR)
46
47
48def _get_config(**kwargs):
49    """
50    Return configuration
51    """
52    config = {
53        "api_host": "localhost",
54        "api_port": 623,
55        "api_user": "admin",
56        "api_pass": "",
57        "api_kg": None,
58        "api_login_timeout": 2,
59    }
60    if "__salt__" in globals():
61        config_key = "{}.config".format(__virtualname__)
62        config.update(__salt__["config.get"](config_key, {}))
63    for k in set(config) & set(kwargs):
64        config[k] = kwargs[k]
65    return config
66
67
68class _IpmiCommand:
69    o = None
70
71    def __init__(self, **kwargs):
72        config = _get_config(**kwargs)
73        self.o = command.Command(
74            bmc=config["api_host"],
75            userid=config["api_user"],
76            password=config["api_pass"],
77            port=config["api_port"],
78            kg=config["api_kg"],
79        )
80
81    def __enter__(self):
82        return self.o
83
84    def __exit__(self, type, value, traceback):
85        if self.o:
86            self.o.ipmi_session.logout()
87
88
89class _IpmiSession:
90    o = None
91
92    def _onlogon(self, response):
93        if "error" in response:
94            raise Exception(response["error"])
95
96    def __init__(self, **kwargs):
97        config = _get_config(**kwargs)
98        self.o = session.Session(
99            bmc=config["api_host"],
100            userid=config["api_user"],
101            password=config["api_pass"],
102            port=config["api_port"],
103            kg=config["api_kg"],
104            onlogon=self._onlogon,
105        )
106        while not self.o.logged:
107            # override timeout
108            self.o.maxtimeout = config["api_login_timeout"]
109            self.o.wait_for_rsp(timeout=1)
110        self.o.maxtimeout = 5
111
112    def __enter__(self):
113        return self.o
114
115    def __exit__(self, type, value, traceback):
116        if self.o:
117            self.o.logout()
118
119
120def raw_command(
121    netfn, command, bridge_request=None, data=(), retry=True, delay_xmit=None, **kwargs
122):
123    """
124    Send raw ipmi command
125
126    This allows arbitrary IPMI bytes to be issued.  This is commonly used
127    for certain vendor specific commands.
128
129    :param netfn: Net function number
130    :param command: Command value
131    :param bridge_request: The target slave address and channel number for
132                        the bridge request.
133    :param data: Command data as a tuple or list
134    :param kwargs:
135        - api_host=127.0.0.1
136        - api_user=admin
137        - api_pass=example
138        - api_port=623
139        - api_kg=None
140
141    :returns: dict -- The response from IPMI device
142
143    CLI Examples:
144
145    .. code-block:: bash
146
147        salt-call ipmi.raw_command netfn=0x06 command=0x46 data=[0x02]
148        # this will return the name of the user with id 2 in bytes
149    """
150    with _IpmiSession(**kwargs) as s:
151        r = s.raw_command(
152            netfn=int(netfn),
153            command=int(command),
154            bridge_request=bridge_request,
155            data=data,
156            retry=retry,
157            delay_xmit=delay_xmit,
158        )
159        return r
160
161
162def fast_connect_test(**kwargs):
163    """
164    Returns True if connection success.
165    This uses an aggressive timeout value!
166
167    :param kwargs:
168        - api_host=127.0.0.1
169        - api_user=admin
170        - api_pass=example
171        - api_port=623
172        - api_kg=None
173
174    CLI Examples:
175
176    .. code-block:: bash
177
178        salt-call ipmi.fast_connect_test api_host=172.168.0.9
179    """
180    try:
181        if "api_login_timeout" not in kwargs:
182            kwargs["api_login_timeout"] = 0
183        with _IpmiSession(**kwargs) as s:
184            # TODO: should a test command be fired?
185            # s.raw_command(netfn=6, command=1, retry=False)
186            return True
187    except Exception as e:  # pylint: disable=broad-except
188        return False
189    return True
190
191
192def set_channel_access(
193    channel=14,
194    access_update_mode="non_volatile",
195    alerting=False,
196    per_msg_auth=False,
197    user_level_auth=False,
198    access_mode="always",
199    privilege_update_mode="non_volatile",
200    privilege_level="administrator",
201    **kwargs
202):
203    """
204    Set channel access
205
206    :param channel: number [1:7]
207
208    :param access_update_mode:
209        - 'dont_change'  = don't set or change Channel Access
210        - 'non_volatile' = set non-volatile Channel Access
211        - 'volatile'     = set volatile (active) setting of Channel Access
212
213    :param alerting:
214        PEF Alerting Enable/Disable
215
216        - True  = enable PEF Alerting
217        - False = disable PEF Alerting on this channel
218          (Alert Immediate command can still be used to generate alerts)
219
220    :param per_msg_auth:
221        Per-message Authentication
222
223        - True  = enable
224        - False = disable Per-message Authentication. [Authentication required to
225          activate any session on this channel, but authentication not
226          used on subsequent packets for the session.]
227
228    :param user_level_auth:
229        User Level Authentication Enable/Disable
230
231        - True  = enable User Level Authentication. All User Level commands are
232          to be authenticated per the Authentication Type that was
233          negotiated when the session was activated.
234        - False = disable User Level Authentication. Allow User Level commands to
235          be executed without being authenticated.
236          If the option to disable User Level Command authentication is
237          accepted, the BMC will accept packets with Authentication Type
238          set to None if they contain user level commands.
239          For outgoing packets, the BMC returns responses with the same
240          Authentication Type that was used for the request.
241
242    :param access_mode:
243        Access Mode for IPMI messaging (PEF Alerting is enabled/disabled
244        separately from IPMI messaging)
245
246        - disabled = disabled for IPMI messaging
247        - pre_boot = pre-boot only channel only available when system is
248          in a powered down state or in BIOS prior to start of boot.
249        - always   = channel always available regardless of system mode.
250          BIOS typically dedicates the serial connection to the BMC.
251        - shared   = same as always available, but BIOS typically leaves the
252          serial port available for software use.
253
254    :param privilege_update_mode:
255        Channel Privilege Level Limit. This value sets the maximum privilege
256        level that can be accepted on the specified channel.
257
258        - dont_change  = don't set or change channel Privilege Level Limit
259        - non_volatile = non-volatile Privilege Level Limit according
260        - volatile     = volatile setting of Privilege Level Limit
261
262    :param privilege_level:
263        Channel Privilege Level Limit
264
265        - reserved      = unused
266        - callback
267        - user
268        - operator
269        - administrator
270        - proprietary   = used by OEM
271
272    :param kwargs:
273        - api_host=127.0.0.1
274        - api_user=admin
275        - api_pass=example
276        - api_port=623
277        - api_kg=None
278
279    CLI Examples:
280
281    .. code-block:: bash
282
283        salt-call ipmi.set_channel_access privilege_level='administrator'
284    """
285    with _IpmiCommand(**kwargs) as s:
286        return s.set_channel_access(
287            channel,
288            access_update_mode,
289            alerting,
290            per_msg_auth,
291            user_level_auth,
292            access_mode,
293            privilege_update_mode,
294            privilege_level,
295        )
296
297
298def get_channel_access(channel=14, read_mode="non_volatile", **kwargs):
299    """
300    :param kwargs:api_host='127.0.0.1' api_user='admin' api_pass='example' api_port=623
301
302    :param channel: number [1:7]
303
304    :param read_mode:
305        - non_volatile  = get non-volatile Channel Access
306        - volatile      = get present volatile (active) setting of Channel Access
307
308    :param kwargs:
309        - api_host=127.0.0.1
310        - api_user=admin
311        - api_pass=example
312        - api_port=623
313        - api_kg=None
314
315    Return Data
316
317        A Python dict with the following keys/values:
318
319        .. code-block:: python
320
321            {
322                alerting:
323                per_msg_auth:
324                user_level_auth:
325                access_mode:{ (ONE OF)
326                    0: 'disabled',
327                    1: 'pre_boot',
328                    2: 'always',
329                    3: 'shared'
330                }
331                privilege_level: { (ONE OF)
332                    1: 'callback',
333                    2: 'user',
334                    3: 'operator',
335                    4: 'administrator',
336                    5: 'proprietary',
337                }
338            }
339
340    CLI Examples:
341
342    .. code-block:: bash
343
344        salt-call ipmi.get_channel_access channel=1
345    """
346    with _IpmiCommand(**kwargs) as s:
347        return s.get_channel_access(channel)
348
349
350def get_channel_info(channel=14, **kwargs):
351    """
352    Get channel info
353
354    :param channel: number [1:7]
355    :param kwargs:
356        - api_host=127.0.0.1
357        - api_user=admin
358        - api_pass=example
359        - api_port=623
360        - api_kg=None
361
362    Return Data
363        channel session supports
364
365        .. code-block:: none
366
367                - no_session: channel is session-less
368                - single: channel is single-session
369                - multi: channel is multi-session
370                - auto: channel is session-based (channel could alternate between
371                    single- and multi-session operation, as can occur with a
372                    serial/modem channel that supports connection mode auto-detect)
373
374    CLI Examples:
375
376    .. code-block:: bash
377
378        salt-call ipmi.get_channel_info
379    """
380    with _IpmiCommand(**kwargs) as s:
381        return s.get_channel_info(channel)
382
383
384def set_user_access(
385    uid,
386    channel=14,
387    callback=True,
388    link_auth=True,
389    ipmi_msg=True,
390    privilege_level="administrator",
391    **kwargs
392):
393    """
394    Set user access
395
396    :param uid: user number [1:16]
397
398    :param channel: number [1:7]
399
400    :param callback:
401        User Restricted to Callback
402
403        - False = User Privilege Limit is determined by the User Privilege Limit
404          parameter, below, for both callback and non-callback connections.
405        - True  = User Privilege Limit is determined by the User Privilege Limit
406          parameter for callback connections, but is restricted to Callback
407          level for non-callback connections. Thus, a user can only initiate
408          a Callback when they 'call in' to the BMC, but once the callback
409          connection has been made, the user could potentially establish a
410          session as an Operator.
411
412    :param link_auth: User Link authentication enable/disable (used to enable
413        whether this user's name and password information will be used for link
414        authentication, e.g. PPP CHAP) for the given channel. Link
415        authentication itself is a global setting for the channel and is
416        enabled/disabled via the serial/modem configuration parameters.
417
418    :param ipmi_msg: User IPMI Messaging: (used to enable/disable whether
419        this user's name and password information will be used for IPMI
420        Messaging. In this case, 'IPMI Messaging' refers to the ability to
421        execute generic IPMI commands that are not associated with a
422        particular payload type. For example, if IPMI Messaging is disabled for
423        a user, but that user is enabled for activating the SOL
424        payload type, then IPMI commands associated with SOL and session
425        management, such as Get SOL Configuration Parameters and Close Session
426        are available, but generic IPMI commands such as Get SEL Time are
427        unavailable.)
428
429    :param privilege_level:
430        User Privilege Limit. (Determines the maximum privilege level that the
431        user is allowed to switch to on the specified channel.)
432
433        - callback
434        - user
435        - operator
436        - administrator
437        - proprietary
438        - no_access
439
440    :param kwargs:
441        - api_host=127.0.0.1
442        - api_user=admin
443        - api_pass=example
444        - api_port=623
445        - api_kg=None
446
447    CLI Examples:
448
449    .. code-block:: bash
450
451        salt-call ipmi.set_user_access uid=2 privilege_level='operator'
452    """
453    with _IpmiCommand(**kwargs) as s:
454        return s.set_user_access(
455            uid, channel, callback, link_auth, ipmi_msg, privilege_level
456        )
457
458
459def get_user_access(uid, channel=14, **kwargs):
460    """
461    Get user access
462
463    :param uid: user number [1:16]
464    :param channel: number [1:7]
465    :param kwargs:
466        - api_host=127.0.0.1
467        - api_user=admin
468        - api_pass=example
469        - api_port=623
470        - api_kg=None
471
472    Return Data
473
474    .. code-block:: none
475
476        channel_info:
477            - max_user_count = maximum number of user IDs on this channel
478            - enabled_users = count of User ID slots presently in use
479            - users_with_fixed_names = count of user IDs with fixed names
480        access:
481            - callback
482            - link_auth
483            - ipmi_msg
484            - privilege_level: [reserved, callback, user, operator
485                               administrator, proprietary, no_access]
486
487    CLI Examples:
488
489    .. code-block:: bash
490
491        salt-call ipmi.get_user_access uid=2
492    """
493    ## user access available during call-in or callback direct connection
494    with _IpmiCommand(**kwargs) as s:
495        return s.get_user_access(uid, channel=channel)
496
497
498def set_user_name(uid, name, **kwargs):
499    """
500    Set user name
501
502    :param uid: user number [1:16]
503    :param name: username (limit of 16bytes)
504    :param kwargs:
505        - api_host=127.0.0.1
506        - api_user=admin
507        - api_pass=example
508        - api_port=623
509        - api_kg=None
510
511    CLI Examples:
512
513    .. code-block:: bash
514
515        salt-call ipmi.set_user_name uid=2 name='steverweber'
516    """
517    with _IpmiCommand(**kwargs) as s:
518        return s.set_user_name(uid, name)
519
520
521def get_user_name(uid, return_none_on_error=True, **kwargs):
522    """
523    Get user name
524
525    :param uid: user number [1:16]
526    :param return_none_on_error: return None on error
527    :param kwargs:
528        - api_host=127.0.0.1
529        - api_user=admin
530        - api_pass=example
531        - api_port=623
532        - api_kg=None
533
534    CLI Examples:
535
536    .. code-block:: bash
537
538        salt-call ipmi.get_user_name uid=2
539    """
540    with _IpmiCommand(**kwargs) as s:
541        return s.get_user_name(uid, return_none_on_error=True)
542
543
544def set_user_password(uid, mode="set_password", password=None, **kwargs):
545    """
546    Set user password and (modes)
547
548    :param uid: id number of user.  see: get_names_uid()['name']
549
550    :param mode:
551        - disable       = disable user connections
552        - enable        = enable user connections
553        - set_password  = set or ensure password
554        - test_password = test password is correct
555    :param password: max 16 char string
556        (optional when mode is [disable or enable])
557    :param kwargs:
558        - api_host=127.0.0.1
559        - api_user=admin
560        - api_pass=example
561        - api_port=623
562        - api_kg=None
563
564    :return:
565        True on success
566        when mode = test_password, return False on bad password
567
568    CLI Example:
569
570    .. code-block:: bash
571
572        salt-call ipmi.set_user_password api_host=127.0.0.1 api_user=admin api_pass=pass
573                                         uid=1 password=newPass
574        salt-call ipmi.set_user_password uid=1 mode=enable
575    """
576    with _IpmiCommand(**kwargs) as s:
577        s.set_user_password(uid, mode="set_password", password=password)
578    return True
579
580
581def get_health(**kwargs):
582    """
583    Get Summarize health
584
585    This provides a summary of the health of the managed system.
586    It additionally provides an iterable list of reasons for
587    warning, critical, or failed assessments.
588
589    good health: {'badreadings': [], 'health': 0}
590
591    :param kwargs:
592        - api_host=127.0.0.1
593        - api_user=admin
594        - api_pass=example
595        - api_port=623
596        - api_kg=None
597
598    CLI Example:
599
600    .. code-block:: bash
601
602        salt-call ipmi.get_health api_host=127.0.0.1 api_user=admin api_pass=pass
603    """
604    with _IpmiCommand(**kwargs) as s:
605        return s.get_health()
606
607
608def get_power(**kwargs):
609    """
610    Get current power state
611
612    The response, if successful, should contain 'powerstate' key and
613    either 'on' or 'off' to indicate current state.
614
615    :param kwargs:
616        - api_host=127.0.0.1
617        - api_user=admin
618        - api_pass=example
619        - api_port=623
620        - api_kg=None
621
622    CLI Example:
623
624    .. code-block:: bash
625
626        salt-call ipmi.get_power api_host=127.0.0.1 api_user=admin api_pass=pass
627    """
628    with _IpmiCommand(**kwargs) as s:
629        return s.get_power()["powerstate"]
630
631
632def get_sensor_data(**kwargs):
633    """
634    Get sensor readings
635
636    Iterates sensor reading objects
637
638    :param kwargs:
639        - api_host=127.0.0.1
640        - api_user=admin
641        - api_pass=example
642        - api_port=623
643        - api_kg=None
644
645    CLI Example:
646
647    .. code-block:: bash
648
649        salt-call ipmi.get_sensor_data api_host=127.0.0.1 api_user=admin api_pass=pass
650    """
651    import ast
652
653    with _IpmiCommand(**kwargs) as s:
654        data = {}
655        for reading in s.get_sensor_data():
656            if reading:
657                r = ast.literal_eval(repr(reading))
658                data[r.pop("name")] = r
659    return data
660
661
662def get_bootdev(**kwargs):
663    """
664    Get current boot device override information.
665
666    Provides the current requested boot device.  Be aware that not all IPMI
667    devices support this.  Even in BMCs that claim to, occasionally the
668    BIOS or UEFI fail to honor it. This is usually only applicable to the
669    next reboot.
670
671    :param kwargs:
672        - api_host=127.0.0.1
673        - api_user=admin
674        - api_pass=example
675        - api_port=623
676        - api_kg=None
677
678    CLI Example:
679
680    .. code-block:: bash
681
682        salt-call ipmi.get_bootdev api_host=127.0.0.1 api_user=admin api_pass=pass
683    """
684    with _IpmiCommand(**kwargs) as s:
685        return s.get_bootdev()
686
687
688def set_power(state="power_on", wait=True, **kwargs):
689    """
690    Request power state change
691
692    :param name:
693        * power_on -- system turn on
694        * power_off -- system turn off (without waiting for OS)
695        * shutdown -- request OS proper shutdown
696        * reset -- reset (without waiting for OS)
697        * boot -- If system is off, then 'on', else 'reset'
698
699    :param ensure: If (bool True), do not return until system actually completes
700                requested state change for 300 seconds.
701                If a non-zero (int), adjust the wait time to the
702                requested number of seconds
703    :param kwargs:
704        - api_host=127.0.0.1
705        - api_user=admin
706        - api_pass=example
707        - api_port=623
708        - api_kg=None
709
710    :returns: dict -- A dict describing the response retrieved
711
712    CLI Examples:
713
714    .. code-block:: bash
715
716        salt-call ipmi.set_power state=shutdown wait=True
717    """
718    if state is True or state == "power_on":
719        state = "on"
720    if state is False or state == "power_off":
721        state = "off"
722    with _IpmiCommand(**kwargs) as s:
723        return s.set_power(state, wait=wait)
724
725
726def set_bootdev(bootdev="default", persist=False, uefiboot=False, **kwargs):
727    """
728    Set boot device to use on next reboot
729
730    :param bootdev:
731        - network: Request network boot
732        - hd: Boot from hard drive
733        - safe: Boot from hard drive, requesting 'safe mode'
734        - optical: boot from CD/DVD/BD drive
735        - setup: Boot into setup utility
736        - default: remove any IPMI directed boot device
737          request
738
739    :param persist: If true, ask that system firmware use this device
740                    beyond next boot.  Be aware many systems do not honor
741                    this
742
743    :param uefiboot: If true, request UEFI boot explicitly.  Strictly
744                    speaking, the spec suggests that if not set, the system
745                    should BIOS boot and offers no "don't care" option.
746                    In practice, this flag not being set does not preclude
747                    UEFI boot on any system I've encountered.
748
749    :param kwargs:
750        - api_host=127.0.0.1
751        - api_user=admin
752        - api_pass=example
753        - api_port=623
754        - api_kg=None
755
756    :returns: dict or True -- If callback is not provided, the response
757
758    CLI Examples:
759
760    .. code-block:: bash
761
762        salt-call ipmi.set_bootdev bootdev=network persist=True
763    """
764    with _IpmiCommand(**kwargs) as s:
765        return s.set_bootdev(bootdev)
766
767
768def set_identify(on=True, duration=600, **kwargs):
769    """
770    Request identify light
771
772    Request the identify light to turn off, on for a duration,
773    or on indefinitely.  Other than error exceptions,
774
775    :param on: Set to True to force on or False to force off
776    :param duration: Set if wanting to request turn on for a duration
777                    in seconds, None = indefinitely.
778    :param kwargs:
779        - api_host=127.0.0.1
780        - api_user=admin
781        - api_pass=example
782        - api_port=623
783        - api_kg=None
784
785    CLI Examples:
786
787    .. code-block:: bash
788
789        salt-call ipmi.set_identify
790    """
791    with _IpmiCommand(**kwargs) as s:
792        return s.set_identify(on=on, duration=duration)
793
794
795def get_channel_max_user_count(channel=14, **kwargs):
796    """
797    Get max users in channel
798
799    :param channel: number [1:7]
800    :param kwargs:
801        - api_host=127.0.0.1
802        - api_user=admin
803        - api_pass=example
804        - api_port=623
805        - api_kg=None
806    :return: int -- often 16
807
808    CLI Examples:
809
810    .. code-block:: bash
811
812        salt-call ipmi.get_channel_max_user_count
813    """
814    access = get_user_access(channel=channel, uid=1, **kwargs)
815    return access["channel_info"]["max_user_count"]
816
817
818def get_user(uid, channel=14, **kwargs):
819    """
820    Get user from uid and access on channel
821
822    :param uid: user number [1:16]
823    :param channel: number [1:7]
824    :param kwargs:
825        - api_host=127.0.0.1
826        - api_user=admin
827        - api_pass=example
828        - api_port=623
829        - api_kg=None
830
831    Return Data
832
833    .. code-block:: none
834
835        name: (str)
836        uid: (int)
837        channel: (int)
838        access:
839            - callback (bool)
840            - link_auth (bool)
841            - ipmi_msg (bool)
842            - privilege_level: (str)[callback, user, operatorm administrator,
843                                    proprietary, no_access]
844
845    CLI Examples:
846
847    .. code-block:: bash
848
849        salt-call ipmi.get_user uid=2
850    """
851    name = get_user_name(uid, **kwargs)
852    access = get_user_access(uid, channel, **kwargs)
853    data = {"name": name, "uid": uid, "channel": channel, "access": access["access"]}
854    return data
855
856
857def get_users(channel=14, **kwargs):
858    """
859    get list of users and access information
860
861    :param channel: number [1:7]
862
863    :param kwargs:
864        - api_host=127.0.0.1
865        - api_user=admin
866        - api_pass=example
867        - api_port=623
868        - api_kg=None
869
870    :return:
871        - name: (str)
872        - uid: (int)
873        - channel: (int)
874        - access:
875            - callback (bool)
876            - link_auth (bool)
877            - ipmi_msg (bool)
878            - privilege_level: (str)[callback, user, operatorm administrator,
879              proprietary, no_access]
880
881    CLI Examples:
882
883    .. code-block:: bash
884
885        salt-call ipmi.get_users api_host=172.168.0.7
886    """
887    with _IpmiCommand(**kwargs) as c:
888        return c.get_users(channel)
889
890
891def create_user(
892    uid,
893    name,
894    password,
895    channel=14,
896    callback=False,
897    link_auth=True,
898    ipmi_msg=True,
899    privilege_level="administrator",
900    **kwargs
901):
902    """
903    create/ensure a user is created with provided settings.
904
905    :param privilege_level:
906        User Privilege Limit. (Determines the maximum privilege level that
907        the user is allowed to switch to on the specified channel.)
908        * callback
909        * user
910        * operator
911        * administrator
912        * proprietary
913        * no_access
914    :param kwargs:
915        - api_host=127.0.0.1
916        - api_user=admin
917        - api_pass=example
918        - api_port=623
919        - api_kg=None
920
921    CLI Examples:
922
923    .. code-block:: bash
924
925        salt-call ipmi.create_user uid=2 name=steverweber api_host=172.168.0.7 api_pass=nevertell
926    """
927    with _IpmiCommand(**kwargs) as c:
928        return c.create_user(
929            uid, name, password, channel, callback, link_auth, ipmi_msg, privilege_level
930        )
931
932
933def user_delete(uid, channel=14, **kwargs):
934    """
935    Delete user (helper)
936
937    :param uid: user number [1:16]
938    :param channel: number [1:7]
939    :param kwargs:
940        - api_host=127.0.0.1
941        - api_user=admin
942        - api_pass=example
943        - api_port=623
944        - api_kg=None
945
946    CLI Examples:
947
948    .. code-block:: bash
949
950        salt-call ipmi.user_delete uid=2
951    """
952    with _IpmiCommand(**kwargs) as c:
953        return c.user_delete(uid, channel)
954