From d945ee08d752ddb5d3b7401bf06bac811d432baf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= <valtri@civ.zcu.cz>
Date: Mon, 26 Feb 2024 14:45:57 +0100
Subject: [PATCH] Enable storage quotas on NFS node

---
 cesnet-central/playbooks/files/xfs-quotas.sh | 138 +++++++++++++++++++
 cesnet-central/playbooks/k8s.yaml            |   7 +
 2 files changed, 145 insertions(+)
 create mode 100755 cesnet-central/playbooks/files/xfs-quotas.sh

diff --git a/cesnet-central/playbooks/files/xfs-quotas.sh b/cesnet-central/playbooks/files/xfs-quotas.sh
new file mode 100755
index 0000000..e0dd517
--- /dev/null
+++ b/cesnet-central/playbooks/files/xfs-quotas.sh
@@ -0,0 +1,138 @@
+#! /bin/sh -e
+#
+# Set the XFS project quotas on specified directories
+#
+# Only directories without projects in /etc/projects and /etc/projid are set,
+# existing project assignments and quotas are not touched.
+#
+# After removing from /etc/projects and /etc/projid, this script will set again
+# the project assignments and quota.
+#
+# Check result:
+#
+# xfs_quota -xc 'report -ph'
+#
+# Check individual file project assignment (replace $DIR by path):
+#
+# xfs_io -c lsproj $DIR
+#
+# Clear project assignment (replace $DIR_OR_ID by project name or ID):
+#
+# xfs_quota -xc "project -C $DIR_OR_ID" /exports
+# vim /etc/projects /etc/projid
+#
+
+PROG="$0"
+SOFT=1024M
+HARD=1152M
+DISK_MOUNTPOINT=/exports
+TARGET_PATH=/exports
+
+usage() {
+	cat << EOF
+$PROG [OPTIONS]
+OPTIONS are:
+  -h,--help
+  -n,--dry-run
+  -i,--include REGEXP
+  -e,--exclude REGEXP
+  -s,--soft-quota QUOTA (default $SOFT)
+  -q,--hard-quota QUOTA (default $HARD)
+EOF
+	return 0
+}
+
+
+TEMP=$(getopt -o 'i:e:s:q:hn' --long 'include:,exclude:,soft-quota:,hard-quota:,help,dry-run' -n 'xfs-quotas.sh' -- "$@") || exit $?
+eval set -- "$TEMP"
+unset TEMP
+
+soft="$SOFT"
+hard="$HARD"
+
+truncate -s 0 /tmp/quota.list
+while true; do
+	case "$1" in
+		-h|--help)
+			usage
+			shift
+			exit 0
+			;;
+		-s|--soft-quota)
+			soft="$2"
+			shift 2
+			continue
+			;;
+		-q|--hard-quota)
+			hard="$2"
+			shift 2
+			continue
+			;;
+		-e|--exclude)
+			grep -v "$2" /tmp/quota.list > /tmp/quota.list2
+			mv /tmp/quota.list2 /tmp/quota.list
+			shift 2
+			continue
+			;;
+		-i|--include)
+			find $TARGET_PATH -mindepth 1 -maxdepth 1 -type d | grep "$2" >> /tmp/quota.list
+			shift 2
+			continue
+			;;
+		-n|--dry-run)
+			dry_run=1
+			shift
+			continue
+			;;
+		--)
+			shift
+			break
+			;;
+		*)
+			usage
+			exit 1
+			;;
+	esac
+done
+
+test -f /etc/projects || touch /etc/projects
+test -f /etc/projid || touch /etc/projid
+
+# all specified directories
+sort /tmp/quota.list | uniq > /tmp/quota.list2
+mv /tmp/quota.list2 /tmp/quota.list
+
+# directories with quota
+cut -d: -f1 /etc/projid 2>/dev/null | sort | uniq > /tmp/quota.xfs.list
+
+lastid=0
+lastid="$( (maxid=0; IFS=:; while read -r dir id; do if test "$id" -gt "$maxid"; then maxid="$id"; fi; done; echo "$maxid") < /etc/projid )"
+cat <<EOF > /tmp/quota-cmd.sh
+#! /bin/sh -e
+cp -p /etc/projects /etc/projects.new
+cp -p /etc/projid /etc/projid.new
+
+EOF
+diff /tmp/quota.list /tmp/quota.xfs.list | grep '^< ' | while read -r _ dir; do
+	lastid=$((lastid+1))
+	id="$lastid"
+	cat <<EOF >> /tmp/quota-cmd.sh
+echo "$id:$dir" >> /etc/projects.new
+echo "$dir:$id" >> /etc/projid.new
+xfs_quota -x -D /etc/projects.new -P /etc/projid.new -c "project -s $dir" $DISK_MOUNTPOINT >/dev/null
+xfs_quota -x  -D /etc/projects.new -P /etc/projid.new -c "limit -p bsoft=$soft bhard=$hard $dir" $DISK_MOUNTPOINT
+
+EOF
+done
+cat <<EOF >>/tmp/quota-cmd.sh
+mv /etc/projects.new /etc/projects
+mv /etc/projid.new /etc/projid
+EOF
+
+if test -z "$dry_run"; then
+	sh -e /tmp/quota-cmd.sh
+else
+	cat /tmp/quota-cmd.sh
+fi
+
+rm -f /tmp/quota-cmd.sh /tmp/quota.list /tmp/quota.list2 /tmp/quota.xfs.list
diff --git a/cesnet-central/playbooks/k8s.yaml b/cesnet-central/playbooks/k8s.yaml
index 3646604..495ba43 100644
--- a/cesnet-central/playbooks/k8s.yaml
+++ b/cesnet-central/playbooks/k8s.yaml
@@ -78,6 +78,13 @@
         dest: /etc/exports
         mode: 0644
       notify: Reload exports
+    - name: Quota script
+      copy:
+        dest: /usr/local/bin/xfs-quotas.sh
+        src: files/xfs-quotas.sh
+        mode: 0755
+        owner: root
+        group: root
     - name: Start NFS service
       service:
         name: nfs-server
-- 
GitLab