Class IpmiClient

java.lang.Object
org.metricshub.ipmi.client.IpmiClient
All Implemented Interfaces:
AutoCloseable

public final class IpmiClient extends Object implements AutoCloseable
A client of one BMC over IPMI 2.0 (RMCP+). It is built with builder(String), owns one session, opened by the first operation that needs one and kept alive until close(), and runs its operations one at a time on that session.
 IpmiClient.Builder builder = IpmiClient.builder("bmc.example.com").credentials("monitor", password);
 try (IpmiClient bmc = builder.privilege(PrivilegeLevel.Operator).build()) {
        System.out.println(bmc.deviceId()); // manufacturer, product, firmware revision
        ChassisStatus chassis = bmc.chassisStatus();
        if (!chassis.powerOn()) {
                bmc.chassisControl(PowerCommand.PowerUp); // the Operator privilege set above
        }
        for (Sensor sensor : bmc.sensors().types(SensorType.Temperature).execute()) {
                sensor.reading().ifPresent(value -> System.out.println(sensor.name() + " = " + value + " " + sensor.unit()));
        }
        for (Fru fru : bmc.frus().execute()) {
                System.out.println(fru.name() + ": " + fru.manufacturer() + " " + fru.model() + " S/N " + fru.serialNumber());
        }
        for (SelEntry entry : bmc.sel().execute()) {
                System.out.println(entry);
        }
 }
 

Close the client: an open client holds one of the few session slots of the BMC (typically 4 to 8) with its keep-alive messages for as long as the JVM runs. Use try-with-resources.

Session recovery: when the session is lost (the BMC rebooted or expired it), the next operation opens a new one. A read operation that fails because the session was lost while it ran is retried once on a new session; send(IpmiCommandCoder), raw(int, int), sol().open() and the control operations are never replayed.

Threads: a client can be shared between threads; its operations are serialized. A stream (SensorsRequest.stream(), FrusRequest.stream(), SelRequest.stream()) reads one element per operation, so the operations of other threads run between two of its elements. BMCs accept a limited number of sessions and drop replies under load, so the client uses a single session, plus one for a Serial over LAN console that the BMC serves on another UDP port. Clients of different BMCs run in parallel.

