Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions pyipmi/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,12 @@ def __init__(self, msg=None):

def __str__(self):
return "{}".format(self.msg)


class AuthenticationError(Exception):
"""Authentication error."""
def __init__(self, msg=None):
self.msg = msg

def __str__(self):
return "{}".format(self.msg)
23 changes: 19 additions & 4 deletions pyipmi/interfaces/ipmitool.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
from array import array

from ..session import Session
from ..errors import IpmiTimeoutError, IpmiConnectionError, IpmiLongPasswordError
from ..errors import (
IpmiTimeoutError,
IpmiConnectionError,
IpmiLongPasswordError,
AuthenticationError,
)
from ..logger import log
from ..msgs import encode_message, decode_message, create_message
from ..msgs.constants import CC_OK
Expand Down Expand Up @@ -64,6 +69,8 @@ def __init__(self, interface_type='lan', cipher=None):
r".*Could not open device.*")
self.re_long_password = re.compile(
r".*password is longer than.*")
self.re_authentication_error = re.compile(
r".*RAKP [0-9]+ HMAC.*")
self._session = None

def open(self):
Expand All @@ -89,6 +96,7 @@ def rmcp_ping(self):
cmd += (' -I %s' % self._interface_type)
cmd += (' -H %s' % self._session.rmcp_host)
cmd += (' -p %s' % self._session.rmcp_port)
cmd += (' -v')
if self._session.auth_type == Session.AUTH_TYPE_NONE:
cmd += (' -A NONE')
elif self._session.auth_type == Session.AUTH_TYPE_PASSWORD:
Expand Down Expand Up @@ -142,13 +150,19 @@ def _parse_output(self, output):
if self.re_long_password.match(line):
raise IpmiLongPasswordError(line)

if self.re_authentication_error.match(line):
raise AuthenticationError('Authentication error')

hexstr += line.replace('\r', '').strip() + ' '

hexstr = hexstr.strip()
if len(hexstr):
rsp = array('B', [
int(value, 16) for value in hexstr.split(' ')
])
try:
rsp = array('B', [
int(value, 16) for value in hexstr.split(' ')
])
except ValueError:
pass

return cc, rsp

Expand Down Expand Up @@ -250,6 +264,7 @@ def _build_ipmitool_cmd(self, target, lun, netfn, raw_bytes):
cmd += (' -I %s' % self._interface_type)
cmd += (' -H %s' % self._session.rmcp_host)
cmd += (' -p %s' % self._session.rmcp_port)
cmd += (' -v')

cmd += self._build_ipmitool_priv_level(self._session.priv_level)

Expand Down
18 changes: 12 additions & 6 deletions tests/interfaces/test_ipmitool.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from pyipmi.errors import IpmiTimeoutError, IpmiConnectionError, IpmiLongPasswordError
from pyipmi.errors import IpmiTimeoutError, IpmiConnectionError, IpmiLongPasswordError, AuthenticationError
from pyipmi.interfaces import Ipmitool
from pyipmi import Session, Target
from pyipmi.utils import py3_array_tobytes
Expand Down Expand Up @@ -53,7 +53,7 @@ def test_rmcp_ping(self):

self._interface.rmcp_ping()
mock.assert_called_once_with('ipmitool -I lan -H 10.0.1.1 -p 623 '
'-U "admin" -P "secret" '
'-v -U "admin" -P "secret" '
'session info all')

def test_send_and_receive_raw_valid(self):
Expand All @@ -65,7 +65,7 @@ def test_send_and_receive_raw_valid(self):
self._interface.send_and_receive_raw(target, 0, 0x6, b'\x01')

mock.assert_called_once_with('ipmitool -I lan -H 10.0.1.1 -p 623 '
'-L ADMINISTRATOR -U "admin" -P "secret" '
'-v -L ADMINISTRATOR -U "admin" -P "secret" '
'-t 0x20 -l 0 raw 0x06 0x01 2>&1')

def test_send_and_receive_raw_lanplus(self):
Expand All @@ -80,7 +80,7 @@ def test_send_and_receive_raw_lanplus(self):
interface.send_and_receive_raw(target, 0, 0x6, b'\x01')

mock.assert_called_once_with('ipmitool -I lanplus -H 10.0.1.1 -p 623 '
'-L ADMINISTRATOR -U "admin" -P "secret" '
'-v -L ADMINISTRATOR -U "admin" -P "secret" '
'-t 0x20 -l 0 raw 0x06 0x01 2>&1')

def test_send_and_receive_raw_cipher(self):
Expand All @@ -95,7 +95,7 @@ def test_send_and_receive_raw_cipher(self):
interface.send_and_receive_raw(target, 0, 0x6, b'\x01')

mock.assert_called_once_with('ipmitool -I lan -H 10.0.1.1 -p 623 '
'-L ADMINISTRATOR -C 7 '
'-v -L ADMINISTRATOR -C 7 '
'-U "admin" -P "secret" '
'-t 0x20 -l 0 raw 0x06 0x01 2>&1')

Expand All @@ -110,7 +110,7 @@ def test_send_and_receive_raw_no_auth(self):
self._interface.send_and_receive_raw(target, 0, 0x6, b'\x01')

mock.assert_called_once_with('ipmitool -I lan -H 10.0.1.1 -p 623 '
'-L ADMINISTRATOR -P "" '
'-v -L ADMINISTRATOR -P "" '
'-t 0x20 -l 0 raw 0x06 0x01 2>&1')

def test_send_and_receive_raw_return_value(self):
Expand Down Expand Up @@ -236,3 +236,9 @@ def test_parse_long_password_error(self):
with pytest.raises(IpmiLongPasswordError):
cc, rsp = self._interface._parse_output(test_str)
assert rsp is None

def test_parse_output_authentication_error(self):
test_str = b'Loading ...\nUsing ...\n> RAKP 2 HMAC is invalid\nError:'
with pytest.raises(AuthenticationError):
cc, rsp = self._interface._parse_output(test_str)
assert rsp is None
Loading