From 9653e789cc7e3c646c7fd6903179ec6b40f13f3d Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Tue, 10 Dec 2024 13:34:00 +0100 Subject: [PATCH 01/14] codespell: fix typo warnings Signed-off-by: Heiko Thiery --- docs/source/bmcWatchdog_cmd.rst | 2 +- docs/source/ipmDevGlobal_cmd.rst | 2 +- docs/source/ipmiMsgSupport_cmd.rst | 8 ++++---- docs/source/quick_start.rst | 6 +++--- pyipmi/bmc.py | 2 +- pyipmi/errors.py | 2 +- pyipmi/fields.py | 2 +- pyipmi/helper.py | 2 +- pyipmi/hpm.py | 2 +- pyipmi/interfaces/ipmb.py | 4 ++-- pyipmi/interfaces/rmcp.py | 2 +- pyipmi/ipmitool.py | 2 +- pyipmi/msgs/message.py | 4 ++-- 13 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/source/bmcWatchdog_cmd.rst b/docs/source/bmcWatchdog_cmd.rst index 461c7397..f20f450a 100644 --- a/docs/source/bmcWatchdog_cmd.rst +++ b/docs/source/bmcWatchdog_cmd.rst @@ -49,7 +49,7 @@ For example: ipmi.set_watchdog_timer(watchdog_timer) -where the ``watchdog_timer`` has the attributes shown bellow for the next command. +where the ``watchdog_timer`` has the attributes shown below for the next command. Get Watchdog Timer Command ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/ipmDevGlobal_cmd.rst b/docs/source/ipmDevGlobal_cmd.rst index 8817fba7..32c0aa6d 100644 --- a/docs/source/ipmDevGlobal_cmd.rst +++ b/docs/source/ipmDevGlobal_cmd.rst @@ -102,7 +102,7 @@ For example: Cold Reset Command ~~~~~~~~~~~~~~~~~~ -This command directs the **Target** to perform a 'Cold Reset' of itself. The device reinitalizes its event, communcation, and sensor funtioncs. Self Test, if implemented, will be also run. +This command directs the **Target** to perform a 'Cold Reset' of itself. The device reinitalizes its event, communication, and sensor funtioncs. Self Test, if implemented, will be also run. +------------------------------+ | **cold_reset()** | diff --git a/docs/source/ipmiMsgSupport_cmd.rst b/docs/source/ipmiMsgSupport_cmd.rst index 188d595e..e6d86825 100644 --- a/docs/source/ipmiMsgSupport_cmd.rst +++ b/docs/source/ipmiMsgSupport_cmd.rst @@ -84,13 +84,13 @@ This is not equivalent with a single IPMI command, but represents a high level A | **establish()** | +------------------------------+ -creates and activates a session of the ``ipmi.session`` instance with the given authentication and privilige level. Multiple IPMI commands are used to establish the session. The following steps are done during the session establishment for an RMCP interface: +creates and activates a session of the ``ipmi.session`` instance with the given authentication and privilege level. Multiple IPMI commands are used to establish the session. The following steps are done during the session establishment for an RMCP interface: - ping the **Target** IP address - issue a **"Get Channel Authentication Capabilities"** command - issue a **"Get Session Challenge"** command - issue an **"Activate Session"** command - - issue a **"Set Session Privilege Level"** command (privilige is set always to ADMINISTRATOR level) + - issue a **"Set Session Privilege Level"** command (privilege is set always to ADMINISTRATOR level) If ``keep_alive_interval`` argument for the interface instantiation was set to a nonzero value then the channel is kept alive by regularly sending the **"Get Device ID"** IPMI command. @@ -109,7 +109,7 @@ This command is used to retrieve capability information about a particular chann | **get_channel_authentication_capabilities(channel, priv_lvl)** | +-----------------------------------------------------------------+ -You should pass the channel number to ``channel``, and the requested maximum privilige level to ``priv_lvl``. +You should pass the channel number to ``channel``, and the requested maximum privilege level to ``priv_lvl``. Example: @@ -121,7 +121,7 @@ Example: Master Write-Read Command ~~~~~~~~~~~~~~~~~~~~~~~~~ -This command can be used for low level |I2C|/SMBus write, read, or write-read accesses to the IPMB or private busses behind a management controller. The command can also be used for providing low-level access to devices that provide an SMBus slave interface. +This command can be used for low level |I2C|/SMBus write, read, or write-read accesses to the IPMB or private buses behind a management controller. The command can also be used for providing low-level access to devices that provide an SMBus slave interface. +---------------------------------------------------------------------------+ | **i2c_write_read(bus_type, bus_id, channel, address, count, data=None)** | diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index 800605da..dac7000f 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -23,7 +23,7 @@ Before establishing the session the interface type shall be defined. There are 4 * **'aardvark'** - :abbr:`IPMB (Intelligent Platform Management Bus)` interface (using the `Total Phase`_ Aardvark) * **'mock'** - This interface uses the ipmitool raw command to "emulate" an :abbr:`RMCP (Remote Management Control Protocol)` session. It uses the session information to assemble the correct ipmitool parameters. Therefore, a session must be established before any request can be sent. -Then you create an instance of the ``pyipmi.Ipmi`` object using the ``interface`` instance just created, and set also the required parameteres of the interface type. You should also set the :abbr:`IPMI (Intelligent Platform Management Interface)` **Target**, otherwise different runtime errors shall be expected later on when invoking methods of this library. Finally, you can try to establish a session. If there is a connection problem (no response), then you get the following error during session establishment: +Then you create an instance of the ``pyipmi.Ipmi`` object using the ``interface`` instance just created, and set also the required parameters of the interface type. You should also set the :abbr:`IPMI (Intelligent Platform Management Interface)` **Target**, otherwise different runtime errors shall be expected later on when invoking methods of this library. Finally, you can try to establish a session. If there is a connection problem (no response), then you get the following error during session establishment: .. error:: @@ -261,7 +261,7 @@ ipmitool command: IPMB with Aardvark ****************** -For :abbr:`IPMB (Intelligent Platform Management Bus)` interface with Aardvark tool you should use the followig code: +For :abbr:`IPMB (Intelligent Platform Management Bus)` interface with Aardvark tool you should use the following code: .. code:: python @@ -345,7 +345,7 @@ in which case debug, info and warning messages are all recorded in the **'ipmi_d .. note:: - It is assumed in all code examples that the instantiation of the ``pyipmi.Ipmi`` object is called **ipmi**, thus **ipmi** will preceed all the methods and attributes of the ``pyipmi.Ipmi`` object. + It is assumed in all code examples that the instantiation of the ``pyipmi.Ipmi`` object is called **ipmi**, thus **ipmi** will proceed all the methods and attributes of the ``pyipmi.Ipmi`` object. .. _Total Phase: http://www.totalphase.com .. _ipmitool: http://sourceforge.net/projects/ipmitool/ diff --git a/pyipmi/bmc.py b/pyipmi/bmc.py index f9619556..b5a05412 100644 --- a/pyipmi/bmc.py +++ b/pyipmi/bmc.py @@ -89,7 +89,7 @@ class Watchdog(State): TIMEOUT_ACTION_POWER_CYCLE = 3 __properties__ = [ - # (propery, description) + # (property, description) ('timer_use', ''), ('dont_stop', ''), ('is_running', ''), diff --git a/pyipmi/errors.py b/pyipmi/errors.py index 23b349d9..828a17d0 100644 --- a/pyipmi/errors.py +++ b/pyipmi/errors.py @@ -69,7 +69,7 @@ class DescriptionError(Exception): class RetryError(Exception): - """Maxium number of retries exceeded.""" + """Maximum number of retries exceeded.""" pass diff --git a/pyipmi/fields.py b/pyipmi/fields.py index 8de650ff..ec7380ff 100644 --- a/pyipmi/fields.py +++ b/pyipmi/fields.py @@ -64,7 +64,7 @@ def _unpack6bitascii(data): class TypeLengthString(object): """ - This is the TYPE/LENGTH BYTE FORMAT field represenation according the + This is the TYPE/LENGTH BYTE FORMAT field representation according the Platform Management FRU Information Storage Definition v1.0. In addition the difference to the 'FRU Information Storage Definition' to diff --git a/pyipmi/helper.py b/pyipmi/helper.py index 0b634ccb..83bc7873 100644 --- a/pyipmi/helper.py +++ b/pyipmi/helper.py @@ -85,7 +85,7 @@ def get_sdr_data_helper(reserve_fn, get_fn, record_id, reservation_id=None): (next_id, data) = get_fn(reservation_id, record_id, offset, length) except CompletionCodeError as e: if e.cc == constants.CC_CANT_RET_NUM_REQ_BYTES: - # reduce max lenght + # reduce max length max_req_len -= 4 if max_req_len <= 0: retry = 0 diff --git a/pyipmi/hpm.py b/pyipmi/hpm.py index a642ecc6..aa026a39 100644 --- a/pyipmi/hpm.py +++ b/pyipmi/hpm.py @@ -314,7 +314,7 @@ def preparation_stage(self, image): # tbd check version #################################################### - # compare current revision with upgrade image earlist comp rev + # compare current revision with upgrade image earliest comp rev targetCap = self.get_target_upgrade_capabilities() # tbd check version diff --git a/pyipmi/interfaces/ipmb.py b/pyipmi/interfaces/ipmb.py index 911aaced..f2541603 100644 --- a/pyipmi/interfaces/ipmb.py +++ b/pyipmi/interfaces/ipmb.py @@ -149,7 +149,7 @@ def encode_ipmb_msg(header, data): def encode_send_message(payload, rq_sa, rs_sa, channel, seq, tracking=1): - """Encode a send message command and embedd the message to be send. + """Encode a send message command and embed the message to be send. payload: the message to be send as bytestring rq_sa: the requester source address @@ -178,7 +178,7 @@ def encode_send_message(payload, rq_sa, rs_sa, channel, seq, tracking=1): def encode_bridged_message(routing, header, payload, seq): - """Encode a (multi-)bridged command and embedd the message to be send. + """Encode a (multi-)bridged command and embed the message to be send. routing: payload: the message to be send as bytestring diff --git a/pyipmi/interfaces/rmcp.py b/pyipmi/interfaces/rmcp.py index a6e08ccb..b745f6d4 100644 --- a/pyipmi/interfaces/rmcp.py +++ b/pyipmi/interfaces/rmcp.py @@ -248,7 +248,7 @@ def _pack_sequence_number(self): return struct.unpack("I", seq))[0] def _padd_password(self): - """Padd the password. + """Pad the password. The password/key is 0 padded to 16-bytes for all specified authentication types. diff --git a/pyipmi/ipmitool.py b/pyipmi/ipmitool.py index 7f5fdb09..9d459695 100755 --- a/pyipmi/ipmitool.py +++ b/pyipmi/ipmitool.py @@ -474,7 +474,7 @@ def usage(toplevel=False): -I Set interface (available: rmcp, aardvark, ipmitool, ipmbdev) -H Set RMCP host -U Set RMCP user - -L Set RMCP priviledge level + -L Set RMCP privilege level -P Set RMCP password -o Set interface specific options (name=value, separated by commas, see below for available options). diff --git a/pyipmi/msgs/message.py b/pyipmi/msgs/message.py index 1aeb680b..0f3db356 100644 --- a/pyipmi/msgs/message.py +++ b/pyipmi/msgs/message.py @@ -54,7 +54,7 @@ def _length(self, obj): def encode(self, obj, data): a = getattr(obj, self.name) if len(a) != self._length(obj): - raise EncodingError('Array must be exaclty %d bytes long ' + raise EncodingError('Array must be exactly %d bytes long ' '(but is %d long)' % (self._length(obj), len(a))) for i in range(self._length(obj)): @@ -320,7 +320,7 @@ def __init__(self, *args, **kwargs): buf -- option message buffer to decode - Optional keyword arguments corresponts to members to set (matching + Optional keyword arguments corresponds to members to set (matching fields in self.__fields__, or 'data'). """ # create message fields From 21529aeb20f83ee807724617ad30b8c6a89d8657 Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Mon, 16 Dec 2024 13:29:57 +0100 Subject: [PATCH 02/14] interfaces: add common open() and close() methods This empty methods now are called from Ipmi class. From Ipmi() class also the establish and close Session() methods are called. Signed-off-by: Heiko Thiery --- pyipmi/__init__.py | 8 ++++++++ pyipmi/interfaces/aardvark.py | 6 ++++++ pyipmi/interfaces/ipmbdev.py | 6 ++++++ pyipmi/interfaces/ipmitool.py | 6 ++++++ pyipmi/interfaces/mock.py | 6 ++++++ pyipmi/interfaces/rmcp.py | 6 ++++++ 6 files changed, 38 insertions(+) diff --git a/pyipmi/__init__.py b/pyipmi/__init__.py index dd89402a..a511463c 100644 --- a/pyipmi/__init__.py +++ b/pyipmi/__init__.py @@ -172,6 +172,14 @@ def __init__(self): for base in Ipmi.__bases__: base.__init__(self) + def open(self): + self.interface.open() + self.session.establish() + + def close(self): + self.session.close() + self.interface.close() + def is_ipmc_accessible(self): return self.interface.is_ipmc_accessible(self.target) diff --git a/pyipmi/interfaces/aardvark.py b/pyipmi/interfaces/aardvark.py index e104a56f..04688500 100644 --- a/pyipmi/interfaces/aardvark.py +++ b/pyipmi/interfaces/aardvark.py @@ -61,6 +61,12 @@ def __init__(self, slave_address=0x20, port=0, serial_number=None, else: self.enable_fastmode(False) + def open(self): + pass + + def close(self): + pass + def enable_pullups(self, enabled): self._dev.i2c_pullups = enabled diff --git a/pyipmi/interfaces/ipmbdev.py b/pyipmi/interfaces/ipmbdev.py index 38532a89..a2e48354 100644 --- a/pyipmi/interfaces/ipmbdev.py +++ b/pyipmi/interfaces/ipmbdev.py @@ -23,6 +23,12 @@ def __init__(self, slave_address=0x20, port='/dev/ipmb-0'): self._dev = os.open(port, os.O_RDWR) + def open(self): + pass + + def close(self): + pass + def establish_session(self, session): # just remember session parameters here self._session = session diff --git a/pyipmi/interfaces/ipmitool.py b/pyipmi/interfaces/ipmitool.py index b1268b4b..fcb8b22a 100644 --- a/pyipmi/interfaces/ipmitool.py +++ b/pyipmi/interfaces/ipmitool.py @@ -65,6 +65,12 @@ def __init__(self, interface_type='lan', cipher=None): self._session = None + def open(self): + pass + + def close(self): + pass + def establish_session(self, session): # just remember session parameters here self._session = session diff --git a/pyipmi/interfaces/mock.py b/pyipmi/interfaces/mock.py index 1eb1a38b..841628bd 100644 --- a/pyipmi/interfaces/mock.py +++ b/pyipmi/interfaces/mock.py @@ -6,6 +6,12 @@ class Mock(object): def __init__(self): pass + def open(self): + pass + + def close(self): + pass + def establish_session(self, session): pass diff --git a/pyipmi/interfaces/rmcp.py b/pyipmi/interfaces/rmcp.py index b745f6d4..f156e491 100644 --- a/pyipmi/interfaces/rmcp.py +++ b/pyipmi/interfaces/rmcp.py @@ -408,6 +408,12 @@ def __init__(self, slave_address=0x81, host_target_address=0x20, self.ignore_sdu_length = quirks_cfg.get('rmcp_ignore_sdu_length', False) self.ignore_rq_seq = quirks_cfg.get('rmcp_ignore_rq_seq', False) + def open(self): + pass + + def close(self): + pass + def _send_rmcp_msg(self, sdu, class_of_msg): rmcp = RmcpMsg(class_of_msg) pdu = rmcp.pack(sdu, self.seq_number) From a66c069ca0d89f9f649f0e731e147f00bf634b2d Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Mon, 16 Dec 2024 14:34:16 +0100 Subject: [PATCH 03/14] ipmi: refactor Ipmi() class Add new args for __init__ and adopt create_connection() accordingly Signed-off-by: Heiko Thiery --- pyipmi/__init__.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pyipmi/__init__.py b/pyipmi/__init__.py index a511463c..ba91fd54 100644 --- a/pyipmi/__init__.py +++ b/pyipmi/__init__.py @@ -48,10 +48,7 @@ def create_connection(interface): session = Session() session.interface = interface - ipmi = Ipmi() - ipmi.interface = interface - ipmi.session = session - ipmi.requester = NullRequester() + ipmi = Ipmi(interface=interface, session=session) return ipmi @@ -164,10 +161,12 @@ class Ipmi(bmc.Bmc, chassis.Chassis, dcmi.Dcmi, fru.Fru, picmg.Picmg, hpm.Hpm, sdr.Sdr, sensor.Sensor, event.Event, sel.Sel, lan.Lan, messaging.Messaging): - def __init__(self): - self._interface = None - self._session = None - self._target = None + def __init__(self, interface=None, session=None, target=None, + requester=NullRequester()): + self._interface = interface + self._session = session + self._target = target + self.requester = requester for base in Ipmi.__bases__: base.__init__(self) From b920c9b0fa3304fa7887678f38fcda2cd37bcc48 Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Mon, 16 Dec 2024 14:35:29 +0100 Subject: [PATCH 04/14] ipmi: add support for context manager in Ipmi() Add __enter__() and __exit__() methods to support context manager. Signed-off-by: Heiko Thiery --- pyipmi/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyipmi/__init__.py b/pyipmi/__init__.py index ba91fd54..daf9f294 100644 --- a/pyipmi/__init__.py +++ b/pyipmi/__init__.py @@ -171,6 +171,12 @@ def __init__(self, interface=None, session=None, target=None, for base in Ipmi.__bases__: base.__init__(self) + def __enter__(self): + return self + + def __exit__(self, exception_type, exception_value, traceback): + return False + def open(self): self.interface.open() self.session.establish() From 087cf9d84481568b6a782404911aeadd2643bd6a Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Mon, 16 Dec 2024 14:46:03 +0100 Subject: [PATCH 05/14] interface/aardvark: use open() and close() Move device specific stuff to open() and close() methods. Signed-off-by: Heiko Thiery --- pyipmi/interfaces/aardvark.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/pyipmi/interfaces/aardvark.py b/pyipmi/interfaces/aardvark.py index 04688500..f99b5af3 100644 --- a/pyipmi/interfaces/aardvark.py +++ b/pyipmi/interfaces/aardvark.py @@ -44,28 +44,31 @@ def __init__(self, slave_address=0x20, port=0, serial_number=None, 'use this interface.') self.slave_address = slave_address + self.port = port + self.serial_number = serial_number + self.i2c_pullups = enable_i2c_pullups + self.target_power = enable_target_power + self.fastmode = enable_fastmode self.timeout = 0.25 self.max_retries = 3 self.next_sequence_number = 0 - self._dev = pyaardvark.open(port, serial_number) + def open(self): + self._dev = pyaardvark.open(self.port, self.serial_number) self._dev.enable_i2c_slave(self.slave_address >> 1) - if enable_i2c_pullups: - self.enable_pullups(enable_i2c_pullups) - if enable_target_power: - self.enable_target_power(enable_target_power) + if self.i2c_pullups: + self.enable_pullups(self.i2c_pullups) + if self.target_power: + self.enable_target_power(self.target_power) - if enable_fastmode is not None: - self.enable_fastmode(enable_fastmode) + if self.fastmode is not None: + self.enable_fastmode(self.fastmode) else: self.enable_fastmode(False) - def open(self): - pass - def close(self): - pass + self._dev.close() def enable_pullups(self, enabled): self._dev.i2c_pullups = enabled @@ -83,11 +86,10 @@ def raw_write(self, address, data): self._dev.i2c_master_write(address, data) def establish_session(self, session): - # just remember session parameters here - self._session = session + pass def close_session(self): - self._dev.close() + pass def is_ipmc_accessible(self, target): header = IpmbHeaderReq() From 6feb4f1d7f6cd5ea2c1ba2ba603110652ee4bef4 Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Tue, 17 Dec 2024 10:40:43 +0100 Subject: [PATCH 06/14] interface/ipmbdev: change open()/close() Signed-off-by: Heiko Thiery --- pyipmi/interfaces/ipmbdev.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pyipmi/interfaces/ipmbdev.py b/pyipmi/interfaces/ipmbdev.py index a2e48354..3ba57ea1 100644 --- a/pyipmi/interfaces/ipmbdev.py +++ b/pyipmi/interfaces/ipmbdev.py @@ -17,24 +17,22 @@ class IpmbDev(object): def __init__(self, slave_address=0x20, port='/dev/ipmb-0'): # TODO: slave address is currently not defined here self.slave_address = slave_address + self.port = port self.timeout = 0.25 self.max_retries = 3 self.next_sequence_number = 0 - self._dev = os.open(port, os.O_RDWR) - def open(self): - pass + self._dev = os.open(self.port, os.O_RDWR) def close(self): - pass + os.close(self._dev) def establish_session(self, session): - # just remember session parameters here - self._session = session + pass def close_session(self): - os.close(self._dev) + pass def is_ipmc_accessible(self, target): header = IpmbHeaderReq() From 88b609d3f4d98584021020549d28ea0bd9d061ae Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Tue, 17 Dec 2024 10:41:18 +0100 Subject: [PATCH 07/14] interface/ipmitool: change open()/close() Signed-off-by: Heiko Thiery --- pyipmi/interfaces/ipmitool.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyipmi/interfaces/ipmitool.py b/pyipmi/interfaces/ipmitool.py index fcb8b22a..f2c1b548 100644 --- a/pyipmi/interfaces/ipmitool.py +++ b/pyipmi/interfaces/ipmitool.py @@ -72,9 +72,11 @@ def close(self): pass def establish_session(self, session): - # just remember session parameters here self._session = session + def close_session(self): + pass + def rmcp_ping(self): if self._interface_type == 'serial-terminal': From e82047e8126b143f380f50ea937ec9b766257667 Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Tue, 17 Dec 2024 10:41:34 +0100 Subject: [PATCH 08/14] interface/rmcp: change open()/close() Signed-off-by: Heiko Thiery --- pyipmi/interfaces/rmcp.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyipmi/interfaces/rmcp.py b/pyipmi/interfaces/rmcp.py index f156e491..312f6b0d 100644 --- a/pyipmi/interfaces/rmcp.py +++ b/pyipmi/interfaces/rmcp.py @@ -393,12 +393,10 @@ def __init__(self, slave_address=0x81, host_target_address=0x20, """ self.host = None self.port = None - self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.seq_number = 0xff self.slave_address = slave_address self.host_target = Target(host_target_address) self.max_retries = max_retries - self.set_timeout(2.0) self.next_sequence_number = 0 self.keep_alive_interval = keep_alive_interval self._stop_keep_alive = None @@ -409,7 +407,8 @@ def __init__(self, slave_address=0x81, host_target_address=0x20, self.ignore_rq_seq = quirks_cfg.get('rmcp_ignore_rq_seq', False) def open(self): - pass + self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.set_timeout(2.0) def close(self): pass From cd2aee9a6d612142ef6cfd5242121d3c461f0b14 Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Tue, 17 Dec 2024 07:40:47 +0100 Subject: [PATCH 09/14] ipmitool: use open() and close() Use the open() and close() methods instead of session establish() and close(). Signed-off-by: Heiko Thiery --- pyipmi/ipmitool.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pyipmi/ipmitool.py b/pyipmi/ipmitool.py index 9d459695..62470c22 100755 --- a/pyipmi/ipmitool.py +++ b/pyipmi/ipmitool.py @@ -644,9 +644,8 @@ def main(): if rmcp_priv_level is not None: ipmi.session.set_priv_level(rmcp_priv_level) - ipmi.session.establish() - try: + ipmi.open() # this will open interface and session cmd(ipmi, args) except pyipmi.errors.CompletionCodeError as e: print('Command returned with completion code 0x%02x' % e.cc) @@ -664,8 +663,7 @@ def main(): sys.exit(1) finally: - if rmcp_host is not None: - ipmi.session.close() + ipmi.close() # this will close interface and session COMMANDS = ( From ed0e0d7ee51470fbdf62b9de248c409d37c255bf Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Tue, 17 Dec 2024 07:39:58 +0100 Subject: [PATCH 10/14] __init__: some cleanups Signed-off-by: Heiko Thiery --- pyipmi/__init__.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pyipmi/__init__.py b/pyipmi/__init__.py index daf9f294..c29ef1cb 100644 --- a/pyipmi/__init__.py +++ b/pyipmi/__init__.py @@ -48,8 +48,7 @@ def create_connection(interface): session = Session() session.interface = interface - ipmi = Ipmi(interface=interface, session=session) - return ipmi + return Ipmi(interface=interface, session=session) class Requester(object): @@ -161,7 +160,7 @@ class Ipmi(bmc.Bmc, chassis.Chassis, dcmi.Dcmi, fru.Fru, picmg.Picmg, hpm.Hpm, sdr.Sdr, sensor.Sensor, event.Event, sel.Sel, lan.Lan, messaging.Messaging): - def __init__(self, interface=None, session=None, target=None, + def __init__(self, interface=None, target=None, session=Session(), requester=NullRequester()): self._interface = interface self._session = session @@ -172,17 +171,21 @@ def __init__(self, interface=None, session=None, target=None, base.__init__(self) def __enter__(self): + self.open() return self def __exit__(self, exception_type, exception_value, traceback): + self.close() return False def open(self): self.interface.open() - self.session.establish() + if self.session is not None: + self.session.establish() def close(self): - self.session.close() + if self.session is not None: + self.session.close() self.interface.close() def is_ipmc_accessible(self): From 7f1edda1c384da956491fa2bdc80d3a1f0776911 Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Tue, 17 Dec 2024 08:34:54 +0100 Subject: [PATCH 11/14] __init__: Ipmi() create session and assign interface We need always a session. So we create if it is not passed on __init__. Also a session needs an interface, set it! Signed-off-by: Heiko Thiery --- pyipmi/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyipmi/__init__.py b/pyipmi/__init__.py index c29ef1cb..d47d6677 100644 --- a/pyipmi/__init__.py +++ b/pyipmi/__init__.py @@ -163,7 +163,14 @@ class Ipmi(bmc.Bmc, chassis.Chassis, dcmi.Dcmi, fru.Fru, picmg.Picmg, hpm.Hpm, def __init__(self, interface=None, target=None, session=Session(), requester=NullRequester()): self._interface = interface + + # we need a session, set if not passed + if session is None: + session = Session() self._session = session + # session needs an interface + self._session.interface = interface + self._target = target self.requester = requester From b4b4c02efc540a26cc269369a998c29d7dafcf55 Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Tue, 17 Dec 2024 07:42:44 +0100 Subject: [PATCH 12/14] examples: use with statement Signed-off-by: Heiko Thiery --- examples/dcmi.py | 4 +++- examples/interface_aardvark.py | 11 ++++++++-- examples/interface_rmcp.py | 23 ++++++++++++--------- tests/test_ipmi.py | 37 +++++++++++++++++++++++++++++++++- 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/examples/dcmi.py b/examples/dcmi.py index 6cee0d21..a9f1d517 100644 --- a/examples/dcmi.py +++ b/examples/dcmi.py @@ -21,8 +21,8 @@ def main(): ipmi = pyipmi.create_connection(interface) ipmi.session.set_session_type_rmcp(host, 623) ipmi.session.set_auth_type_user(user, password) - ipmi.session.establish() ipmi.target = pyipmi.Target(ipmb_address=0x20) + ipmi.open() for selector in range(1, 6): caps = ipmi.get_dcmi_capabilities(selector) @@ -42,6 +42,8 @@ def main(): print(' period: {}'.format(rsp.period)) print(' state: {}'.format(rsp.reading_state)) + ipmi.close() + if __name__ == '__main__': main() diff --git a/examples/interface_aardvark.py b/examples/interface_aardvark.py index 60db6bb4..ad043987 100644 --- a/examples/interface_aardvark.py +++ b/examples/interface_aardvark.py @@ -7,10 +7,17 @@ interface = pyipmi.interfaces.create_interface('aardvark', slave_address=0x20, serial_number='2237-523145') -ipmi = pyipmi.create_connection(interface) -ipmi.target = pyipmi.Target(ipmb_address=0xb4) +target = pyipmi.Target(ipmb_address=0xb4) + +# (1) The device connection can either be opened and closed +ipmi = pyipmi.Ipmi(interface=interface, target=target) +ipmi.open() device_id = ipmi.get_device_id() +ipmi.close() +# (2) or the 'with' statement can be used +with pyipmi.Ipmi(interface=interface, target=target) as ipmi: + device_id = ipmi.get_device_id() print(''' Device ID: %(device_id)s diff --git a/examples/interface_rmcp.py b/examples/interface_rmcp.py index 82090e51..aa4954bb 100644 --- a/examples/interface_rmcp.py +++ b/examples/interface_rmcp.py @@ -4,20 +4,25 @@ import pyipmi.interfaces -interface = pyipmi.interfaces.create_interface('rmcp', +intf = pyipmi.interfaces.create_interface('rmcp', slave_address=0x81, host_target_address=0x20, keep_alive_interval=0) -ipmi = pyipmi.create_connection(interface) -ipmi.session.set_session_type_rmcp('10.0.114.199', 623) -ipmi.session.set_auth_type_user('admin', 'admin') -ipmi.session.set_priv_level("ADMINISTRATOR") -ipmi.session.establish() -ipmi.target = pyipmi.Target(ipmb_address=0x20) - +sess = pyipmi.Session() +sess.set_session_type_rmcp('10.0.114.116', 623) +sess.set_auth_type_user('admin', 'admin') +sess.set_priv_level("ADMINISTRATOR") +target = pyipmi.Target(ipmb_address=0x20) + +# (1) The device connection can either be opened and closed +ipmi = pyipmi.Ipmi(interface=intf, session=sess, target=target) +ipmi.open() device_id = ipmi.get_device_id() +ipmi.close() -ipmi.session.close() +# (2) or the 'with' statement can be used +with pyipmi.Ipmi(interface=intf, session=sess, target=target) as ipmi: + device_id = ipmi.get_device_id() print(''' Device ID: %(device_id)s diff --git a/tests/test_ipmi.py b/tests/test_ipmi.py index e0072d20..6caaad00 100644 --- a/tests/test_ipmi.py +++ b/tests/test_ipmi.py @@ -5,7 +5,8 @@ import pytest -from pyipmi import interfaces, create_connection, Target, Routing +from pyipmi import (Ipmi, interfaces, create_connection, NullRequester, Routing, + Session, Target) from pyipmi.errors import CompletionCodeError, RetryError from pyipmi.msgs.bmc import GetDeviceIdReq, GetDeviceIdRsp from pyipmi.msgs.sensor import GetSensorReadingReq, GetSensorReadingRsp @@ -88,6 +89,40 @@ def test_target_set_routing_from_string(): assert target.routing[1].channel == 0x23 +def test_create_connection(): + interface = interfaces.create_interface('mock') + + ipmi = create_connection(interface) + assert ipmi.interface is not None + assert isinstance(ipmi.interface, interfaces.mock.Mock) + assert isinstance(ipmi.session, Session) + assert isinstance(ipmi.session.interface, interfaces.mock.Mock) + assert isinstance(ipmi.requester, NullRequester) + + +def test_ipmi(): + ipmi = Ipmi() + assert ipmi.interface is None + assert isinstance(ipmi.session, Session) + assert isinstance(ipmi.requester, NullRequester) + + interface = interfaces.create_interface('mock') + ipmi = Ipmi(interface=interface) + assert isinstance(ipmi.interface, interfaces.mock.Mock) + assert isinstance(ipmi.session, Session) + assert isinstance(ipmi.session.interface, interfaces.mock.Mock) + assert isinstance(ipmi.requester, NullRequester) + + +def test_ipmi_with_statemetn(): + interface = interfaces.create_interface('mock') + + with Ipmi(interface=interface) as ipmi: + assert ipmi.interface is not None + assert isinstance(ipmi.session, Session) + assert isinstance(ipmi.requester, NullRequester) + + def test_ipmi_send_message_retry(): req = GetDeviceIdReq() rsp = GetDeviceIdRsp() From 8fc81602a5ce3e51ba6b8808a0dc26cd0bbfc14b Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Tue, 17 Dec 2024 07:39:13 +0100 Subject: [PATCH 13/14] docs: fix flake8 warnings Signed-off-by: Heiko Thiery --- bin/supported_cmds.py | 1 - docs/source/conf.py | 18 ++++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/bin/supported_cmds.py b/bin/supported_cmds.py index fe8820a4..806a7464 100644 --- a/bin/supported_cmds.py +++ b/bin/supported_cmds.py @@ -71,6 +71,5 @@ def main(): print(data) - if __name__ == '__main__': main() diff --git a/docs/source/conf.py b/docs/source/conf.py index 80eb693a..d910a8fe 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -32,14 +32,14 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.ifconfig', - 'sphinx.ext.viewcode', - 'sphinx.ext.githubpages', - 'sphinx.ext.graphviz'] + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.ifconfig', + 'sphinx.ext.viewcode', + 'sphinx.ext.githubpages', + 'sphinx.ext.graphviz'] # Add any paths that contain templates here, relative to this directory. templates_path = ['ytemplates'] @@ -162,7 +162,5 @@ ] - - # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'https://docs.python.org/': None} From cf7b27f6d21448614eb82d12a3609dbd24e7a6cf Mon Sep 17 00:00:00 2001 From: Heiko Thiery Date: Tue, 17 Dec 2024 09:16:42 +0100 Subject: [PATCH 14/14] tests: add event tests Signed-off-by: Heiko Thiery --- tests/test_event.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/test_event.py diff --git a/tests/test_event.py b/tests/test_event.py new file mode 100644 index 00000000..13272f80 --- /dev/null +++ b/tests/test_event.py @@ -0,0 +1,38 @@ +from unittest.mock import MagicMock + +from pyipmi import interfaces, create_connection +from pyipmi.msgs.event import (SetEventReceiverRsp, GetEventReceiverRsp) + + +class TestEvent(object): + + def setup_method(self): + self.mock_send_recv = MagicMock() + + interface = interfaces.create_interface('mock') + self.ipmi = create_connection(interface) + self.ipmi.send_message = self.mock_send_recv + + def test_set_event_receiver(self): + + rsp = SetEventReceiverRsp() + rsp.completion_code = 0 + self.mock_send_recv.return_value = rsp + + self.ipmi.set_event_receiver(ipmb_address=0xb0, lun=1) + args, _ = self.mock_send_recv.call_args + req = args[0] + assert req.event_receiver.ipmb_i2c_slave_address == 0xb0 + assert req.event_receiver.lun == 1 + + def test_get_event_receiver(self): + + rsp = GetEventReceiverRsp() + rsp.completion_code = 0 + rsp.event_receiver.ipmb_i2c_slave_address = 0xc0 + rsp.event_receiver.lun = 2 + self.mock_send_recv.return_value = rsp + + (addr, lun) = self.ipmi.get_event_receiver() + assert addr == 0xc0 + assert lun == 2