Skip to content

Commit

Permalink
Support specifying mac address without quotation mark
Browse files Browse the repository at this point in the history
- In yaml, all the string value consists of a series of one-digit or
two-digit numbers delimited by colons and all numbers but the first are
between 0 and 59, it would be interpreted as a sexagesimal number, and
would be converted automatically to the equivalent number of seconds.

- The committed patch will guarantee to remediate the yaml's peculiarity
and convert back into the mac address specified in the original yaml
file. And in case that user specifies arbitrary integer(e.g. `mac:1234`),
we introduce `force_len`(e.g. `MAC_ADDR_OCTETS = [6, 20]`) to raise
error for invalid integer value.

Signed-off-by: Wen Liang <[email protected]>
  • Loading branch information
liangwen12year committed May 2, 2021
1 parent cffefa8 commit 48706ab
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 2 deletions.
19 changes: 18 additions & 1 deletion module_utils/network_lsr/argument_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
from ansible.module_utils.network_lsr.utils import Util # noqa:E501

UINT32_MAX = 0xFFFFFFFF
# a MAC address for type ethernet requires 6 octets
# a MAC address for type infiniband requires 20 octets
MAC_ADDR_OCTETS = [6, 20]


class ArgUtil:
Expand Down Expand Up @@ -413,11 +416,25 @@ def _validate_impl(self, value, name):


class ArgValidatorMac(ArgValidatorStr):
def __init__(self, name, force_len=None, required=False, default_value=None):
def __init__(
self, name, force_len=MAC_ADDR_OCTETS, required=False, default_value=None
):
ArgValidatorStr.__init__(self, name, required, default_value, None)
self.force_len = force_len

def _validate_impl(self, value, name):
if type(value) == int:
try:
value = Util.num_to_mac(value, self.force_len)
except MyError:
raise ValidationError(
name, "value '%s' is not a valid MAC address" % (value)
)
if not isinstance(value, Util.STRING_TYPE):
raise ValidationError(
name,
"must be a string and value should be quoted, but is '%s', " % (value),
)
v = ArgValidatorStr._validate_impl(self, value, name)
try:
addr = Util.mac_aton(v, self.force_len)
Expand Down
20 changes: 19 additions & 1 deletion module_utils/network_lsr/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def mac_aton(mac_str, force_len=None):
if i == 1:
raise MyError("not a valid MAC address: '%s'" % (mac_str))
if force_len is not None:
if force_len != len(b):
if not any(a for a in force_len if a == len(b)):
raise MyError(
"not a valid MAC address of length %s: '%s'" % (force_len, mac_str)
)
Expand All @@ -267,6 +267,24 @@ def mac_ntoa(mac):
def mac_norm(mac_str, force_len=None):
return Util.mac_ntoa(Util.mac_aton(mac_str, force_len))

@staticmethod
def num_to_mac(num, force_len=None):
mac = []
s_num = num
while num:
num, mod = divmod(num, 60)
if mod < 10:
mac.insert(0, "0" + str(mod))
else:
mac.insert(0, str(mod))
mac_addr = ":".join(mac)
if force_len is not None:
if not any(a for a in force_len if a == len(mac)):
raise MyError(
"not a valid number '%d' for MAC address: '%s'" % (s_num, mac_addr)
)
return mac_addr

@staticmethod
def boolean(arg):
if arg is None or isinstance(arg, bool):
Expand Down
35 changes: 35 additions & 0 deletions tests/unit/test_network_connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -3260,6 +3260,41 @@ def test_set_deprecated_slave_type(self):
self.assertTrue("port_type" in connection)
self.assertTrue("slave_type" not in connection)

def test_mac_address_argvalidator(self):
"""
Test that argvalidator for validating mac address is correctly defined.
"""
validator = network_lsr.argument_validator.ArgValidatorMac("mac")
self.assertEqual(validator.validate(41135085296), "52:54:00:12:34:56")
self.assertEqual(validator.validate("00:00:5e:00:53:5d"), "00:00:5e:00:53:5d")
self.assertEqual(validator.validate("00:00:00:00:00:00"), "00:00:00:00:00:00")
self.assertEqual(validator.validate("ff:ff:ff:ff:ff:ff"), "ff:ff:ff:ff:ff:ff")
self.assertEqual(
validator.validate(
"80:00:00:6d:fe:80:00:00:00:00:00:00:00:02:55:00:70:33:cf:01"
),
"80:00:00:6d:fe:80:00:00:00:00:00:00:00:02:55:00:70:33:cf:01",
)
self.assertEqual(
validator.validate(
"01:02:03:04:05:06:07:08:09:0A:01:02:03:04:05:06:07:08:09:11"
),
"01:02:03:04:05:06:07:08:09:0a:01:02:03:04:05:06:07:08:09:11",
)
self.assertValidationError(validator, 1234)
self.assertValidationError(validator, "aa:bb")
self.assertValidationError(validator, sys.maxsize)
self.assertValidationError(validator, 0)
self.assertValidationError(
validator, "80:00:00:6d:fe:80:00:00:00:00:00:00:00:02:55:00:70:33:cf:"
)
self.assertValidationError(
validator, "80:00:00:6d:fe:80:00:00:00:00:00:00:00:02:55:00:70:33:cf:xx"
)
self.assertValidationError(
validator, "80:00:00:6d:fe:80:00:00:00:00:00:00:00:02:55:000:70:33:cf:01"
)


@my_test_skipIf(nmutil is None, "no support for NM (libnm via pygobject)")
class TestNM(unittest.TestCase):
Expand Down

0 comments on commit 48706ab

Please sign in to comment.