saltstack/salt — pull request #7555 by VertigoRay (2013-10-02 04:53:06+00:00)
Title: OSError: [Errno 22] Invalid argument - caused by duplicate gids.

Currently, `supgroups` can return a list that has duplicate gids in it:
```python
>>> supgroups = [g.gr_gid for g in grp.getgrall() if uinfo.pw_name in g.gr_mem and g.gr_gid != uinfo.pw_gid]
>>> supgroups
[80, 29, 1, 2, 5, 9, 8, 20, 3, 4, 1, 2, 3, 4, 5, 8, 9, 20, 29, 80]
```

This causes problems in the comparison of [`sorted(os.getgroups()) != sorted(supgroups)`](https://github.com/saltstack/salt/blob/0.17/salt/modules/cmdmod.py#L80). More importantly, it causes an *OSError* when trying to run [`os.setgroups(supgroups)`](https://github.com/saltstack/salt/blob/0.17/salt/modules/cmdmod.py#L82). Simply de-duplicating the list during the creation process resolves the issue.

Here's simple script that should help you understand (foo.py):
```python
import os
import pwd
import grp

uinfo = pwd.getpwnam('root')
print('uinfo: %s' % uinfo)
print('[g.gr_gid for g in grp.getgrall()]: %s' % [g.gr_gid for g in grp.getgrall()])
supgroups = [g.gr_gid for g in grp.getgrall() if uinfo.pw_name in g.gr_mem and g.gr_gid != uinfo.pw_gid]
print('supgroups: %s' % supgroups)
print('Notice the duplication ...')
print('os.getgroups(): %s' % os.getgroups())

try:
os.setgroups(supgroups)
except OSError as e:
print('Error: %s' % e)

print('type(supgroups): %s' % type(supgroups))
seen = set()
supgroups_deduped = [ x for x in supgroups if x not in seen and not seen.add(x) ]
print('supgroups_deduped: %s' % supgroups_deduped)
os.setgroups(supgroups_deduped)
print('os.getgroups(): %s' % os.getgroups())
```
Output:
```sh
# python foo.py
uinfo: pwd.struct_passwd(pw_name='root', pw_passwd='*', pw_uid=0, pw_gid=0, pw_gecos='System Administrator', pw_dir='/var/root', pw_shell='/bin/sh')
[g.gr_gid for g in grp.getgrall()]: [83, 55, 87, 81, 79, 33, 67, 235, 97, 93, 32, 82, 202, 212, 72, 207, 59, 204, 220, 227, 56, 201, 25, 96, 84, 30, 211, 205, 26, 98, 100, 78, 54, 65, 74, 222, 228, 24, 209, 28, 27, 216, 76, 60, 203, 31, 92, 58, 200, 89, 75, 73, 13, 94, 210, 91, 208, 99, 95, 213, 66, 224, 221, 88, 70, 90, 80, 50, 7, 29, 401, 53, 1, 68, 12, 16, 51, 2, 61, 6, 62, 52, 69, 4294967294, 4294967295, 5, 10, 9, 8, 20, 3, 4, 45, 0, 2106269579, 4294967294, 4294967295, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 16, 20, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 45, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 65, 66, 67, 68, 69, 70, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 200, 201, 202, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 216, 220, 221, 222, 224, 227, 228]
supgroups: [80, 29, 1, 2, 5, 9, 8, 20, 3, 4, 1, 2, 3, 4, 5, 8, 9, 20, 29, 80]
Notice the duplication ...
os.getgroups(): [0, 401, 1, 2, 3, 4, 5, 8, 9, 12, 20, 29, 33, 61, 80, 98]
Error: [Errno 22] Invalid argument
type(supgroups):
supgroups_deduped: [80, 29, 1, 2, 5, 9, 8, 20, 3, 4]
os.getgroups(): [0, 401, 1, 2, 3, 4, 5, 8, 9, 12, 20, 29, 33, 61, 80, 98]
```

Of course, `os.getgroups()` doesn't work as expected in *OS X 10.5+*:
* http://docs.python.org/2/library/os.html#os.getgroups
* http://docs.python.org/2/library/os.html#os.setgroups

Not sure how to work around that yet, but at least we won't get an error when `sorted(os.getgroups())` matches `sorted(supgroups)`!! ;)

```sh
# /usr/local/bin/salt-minion --versions-report
Salt: 0.16.3
Python: 2.7.2 (default, Oct 11 2012, 20:14:37)
Jinja2: 2.7.1
M2Crypto: 0.21.1
msgpack-python: 0.3.0
msgpack-pure: Not Installed
pycrypto: 2.6
PyYAML: 3.10
PyZMQ: 13.1.0
ZMQ: 3.2.3
```
OS X 10.8.4