Merge lp:~jamesbeedy/charm-helpers/add_uid_gid into lp:charm-helpers

Proposed by james beedy
Status: Merged
Merged at revision: 581
Proposed branch: lp:~jamesbeedy/charm-helpers/add_uid_gid
Merge into: lp:charm-helpers
Diff against target: 190 lines (+103/-8)
2 files modified
charmhelpers/core/host.py (+53/-4)
tests/core/test_host.py (+50/-4)
To merge this branch: bzr merge lp:~jamesbeedy/charm-helpers/add_uid_gid
Reviewer Review Type Date Requested Status
Matt Bruzek Approve
Review via email: mp+295996@code.launchpad.net

Description of the change

Added uid and gid specification functionality for adduser and addgroup.

Modified adduser and addgroup to include optional uid and gid
specification functionality.

Also added 3 new helper functions uid_exists, gid_exists, and group_exists.

Fixes: Bug #1586693

To post a comment you must log in.
Revision history for this message
Matt Bruzek (mbruzek) wrote :

Thanks for the contribution James! Overall I think this kind of change is a good thing and I am interested to see it land. I see that the new arguments are optional so that will not break backwards compatibility with previous callers of this method.

I found a small problem with the cmd array manipulation. By using .append('--uid 1003') that creates a single array element with a space where we want 2 new elements. If you fix that, I can get behind this change.

Thanks for the work I look forward to the next iteration.

Revision history for this message
Matt Bruzek (mbruzek) wrote :

When I tried to 'make test' many of the existing tests fail because the positional arguments are setting the uid argument.

ERROR: tests.core.test_host.HelpersTest.test_doesnt_add_user_if_it_already_exists
----------------------------------------------------------------------
_StringException: Traceback (most recent call last):
  File "/tmp/add_uid_gid/.venv/local/lib/python2.7/site-packages/mock.py", line 1201, in patched
    return func(*args, **keywargs)
  File "/tmp/add_uid_gid/tests/core/test_host.py", line 560, in test_doesnt_add_user_if_it_already_exists
    result = host.adduser(username, password)
  File "/tmp/add_uid_gid/charmhelpers/core/host.py", line 198, in adduser
    user_info = pwd.getpwuid(uid)
TypeError: an integer is required

