nixos/taskserver: Don't change imperative users
Whenever the nixos-taskserver tool was invoked manually for creating an organisation/group/user we now add an empty file called .imperative to the data directory. During the preStart of the Taskserver service, we use process-json which in turn now checks whether those .imperative files exist and if so, it doesn't do anything with it. This should now ensure that whenever there is a manually created user, it doesn't get killed off by the declarative configuration in case it shouldn't exist within that configuration. In addition, we also add a small subtest to check whether this is happening or not and fail if the imperatively created user got deleted by process-json. Signed-off-by: aszlig <aszlig@redmoonstudios.org>
This commit is contained in:
parent
9586795ef2
commit
a41b109bc1
@ -96,6 +96,28 @@ def mkpath(*args):
|
||||
return os.path.join(TASKD_DATA_DIR, "orgs", *args)
|
||||
|
||||
|
||||
def mark_imperative(*path):
|
||||
"""
|
||||
Mark the specified path as being imperatively managed by creating an empty
|
||||
file called ".imperative", so that it doesn't interfere with the
|
||||
declarative configuration.
|
||||
"""
|
||||
open(os.path.join(mkpath(*path), ".imperative"), 'a').close()
|
||||
|
||||
|
||||
def is_imperative(*path):
|
||||
"""
|
||||
Check whether the given path is marked as imperative, see mark_imperative()
|
||||
for more information.
|
||||
"""
|
||||
full_path = []
|
||||
for component in path:
|
||||
full_path.append(component)
|
||||
if os.path.exists(os.path.join(mkpath(*full_path), ".imperative")):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def fetch_username(org, key):
|
||||
for line in open(mkpath(org, "users", key, "config"), "r"):
|
||||
match = RE_CONFIGUSER.match(line)
|
||||
@ -247,8 +269,9 @@ class Group(object):
|
||||
|
||||
|
||||
class Organisation(object):
|
||||
def __init__(self, name):
|
||||
def __init__(self, name, ignore_imperative):
|
||||
self.name = name
|
||||
self.ignore_imperative = ignore_imperative
|
||||
|
||||
def add_user(self, name):
|
||||
"""
|
||||
@ -256,6 +279,8 @@ class Organisation(object):
|
||||
|
||||
Returns a 'User' object or None if the user already exists.
|
||||
"""
|
||||
if self.ignore_imperative and is_imperative(self.name):
|
||||
return None
|
||||
if name not in self.users.keys():
|
||||
output = taskd_cmd("add", "user", self.name, name,
|
||||
capture_stdout=True)
|
||||
@ -265,7 +290,7 @@ class Organisation(object):
|
||||
raise TaskdError(msg.format(name))
|
||||
|
||||
generate_key(self.name, name)
|
||||
newuser = User(self.name, name, key)
|
||||
newuser = User(self.name, name, key.group(1))
|
||||
self._lazy_users[name] = newuser
|
||||
return newuser
|
||||
return None
|
||||
@ -275,8 +300,12 @@ class Organisation(object):
|
||||
Delete a user and revoke its keys.
|
||||
"""
|
||||
if name in self.users.keys():
|
||||
# Work around https://bug.tasktools.org/browse/TD-40:
|
||||
user = self.get_user(name)
|
||||
if self.ignore_imperative and \
|
||||
is_imperative(self.name, "users", user.key):
|
||||
return
|
||||
|
||||
# Work around https://bug.tasktools.org/browse/TD-40:
|
||||
rmtree(mkpath(self.name, "users", user.key))
|
||||
|
||||
revoke_key(self.name, name)
|
||||
@ -288,6 +317,8 @@ class Organisation(object):
|
||||
|
||||
Returns a 'Group' object or None if the group already exists.
|
||||
"""
|
||||
if self.ignore_imperative and is_imperative(self.name):
|
||||
return None
|
||||
if name not in self.groups.keys():
|
||||
taskd_cmd("add", "group", self.name, name)
|
||||
newgroup = Group(self.name, name)
|
||||
@ -300,6 +331,9 @@ class Organisation(object):
|
||||
Delete a group.
|
||||
"""
|
||||
if name in self.users.keys():
|
||||
if self.ignore_imperative and \
|
||||
is_imperative(self.name, "groups", name):
|
||||
return
|
||||
taskd_cmd("remove", "group", self.name, name)
|
||||
del self._lazy_groups[name]
|
||||
|
||||
@ -327,6 +361,16 @@ class Organisation(object):
|
||||
|
||||
|
||||
class Manager(object):
|
||||
def __init__(self, ignore_imperative=False):
|
||||
"""
|
||||
Instantiates an organisations manager.
|
||||
|
||||
If ignore_imperative is True, all actions that modify data are checked
|
||||
whether they're created imperatively and if so, they will result in no
|
||||
operation.
|
||||
"""
|
||||
self.ignore_imperative = ignore_imperative
|
||||
|
||||
def add_org(self, name):
|
||||
"""
|
||||
Create a new organisation.
|
||||
@ -336,7 +380,7 @@ class Manager(object):
|
||||
"""
|
||||
if name not in self.orgs.keys():
|
||||
taskd_cmd("add", "org", name)
|
||||
neworg = Organisation(name)
|
||||
neworg = Organisation(name, self.ignore_imperative)
|
||||
self._lazy_orgs[name] = neworg
|
||||
return neworg
|
||||
return None
|
||||
@ -348,6 +392,8 @@ class Manager(object):
|
||||
"""
|
||||
org = self.get_org(name)
|
||||
if org is not None:
|
||||
if self.ignore_imperative and is_imperative(name):
|
||||
return
|
||||
for user in org.users.keys():
|
||||
org.del_user(user)
|
||||
for group in org.groups.keys():
|
||||
@ -362,7 +408,7 @@ class Manager(object):
|
||||
def orgs(self):
|
||||
result = {}
|
||||
for org in os.listdir(mkpath()):
|
||||
result[org] = Organisation(org)
|
||||
result[org] = Organisation(org, self.ignore_imperative)
|
||||
return result
|
||||
|
||||
|
||||
@ -452,6 +498,7 @@ def add_org(name):
|
||||
sys.exit(msg.format(name))
|
||||
|
||||
taskd_cmd("add", "org", name)
|
||||
mark_imperative(name)
|
||||
|
||||
|
||||
@cli.command("del-org")
|
||||
@ -485,6 +532,8 @@ def add_user(organisation, user):
|
||||
if userobj is None:
|
||||
msg = "User {} already exists in organisation {}."
|
||||
sys.exit(msg.format(user, organisation))
|
||||
else:
|
||||
mark_imperative(organisation.name, "users", userobj.key)
|
||||
|
||||
|
||||
@cli.command("del-user")
|
||||
@ -510,10 +559,12 @@ def add_group(organisation, group):
|
||||
"""
|
||||
Create a group for the given organisation.
|
||||
"""
|
||||
userobj = organisation.add_group(group)
|
||||
if userobj is None:
|
||||
groupobj = organisation.add_group(group)
|
||||
if groupobj is None:
|
||||
msg = "Group {} already exists in organisation {}."
|
||||
sys.exit(msg.format(group, organisation))
|
||||
else:
|
||||
mark_imperative(organisation.name, "groups", groupobj.name)
|
||||
|
||||
|
||||
@cli.command("del-group")
|
||||
@ -562,10 +613,12 @@ def process_json(json_file):
|
||||
"""
|
||||
data = json.load(json_file)
|
||||
|
||||
mgr = Manager()
|
||||
mgr = Manager(ignore_imperative=True)
|
||||
add_or_delete(mgr.orgs.keys(), data.keys(), mgr.add_org, mgr.del_org)
|
||||
|
||||
for org in mgr.orgs.values():
|
||||
if is_imperative(org.name):
|
||||
continue
|
||||
add_or_delete(org.users.keys(), data[org.name]['users'],
|
||||
org.add_user, org.del_user)
|
||||
add_or_delete(org.groups.keys(), data[org.name]['groups'],
|
||||
|
@ -41,7 +41,8 @@ import ./make-test.nix {
|
||||
for my $client ($client1, $client2) {
|
||||
$client->nest("initialize client for user $user", sub {
|
||||
$client->succeed(
|
||||
su $user, "task rc.confirmation=no config confirmation no"
|
||||
(su $user, "rm -rf /home/$user/.task"),
|
||||
(su $user, "task rc.confirmation=no config confirmation no")
|
||||
);
|
||||
|
||||
my $exportinfo = $server->succeed(
|
||||
@ -156,5 +157,12 @@ import ./make-test.nix {
|
||||
$client1->succeed(su "bar", "task add destroy even more >&2");
|
||||
$client1->fail(su "bar", "task sync >&2");
|
||||
};
|
||||
|
||||
readdImperativeUser;
|
||||
|
||||
subtest "check whether declarative config overrides user bar", sub {
|
||||
restartServer;
|
||||
testSync "bar";
|
||||
};
|
||||
'';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user