summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cloudinit/distros/__init__.py13
-rw-r--r--tests/unittests/test_distros/test_create_users.py28
2 files changed, 37 insertions, 4 deletions
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index ef618c28..20c994dc 100644
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -577,11 +577,16 @@ class Distro(object):
"""
Lock the password of a user, i.e., disable password logins
"""
+ # passwd must use short '-l' due to SLES11 lacking long form '--lock'
+ lock_tools = (['passwd', '-l', name], ['usermod', '--lock', name])
try:
- # Need to use the short option name '-l' instead of '--lock'
- # (which would be more descriptive) since SLES 11 doesn't know
- # about long names.
- util.subp(['passwd', '-l', name])
+ cmd = next(l for l in lock_tools if util.which(l[0]))
+ except StopIteration:
+ raise RuntimeError((
+ "Unable to lock user account '%s'. No tools available. "
+ " Tried: %s.") % (name, [c[0] for c in lock_tools]))
+ try:
+ util.subp(cmd)
except Exception as e:
util.logexc(LOG, 'Failed to disable password for user %s', name)
raise e
diff --git a/tests/unittests/test_distros/test_create_users.py b/tests/unittests/test_distros/test_create_users.py
index c3f258d5..40624952 100644
--- a/tests/unittests/test_distros/test_create_users.py
+++ b/tests/unittests/test_distros/test_create_users.py
@@ -240,4 +240,32 @@ class TestCreateUser(CiTestCase):
[mock.call(set(['auth1']), user), # not disabled
mock.call(set(['key1']), 'foouser', options=disable_prefix)])
+ @mock.patch("cloudinit.distros.util.which")
+ def test_lock_with_usermod_if_no_passwd(self, m_which, m_subp,
+ m_is_snappy):
+ """Lock uses usermod --lock if no 'passwd' cmd available."""
+ m_which.side_effect = lambda m: m in ('usermod',)
+ self.dist.lock_passwd("bob")
+ self.assertEqual(
+ [mock.call(['usermod', '--lock', 'bob'])],
+ m_subp.call_args_list)
+
+ @mock.patch("cloudinit.distros.util.which")
+ def test_lock_with_passwd_if_available(self, m_which, m_subp,
+ m_is_snappy):
+ """Lock with only passwd will use passwd."""
+ m_which.side_effect = lambda m: m in ('passwd',)
+ self.dist.lock_passwd("bob")
+ self.assertEqual(
+ [mock.call(['passwd', '-l', 'bob'])],
+ m_subp.call_args_list)
+
+ @mock.patch("cloudinit.distros.util.which")
+ def test_lock_raises_runtime_if_no_commands(self, m_which, m_subp,
+ m_is_snappy):
+ """Lock with no commands available raises RuntimeError."""
+ m_which.return_value = None
+ with self.assertRaises(RuntimeError):
+ self.dist.lock_passwd("bob")
+
# vi: ts=4 expandtab