Failures of the BMC and of the network are reported as IpmiClientExceptions, whose subclasses say what to act on. A call the client does not allow throws an IllegalStateException: any operation of a closed client, an operation that needs a session on a client built without credentials (every operation but capabilities()), and a PowerCommand.PowerCycle of a system that is off. An invalid setting or argument throws an IllegalArgumentException before anything is sent to the BMC, and a null argument a NullPointerException, except for builder(String) (IllegalArgumentException) and IpmiClient.Builder.bmcKey(byte[]) (no key).

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final class 
    Builds an IpmiClient: the BMC, the credentials and the session settings.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final Duration
    Period of the keep-alive messages when the builder sets none: 30 seconds.
    static final Duration
    Timeout of each message when the builder sets none: 5 seconds.
    static final int
    Resends of a message (IpmiClient.Builder.retries(int)) when the builder sets none: 3.
    static final Duration
    Deadline of each operation when the builder sets none: 2 minutes.
  • Method Summary

    Modifier and Type
    Method
    Description
    Starts building a client of the BMC at the given host.
    Reads what the BMC supports before any login: its authentication options and the cipher suites it offers (Get Channel Authentication Capabilities and Get Channel Cipher Suites).
    void
    Controls the power of the chassis (Chassis Control, IPMI 2.0 section 28.3): power up, power down, power cycle, hard reset, soft shutdown or diagnostic interrupt.
    void
    chassisIdentify(int seconds)
    Makes the chassis identify itself (Chassis Identify, IPMI 2.0 section 28.5), typically with a blinking LED, for the given number of seconds, or turns the identify off.
    void
    Makes the chassis identify itself until chassisIdentify(0) turns it off: the optional "force identify on" of Chassis Identify, which not every BMC implements.
    Reads the state of the chassis: power, faults, intrusion, identify LED (Get Chassis Status).
    void
    Closes the session (Close Session, sent once and waited for at most the message timeout plus one second), releases the UDP port and the threads.
    Reads the identity of the BMC: manufacturer and product IDs, firmware revision, IPMI version, functions (Get Device ID).
    Reads the FRU inventories of the system: frus().execute() for all of them, with ids() to select some, and frus().stream() to get each FRU as soon as it is read.
    Returns the host name or IP address of the BMC.
    raw(int networkFunction, int command)
    Sends any request in the session, like ipmitool raw, and returns its reply whatever its completion code: bmc.raw(0x2C, 0x01).data(0xDC, 0x01).execute() is Get DCMI Capabilities Info.
    sel()
    Reads the System Event Log (SEL): sel().execute() for every entry, with SelRequest.since(SelEntry) for the entries added after one already read.
    <R extends ResponseData>
    R
    send(IpmiCommandCoder<R> command)
    Sends any command of the protocol core in the session and returns its typed reply, for the commands the client does not wrap: bmc.send(new GetDeviceId()).
    Reads the sensors of the BMC: sensors().execute() for all of them, with types() and names() to select some before their readings are requested, and sensors().stream() to get each sensor as soon as it is read.
    sol()
    Opens a Serial over LAN console in the session: sol().open().

    Methods inherited from class java.lang.Object

    equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • DEFAULT_TIMEOUT

      public static final Duration DEFAULT_TIMEOUT
      Deadline of each operation when the builder sets none: 2 minutes.
    • DEFAULT_MESSAGE_TIMEOUT

      public static final Duration DEFAULT_MESSAGE_TIMEOUT
      Timeout of each message when the builder sets none: 5 seconds.
    • DEFAULT_RETRIES

      public static final int DEFAULT_RETRIES
      Resends of a message (IpmiClient.Builder.retries(int)) when the builder sets none: 3.
      See Also:
    • DEFAULT_KEEP_ALIVE

      public static final Duration DEFAULT_KEEP_ALIVE
      Period of the keep-alive messages when the builder sets none: 30 seconds.
  • Method Details

    • builder

      public static IpmiClient.Builder builder(String host)
      Starts building a client of the BMC at the given host.
      Parameters:
      host - the host name or IP address of the BMC
      Returns:
      the builder
      Throws:
      IllegalArgumentException - when the host is null or blank
    • host

      public String host()
      Returns the host name or IP address of the BMC.
      Returns:
      the host
    • capabilities

      public BmcCapabilities capabilities()
      Reads what the BMC supports before any login: its authentication options and the cipher suites it offers (Get Channel Authentication Capabilities and Get Channel Cipher Suites). Needs no credentials and opens no session.
      Returns:
      the capabilities
      Throws:
      IpmiConnectionException - when the BMC does not answer
      IpmiClientException - when the BMC does not support IPMI 2.0 (RMCP+), or the replies cannot be decoded
    • chassisStatus

      public ChassisStatus chassisStatus()
      Reads the state of the chassis: power, faults, intrusion, identify LED (Get Chassis Status).
      Returns:
      the chassis status
      Throws:
      IpmiClientException - when the session cannot be opened or the BMC does not answer
    • deviceId

      public DeviceId deviceId()
      Reads the identity of the BMC: manufacturer and product IDs, firmware revision, IPMI version, functions (Get Device ID). The first thing to read to tell the platform apart, before choosing the OEM decodings it needs.
      Returns:
      the device ID
      Throws:
      IpmiClientException - when the session cannot be opened or the BMC does not answer
    • chassisControl

      public void chassisControl(PowerCommand command)
      Controls the power of the chassis (Chassis Control, IPMI 2.0 section 28.3): power up, power down, power cycle, hard reset, soft shutdown or diagnostic interrupt. The BMC answers once it accepts the command and may carry it out afterwards: chassisStatus() tells when the power state changed. Needs the Operator privilege (IpmiClient.Builder.privilege(PrivilegeLevel)).

      The command is sent once: the BMC may have carried it out even when its reply is lost, and a reset sent twice resets the system twice.

      • A lost reply fails the call with IpmiTimeoutException, without a resend.
      • A C3h reply (timeout on the BMC side, response unavailable) fails the call with IpmiCompletionCodeException, without a resend.
      • The command is never replayed on a new session.
      • After a lost reply, the next operation first checks the session with a Get Device ID, and opens a new one when the BMC does not answer it (it rebooted or expired the session).

      After such a failure, read the power state with chassisStatus(). A busy reply (C0h or D2h) says that the BMC did not carry the command out: the command is sent again after a pause, like any other. A PowerCommand.PowerCycle of a system that is off is refused, as the specification recommends: some BMCs would power the system up instead of doing nothing.

      Parameters:
      command - the power command
      Throws:
      IllegalStateException - for a power cycle of a system that is off
      IpmiCompletionCodeException - when the BMC refuses the command: D4h at a session below Operator, D5h for a command it cannot carry out in the present state (a reset of a system that is off), CCh for an optional command it does not implement
      IpmiTimeoutException - when the BMC does not answer: whether it carried the command out is unknown
      IpmiClientException - when the session cannot be opened
    • chassisIdentify

      public void chassisIdentify(int seconds)
      Makes the chassis identify itself (Chassis Identify, IPMI 2.0 section 28.5), typically with a blinking LED, for the given number of seconds, or turns the identify off. Needs the Operator privilege. Sent once, never again when its reply is lost nor on a new session: a lost reply fails with IpmiTimeoutException, and ChassisStatus.identifyState() tells what the BMC did. Like after chassisControl(PowerCommand), the next operation first checks the session.
      Parameters:
      seconds - how long the identify stays on, 1 to 255 (the BMC may stretch it by 20%); 0 turns it off
      Throws:
      IllegalArgumentException - when seconds is not between 0 and 255
      IpmiCompletionCodeException - when the BMC refuses the command: D4h at a session below Operator, C1h when it does not implement it
      IpmiTimeoutException - when the BMC does not answer
      IpmiClientException - when the session cannot be opened
    • chassisIdentifyForever

      public void chassisIdentifyForever()
      Makes the chassis identify itself until chassisIdentify(0) turns it off: the optional "force identify on" of Chassis Identify, which not every BMC implements. Needs the Operator privilege. Sent once, like chassisIdentify(int).
      Throws:
      IpmiCompletionCodeException - when the BMC refuses the command: D4h at a session below Operator, C1h when it does not implement Chassis Identify, CCh when it does not implement the force byte
      IpmiTimeoutException - when the BMC does not answer
      IpmiClientException - when the session cannot be opened
    • sensors

      public SensorsRequest sensors()
      Reads the sensors of the BMC: sensors().execute() for all of them, with types() and names() to select some before their readings are requested, and sensors().stream() to get each sensor as soon as it is read.
      Returns:
      the request to complete
    • frus

      public FrusRequest frus()
      Reads the FRU inventories of the system: frus().execute() for all of them, with ids() to select some, and frus().stream() to get each FRU as soon as it is read. With the SDR cache (IpmiClient.Builder.sdrCache(boolean), enabled by default), sensors() and frus() share one walk of the SDR repository until Get SDR Repository Info reports a change; the repository of a BMC that refuses Get SDR Repository Info is walked again by every call.
      Returns:
      the request to complete
    • sel

      public SelRequest sel()
      Reads the System Event Log (SEL): sel().execute() for every entry, with SelRequest.since(SelEntry) for the entries added after one already read.
      Returns:
      the request to complete
    • send

      public <R extends ResponseData> R send(IpmiCommandCoder<R> command)
      Sends any command of the protocol core in the session and returns its typed reply, for the commands the client does not wrap: bmc.send(new GetDeviceId()). A command is never replayed on a new session.
      Type Parameters:
      R - the type of the reply
      Parameters:
      command - the command
      Returns:
      the reply
      Throws:
      IpmiCompletionCodeException - when the BMC answers with an error completion code
      IpmiClientException - when the session cannot be opened or the BMC does not answer
    • raw

      public RawRequest raw(int networkFunction, int command)
      Sends any request in the session, like ipmitool raw, and returns its reply whatever its completion code: bmc.raw(0x2C, 0x01).data(0xDC, 0x01).execute() is Get DCMI Capabilities Info.

      Every request network function is accepted, the extension and OEM ones included:

      • Group Extension (2Ch): the first data byte is the defining body, DCh for DCMI;
      • OEM/Group (2Eh): the first three data bytes are an IANA enterprise number;
      • controller-specific OEM (30h to 3Eh).

      An error completion code is returned in the reply, not thrown, and the request is not sent again for it, even for a busy BMC (C0h) or a C3h. The exception is a D4h on a client built with PrivilegeLevel.MaximumAvailable (IpmiClient.Builder.privilege(PrivilegeLevel)): the session is raised, to Operator then Administrator, and the request sent again. The D4h is returned once the session cannot go higher (Administrator, or the ceiling the BMC set), and a raise that fails for another reason (a busy BMC) throws IpmiCompletionCodeException.

      Like send(IpmiCommandCoder), a request whose reply is lost is sent again (the retries of the builder), but never replayed on a new session. A control request sent raw has none of the safeguards of chassisControl(PowerCommand).

      Parameters:
      networkFunction - the network function of the request: an even number from 00h to 3Eh (the odd ones are those of the responses, IPMI 2.0 section 5.1)
      command - the command code, 00h to FFh
      Returns:
      the request to complete
      Throws:
      IllegalArgumentException - when the network function or the command is out of range
    • sol

      public SolRequest sol()
      Opens a Serial over LAN console in the session: sol().open().
      Returns:
      the request to complete
    • close

      public void close()
      Closes the session (Close Session, sent once and waited for at most the message timeout plus one second), releases the UDP port and the threads. Closing a closed client does nothing, and a BMC that does not answer the logout does not fail the caller.

      Close the SOL consoles first. A console still open ends with the client: its reads return -1, no Deactivate Payload is sent for it, and the session of a console that the BMC serves on another UDP port is left for the BMC to expire.

      Specified by:
      close in interface AutoCloseable