FAIL: tests.core.test_host.HelpersTest.test_adds_a_user_if_it_doesnt_exist
AssertionError: Expected call: check_call(['useradd', '--create-home', '--shell', '/bin/bash', '--password', 'eodnho
j', '-g', 'johndoe', 'johndoe'])
Actual call: check_call(['useradd', '--uid eodnhoj', '--system', '-g', 'johndoe', 'johndoe'])

FAIL: tests.core.test_host.HelpersTest.test_adds_a_user_with_different_shell
AssertionError: Expected call: check_call(['useradd', '--create-home', '--shell', '/bin/zsh', '--password', 'eodnhoj
', 'johndoe'])
Actual call: check_call(['useradd', '--uid eodnhoj', '--system', 'johndoe'])

FAIL: tests.core.test_host.HelpersTest.test_adduser_with_groups
AssertionError: Expected call: check_call(['useradd', '--create-home', '--shell', '/bin/bash', '--password', 'eodnho
j', '-g', 'foo', '-G', 'bar,qux', 'johndoe'])
Actual call: check_call(['useradd', '--uid eodnhoj', '--system', '-g', 'foo', '-G', 'bar,qux', 'johndoe'])

The tests need to pass before this change can be accepted.

review: Needs Fixing
581. By james beedy

cleanup

582. By James Beedy <jbeedy@virt-test0>

syntax

583. By James Beedy <jbeedy@virt-test0>

Add keyword argument for password in user tests

Modified calls to adduser to specify a keyword
arg for password.

Revision history for this message
james beedy (jamesbeedy) wrote :

@mbruzek Thanks for the review. The tests are now passing!
Looking at writing a few tests specific to the uid and gid functionality as well.

Revision history for this message
Matt Bruzek (mbruzek) wrote :

Hey James, I _just_ created a merge proposal against this branch of code that has fixes and tests passing. Please consider: https://code.launchpad.net/~mbruzek/charm-helpers/add_uid_gid/+merge/296130

Sorry it took so long, I had been interrupted several times with meetings before making this request.

Revision history for this message
Matt Bruzek (mbruzek) wrote :

> Hey James, I _just_ created a merge proposal against this branch of code that
> has fixes and tests passing. Please consider:
> https://code.launchpad.net/~mbruzek/charm-helpers/add_uid_gid/+merge/296132
>
> Sorry it took so long, I had been interrupted several times with meetings
> before making this request.

584. By James Beedy <jbeedy@virt-test0>

Merge lp:~mbruzek/charm-helpers/add_uid_gid

Fix text conflict

Revision history for this message
Matt Bruzek (mbruzek) wrote :

There was still one lint error, but I fixed that and pushed this change to charm-helpers. Thank you for the contribution!

review: Approve
Revision history for this message
Matt Bruzek (mbruzek) wrote :

make tests pass and I am satisfied with the code changes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charmhelpers/core/host.py'
--- charmhelpers/core/host.py 2016-05-17 17:41:24 +0000
+++ charmhelpers/core/host.py 2016-05-31 20:24:20 +0000
@@ -174,9 +174,8 @@
174 """Return True if the host system uses systemd, False otherwise."""174 """Return True if the host system uses systemd, False otherwise."""
175 return os.path.isdir(SYSTEMD_SYSTEM)175 return os.path.isdir(SYSTEMD_SYSTEM)
176176
177
178def adduser(username, password=None, shell='/bin/bash', system_user=False,177def adduser(username, password=None, shell='/bin/bash', system_user=False,
179 primary_group=None, secondary_groups=None):178 primary_group=None, secondary_groups=None, uid=None):
180 """Add a user to the system.179 """Add a user to the system.
181180
182 Will log but otherwise succeed if the user already exists.181 Will log but otherwise succeed if the user already exists.
@@ -187,15 +186,21 @@
187 :param bool system_user: Whether to create a login or system user186 :param bool system_user: Whether to create a login or system user
188 :param str primary_group: Primary group for user; defaults to username187 :param str primary_group: Primary group for user; defaults to username
189 :param list secondary_groups: Optional list of additional groups188 :param list secondary_groups: Optional list of additional groups
189 :param int uid: UID for user being created
190190
191 :returns: The password database entry struct, as returned by `pwd.getpwnam`191 :returns: The password database entry struct, as returned by `pwd.getpwnam`
192 """192 """
193 try:193 try:
194 user_info = pwd.getpwnam(username)194 user_info = pwd.getpwnam(username)
195 log('user {0} already exists!'.format(username))195 log('user {0} already exists!'.format(username))
196 if uid:
197 user_info = pwd.getpwuid(int(uid))
198 log('user with uid {0} already exists!'.format(uid))
196 except KeyError:199 except KeyError:
197 log('creating user {0}'.format(username))200 log('creating user {0}'.format(username))
198 cmd = ['useradd']201 cmd = ['useradd']
202 if uid:
203 cmd.extend(['--uid', str(uid)])
199 if system_user or password is None:204 if system_user or password is None:
200 cmd.append('--system')205 cmd.append('--system')
201 else:206 else:
@@ -230,14 +235,58 @@
230 return user_exists235 return user_exists
231236
232237
233def add_group(group_name, system_group=False):238def uid_exists(uid):
234 """Add a group to the system"""239 """Check if a uid exists"""
240 try:
241 pwd.getpwuid(uid)
242 uid_exists = True
243 except KeyError:
244 uid_exists = False
245 return uid_exists
246
247
248def group_exists(groupname):
249 """Check if a group exists"""
250 try:
251 grp.getgrnam(groupname)
252 group_exists = True
253 except KeyError:
254 group_exists = False
255 return group_exists
256
257
258def gid_exists(gid):
259 """Check if a gid exists"""
260 try:
261 grp.getgrgid(gid)
262 gid_exists = True
263 except KeyError:
264 gid_exists = False
265 return gid_exists
266
267
268def add_group(group_name, system_group=False, gid=None):
269 """Add a group to the system
270
271 Will log but otherwise succeed if the group already exists.
272
273 :param str group_name: group to create
274 :param bool system_group: Create system group
275 :param int gid: GID for user being created
276
277 :returns: The password database entry struct, as returned by `grp.getgrnam`
278 """
235 try:279 try:
236 group_info = grp.getgrnam(group_name)280 group_info = grp.getgrnam(group_name)
237 log('group {0} already exists!'.format(group_name))281 log('group {0} already exists!'.format(group_name))
282 if gid:
283 group_info = grp.getgrgid(gid)
284 log('group with gid {0} already exists!'.format(gid))
238 except KeyError:285 except KeyError:
239 log('creating group {0}'.format(group_name))286 log('creating group {0}'.format(group_name))
240 cmd = ['addgroup']287 cmd = ['addgroup']
288 if gid:
289 cmd.extend(['--gid', str(gid)])
241 if system_group:290 if system_group:
242 cmd.append('--system')291 cmd.append('--system')
243 else:292 else:
244293
=== modified file 'tests/core/test_host.py'
--- tests/core/test_host.py 2016-05-17 17:37:13 +0000
+++ tests/core/test_host.py 2016-05-31 20:24:20 +0000
@@ -533,7 +533,7 @@
533533
534 getpwnam.side_effect = [existing_user_pwnam, new_user_pwnam]534 getpwnam.side_effect = [existing_user_pwnam, new_user_pwnam]
535535
536 result = host.adduser(username, password)536 result = host.adduser(username, password=password)
537537
538 self.assertEqual(result, new_user_pwnam)538 self.assertEqual(result, new_user_pwnam)
539 check_call.assert_called_with([539 check_call.assert_called_with([
@@ -557,7 +557,7 @@
557557
558 getpwnam.return_value = existing_user_pwnam558 getpwnam.return_value = existing_user_pwnam
559559
560 result = host.adduser(username, password)560 result = host.adduser(username, password=password)
561561
562 self.assertEqual(result, existing_user_pwnam)562 self.assertEqual(result, existing_user_pwnam)
563 self.assertFalse(check_call.called)563 self.assertFalse(check_call.called)
@@ -578,7 +578,7 @@
578 getpwnam.side_effect = [existing_user_pwnam, new_user_pwnam]578 getpwnam.side_effect = [existing_user_pwnam, new_user_pwnam]
579 getgrnam.side_effect = KeyError('group not found')579 getgrnam.side_effect = KeyError('group not found')
580580
581 result = host.adduser(username, password, shell=shell)581 result = host.adduser(username, password=password, shell=shell)
582582
583 self.assertEqual(result, new_user_pwnam)583 self.assertEqual(result, new_user_pwnam)
584 check_call.assert_called_with([584 check_call.assert_called_with([
@@ -603,7 +603,7 @@
603603
604 getpwnam.side_effect = [existing_user_pwnam, new_user_pwnam]604 getpwnam.side_effect = [existing_user_pwnam, new_user_pwnam]
605605
606 result = host.adduser(username, password,606 result = host.adduser(username, password=password,
607 primary_group='foo', secondary_groups=[607 primary_group='foo', secondary_groups=[
608 'bar', 'qux',608 'bar', 'qux',
609 ])609 ])
@@ -642,6 +642,52 @@
642 getpwnam.assert_called_with(username)642 getpwnam.assert_called_with(username)
643643
644 @patch('pwd.getpwnam')644 @patch('pwd.getpwnam')
645 @patch('pwd.getpwuid')
646 @patch('grp.getgrnam')
647 @patch('subprocess.check_call')
648 @patch.object(host, 'log')
649 def test_add_user_uid(self, log, check_call, getgrnam, getpwuid, getpwnam):
650 user_name = 'james'
651 user_id = 1111
652 uid_key_error = KeyError('user not found')
653 getpwuid.side_effect = uid_key_error
654 host.adduser(user_name, uid=user_id)
655
656 check_call.assert_called_with([
657 'useradd',
658 '--uid',
659 str(user_id),
660 '--system',
661 '-g',
662 user_name,
663 user_name
664 ])
665 getpwnam.assert_called_with(user_name)
666 getpwuid.assert_called_with(user_id)
667
668 @patch('grp.getgrnam')
669 @patch('grp.getgrgid')
670 @patch('subprocess.check_call')
671 @patch.object(host, 'log')
672 def test_add_group_gid(self, log, check_call, getgrgid, getgrnam):
673 group_name = 'darkhorse'
674 group_id = 1005
675 existing_group_gid = KeyError('group not found')
676 new_group_gid = 1006
677 getgrgid.side_effect = [existing_group_gid, new_group_gid]
678
679 host.add_group(group_name, gid=group_id)
680 check_call.assert_called_with([
681 'addgroup',
682 '--gid',
683 str(group_id),
684 '--group',
685 group_name
686 ])
687 getgrgid.assert_called_with(group_id)
688 getgrnam.assert_called_with(group_name)
689
690 @patch('pwd.getpwnam')
645 def test_user_exists_true(self, getpwnam):691 def test_user_exists_true(self, getpwnam):
646 getpwnam.side_effect = 'pw info'692 getpwnam.side_effect = 'pw info'
647 self.assertTrue(host.user_exists('bob'))693 self.assertTrue(host.user_exists('bob'))

Subscribers

People subscribed via source and target branches