mirror of
https://github.com/facebook/sapling.git
synced 2024-10-06 23:07:18 +03:00
grpcheck: new extension to check if the user is in given groups
Summary: We have seen issues that users have outdated groups when running hg commands, which will probably always cause issues: - Authentication issue, unable to ssh - Filesystem permission issue, unable to write hgcache - Even worse with chg server since the long-running server process will keep the wrong groups information This extension is to address the above issues. It allows us to print a message to let the user know they have group issues. Besides, it allows us to override configs like `chgserver.idletimeout` so chg servers with wrong groups can have a much smaller TTL and won't be long-running and causing issues. Test Plan: Run the newly added test Reviewers: #sourcecontrol, simonfar Reviewed By: simonfar Subscribers: simonfar, mjpieters Differential Revision: https://phabricator.intern.facebook.com/D3896628 Signature: t1:3896628:1474454162:22785ff23e3ada75013ce5f1eead3407068ba172
This commit is contained in:
parent
71c96fe8ea
commit
73eac46994
72
hgext3rd/grpcheck.py
Normal file
72
hgext3rd/grpcheck.py
Normal file
@ -0,0 +1,72 @@
|
||||
# grpcheck.py - check if the user is in specified groups
|
||||
#
|
||||
# Copyright 2015 Facebook, Inc.
|
||||
#
|
||||
# This software may be used and distributed according to the terms of the
|
||||
# GNU General Public License version 2 or any later version.
|
||||
|
||||
"""check if the user is in specified groups
|
||||
|
||||
If the user is not a member of specified groups, optionally show a warning
|
||||
message and override some other config items.
|
||||
|
||||
::
|
||||
[grpcheck]
|
||||
# the user is expected to be a member of devs and users group
|
||||
groups = devs, users
|
||||
# warning to show if the user is not a member of any of those groups
|
||||
warning = You are not a member of %s group. Consult IT department for help.
|
||||
# if the user is not a member of any of those groups, override chgserver
|
||||
# config to make chgserver exit earlier
|
||||
overrides.chgserver.idletimeout = 2
|
||||
"""
|
||||
|
||||
import os
|
||||
import grp
|
||||
|
||||
testedwith = '3.9'
|
||||
|
||||
_missinggroup = None
|
||||
|
||||
def _grpname2gid(name):
|
||||
try:
|
||||
return grp.getgrnam(name).gr_gid
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def _firstmissinggroup(groupnames):
|
||||
usergids = set(os.getgroups())
|
||||
for name in groupnames:
|
||||
expectedgid = _grpname2gid(name)
|
||||
# ignore unknown groups
|
||||
if expectedgid is not None and expectedgid not in usergids:
|
||||
return name
|
||||
|
||||
def _overrideconfigs(ui):
|
||||
for k, v in ui.configitems('grpcheck'):
|
||||
if not k.startswith('overrides.'):
|
||||
continue
|
||||
section, name = k[len('overrides.'):].split('.', 1)
|
||||
ui.setconfig(section, name, v)
|
||||
|
||||
def extsetup(ui):
|
||||
groupnames = ui.configlist('grpcheck', 'groups')
|
||||
if not groupnames:
|
||||
return
|
||||
missing = _firstmissinggroup(groupnames)
|
||||
if not missing:
|
||||
return
|
||||
message = ui.config('grpcheck', 'warning')
|
||||
if message and not ui.plain():
|
||||
if '%s' in message:
|
||||
message = message % missing
|
||||
ui.warn(message + '\n')
|
||||
_overrideconfigs(ui)
|
||||
# re-used by reposetup. groups information is immutable for a process,
|
||||
# so we can re-use the "missing" calculation result safely.
|
||||
global _missinggroup
|
||||
_missinggroup = missing
|
||||
|
||||
def reposetup(ui, repo):
|
||||
if _missinggroup:
|
||||
_overrideconfigs(ui)
|
73
tests/test-grpcheck.t
Normal file
73
tests/test-grpcheck.t
Normal file
@ -0,0 +1,73 @@
|
||||
$ cat >> $HGRCPATH << EOF
|
||||
> [extensions]
|
||||
> grpcheck = $TESTDIR/../hgext3rd/grpcheck.py
|
||||
> EOF
|
||||
|
||||
$ hg init repo
|
||||
$ cd repo
|
||||
|
||||
mock os.getgroups and grp.getgrnam
|
||||
|
||||
$ cat >> $TESTTMP/mockgrp.py << EOF
|
||||
> import os, grp
|
||||
> def _getgroups():
|
||||
> return map(int, os.environ.get('HGMOCKGRPS', '1000').split())
|
||||
> class _grp(object):
|
||||
> def __init__(self, gid):
|
||||
> self.gr_gid = gid
|
||||
> def _getgrnam(name):
|
||||
> if name == 'users':
|
||||
> gid = 1000
|
||||
> elif name == 'devs':
|
||||
> gid = 2000
|
||||
> else:
|
||||
> raise KeyError()
|
||||
> return _grp(gid)
|
||||
> os.getgroups = _getgroups
|
||||
> grp.getgrnam = _getgrnam
|
||||
> EOF
|
||||
|
||||
$ cat >> $HGRCPATH << EOF
|
||||
> mockgrp = $TESTTMP/mockgrp.py
|
||||
> [grpcheck]
|
||||
> groups = users, devs
|
||||
> warning = You should be in %s group.
|
||||
> overrides.chgserver.idletimeout = 3
|
||||
> overrides.ui.foo = bar
|
||||
> EOF
|
||||
|
||||
when the user is not in those groups, warnings are printed
|
||||
|
||||
$ hg log
|
||||
You should be in devs group.
|
||||
$ HGMOCKGRPS=100 hg log
|
||||
You should be in users group.
|
||||
$ HGMOCKGRPS='100 1000' hg log
|
||||
You should be in devs group.
|
||||
|
||||
customized warning message
|
||||
|
||||
$ hg --config grpcheck.warning=foo log
|
||||
foo
|
||||
|
||||
no warning if HGPLAIN or grpcheck.warning is empty
|
||||
|
||||
$ hg --config grpcheck.warning= log
|
||||
$ HGPLAIN=1 hg log
|
||||
|
||||
warning does not affect write action (commit)
|
||||
|
||||
$ touch a
|
||||
$ hg commit -A a -m a
|
||||
You should be in devs group.
|
||||
$ hg log -T '{rev} {node}\n'
|
||||
You should be in devs group.
|
||||
0 3903775176ed42b1458a6281db4a0ccf4d9f287a
|
||||
|
||||
config overrides
|
||||
|
||||
$ HGPLAIN=1 hg config --untrusted chgserver.idletimeout
|
||||
3
|
||||
$ cd .. # use repo ui
|
||||
$ HGPLAIN=1 hg config --untrusted ui.foo
|
||||
bar
|
Loading…
Reference in New Issue
Block a user