about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authoraszlig <aszlig@redmoonstudios.org>2016-04-12 03:42:13 +0200
committeraszlig <aszlig@redmoonstudios.org>2016-04-12 03:42:13 +0200
commita41b109bc10e66824af5e1f150cb741f9f9399c2 (patch)
tree0cee8f306bd1f8b2a6ad285e9c45c63dec09fb12 /nixos
parent9586795ef27ac4d406c10c12f92fc735b5f4ff24 (diff)
downloadnixlib-a41b109bc10e66824af5e1f150cb741f9f9399c2.tar
nixlib-a41b109bc10e66824af5e1f150cb741f9f9399c2.tar.gz
nixlib-a41b109bc10e66824af5e1f150cb741f9f9399c2.tar.bz2
nixlib-a41b109bc10e66824af5e1f150cb741f9f9399c2.tar.lz
nixlib-a41b109bc10e66824af5e1f150cb741f9f9399c2.tar.xz
nixlib-a41b109bc10e66824af5e1f150cb741f9f9399c2.tar.zst
nixlib-a41b109bc10e66824af5e1f150cb741f9f9399c2.zip
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>
Diffstat (limited to 'nixos')
-rw-r--r--nixos/modules/services/misc/taskserver/helper-tool.py69
-rw-r--r--nixos/tests/taskserver.nix10
2 files changed, 70 insertions, 9 deletions
diff --git a/nixos/modules/services/misc/taskserver/helper-tool.py b/nixos/modules/services/misc/taskserver/helper-tool.py
index 30dcfe0a7a25..512aaa4ab9f8 100644
--- a/nixos/modules/services/misc/taskserver/helper-tool.py
+++ b/nixos/modules/services/misc/taskserver/helper-tool.py
@@ -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'],
diff --git a/nixos/tests/taskserver.nix b/nixos/tests/taskserver.nix
index 5d2e030a8f6d..79a7703f037e 100644
--- a/nixos/tests/taskserver.nix
+++ b/nixos/tests/taskserver.nix
@@ -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";
+    };
   '';
 }