Implement home exam server.
This commit is contained in:
parent
147fddc772
commit
f4f0795e80
10 changed files with 248 additions and 0 deletions
17
fvs-homex-server.yml
Normal file
17
fvs-homex-server.yml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
## This playbook deploys a FvS homex server machine.
|
||||||
|
---
|
||||||
|
- name: apply configuration to the homex server
|
||||||
|
hosts: all
|
||||||
|
remote_user: ansible
|
||||||
|
become: yes
|
||||||
|
vars:
|
||||||
|
extra_pkgs:
|
||||||
|
- vim
|
||||||
|
- systemd-journal-remote
|
||||||
|
- python3-ldap
|
||||||
|
extra_pkgs_bpo: [ ]
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- up2date_debian
|
||||||
|
- fvs-sssd
|
||||||
|
- exam_homes
|
23
roles/exam_homes/files/archive-homes
Executable file
23
roles/exam_homes/files/archive-homes
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
#
|
||||||
|
# Backup and remove all student home directories.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
HDIRS='/home/'
|
||||||
|
DIRS=()
|
||||||
|
|
||||||
|
for DIR in $(find $HDIRS -maxdepth 1 -mindepth 1 -type d) ; do
|
||||||
|
H="$(basename $DIR)"
|
||||||
|
if [[ "$H" =~ ^L_ ]] || [[ "$H" =~ ansible ]] ; then
|
||||||
|
echo "Skipping home of '$H'."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
DIRS+=("$DIR")
|
||||||
|
done
|
||||||
|
[[ "${#DIRS[@]}" -eq 0 ]] && exit 0
|
||||||
|
|
||||||
|
tar czf "/var/backups/homes_$(date -I).tar.gz" -C "$HDIRS" \
|
||||||
|
-P --transform="s%$HDIRS%%" "${DIRS[@]}"
|
||||||
|
rm -rf "${DIRS[@]}"
|
||||||
|
echo "Archived and removed: ${DIRS[@]}"
|
6
roles/exam_homes/files/archive-homes.service
Normal file
6
roles/exam_homes/files/archive-homes.service
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Archive students' home directories
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/local/sbin/archive-homes
|
11
roles/exam_homes/files/archive-homes.timer
Normal file
11
roles/exam_homes/files/archive-homes.timer
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Run archive script every night
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=daily
|
||||||
|
Persistent=true
|
||||||
|
AccuracySec=3h
|
||||||
|
RandomizedDelaySec=3h
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
26
roles/exam_homes/files/copy2students
Executable file
26
roles/exam_homes/files/copy2students
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
#
|
||||||
|
# Copy content to all student home download directories.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
if [[ -z $@ ]] ; then
|
||||||
|
echo "Argument missing!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
HDIRS='/home/'
|
||||||
|
DIRS=()
|
||||||
|
|
||||||
|
for DIR in $(find $HDIRS -maxdepth 1 -mindepth 1 -type d) ; do
|
||||||
|
H="$(basename $DIR)"
|
||||||
|
if [[ "$H" =~ ^L_ ]] || [[ "$H" =~ ansible ]] ; then
|
||||||
|
echo "Skipping home of '$H'."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
DIRS+=("$DIR")
|
||||||
|
done
|
||||||
|
[[ "${#DIRS[@]}" -eq 0 ]] && exit 0
|
||||||
|
|
||||||
|
for DIR in "${DIRS[@]}" ; do
|
||||||
|
cp -va $@ "$DIR/Downloads/"
|
||||||
|
done
|
75
roles/exam_homes/files/examode.py
Executable file
75
roles/exam_homes/files/examode.py
Executable file
|
@ -0,0 +1,75 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import ldap
|
||||||
|
from os import scandir
|
||||||
|
|
||||||
|
HOME = '/home'
|
||||||
|
BASE = 'ou=schueler,ou=Benutzer,ou=fvs,ou=SCHULEN,o=ml3'
|
||||||
|
#BASE = 'ou=Benutzer,ou=fvs,ou=SCHULEN,o=ml3'
|
||||||
|
LDAP = 'ldap://ldap.steinbeisschule-reutlingen.de'
|
||||||
|
|
||||||
|
def fetch_ou(uid):
|
||||||
|
l = ldap.initialize(LDAP)
|
||||||
|
f = '(uid=' + uid + ')'
|
||||||
|
try:
|
||||||
|
return l.search_s(BASE,ldap.SCOPE_SUBTREE,f,['ou'])[0][1]['ou'][0].decode('utf-8')
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def fetch_uids(crs):
|
||||||
|
uids = []
|
||||||
|
l = ldap.initialize(LDAP)
|
||||||
|
# if 'Abgang' in crs:
|
||||||
|
# b = 'ou=Abgang,' + BASE
|
||||||
|
# else:
|
||||||
|
# b = 'ou=' + crs + ',' + BASE
|
||||||
|
b = BASE
|
||||||
|
r = l.search_s(b,ldap.SCOPE_SUBTREE,'(ou=' + crs + ')',['uid'])
|
||||||
|
for dn,entry in r:
|
||||||
|
if entry != {}:
|
||||||
|
uids.append(entry['uid'][0].decode('utf-8'))
|
||||||
|
return uids
|
||||||
|
|
||||||
|
def assign_course(user, crs_uids, home):
|
||||||
|
c = fetch_ou(user)
|
||||||
|
print('Needed to fetch new course', c, 'for', user)
|
||||||
|
if c:
|
||||||
|
crs_uids[c] = fetch_uids(c)
|
||||||
|
home[user] = c
|
||||||
|
else:
|
||||||
|
print('No course for', user , 'found!')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
home = {}
|
||||||
|
with scandir(HOME) as it:
|
||||||
|
for entry in it:
|
||||||
|
if entry.is_dir() and entry.name != 'lost+found':
|
||||||
|
home[entry.name] = ''
|
||||||
|
|
||||||
|
crs_uids = {}
|
||||||
|
for user in home:
|
||||||
|
if crs_uids == {}:
|
||||||
|
assign_course(user, crs_uids, home)
|
||||||
|
continue
|
||||||
|
for k in crs_uids.keys():
|
||||||
|
if user in crs_uids[k]:
|
||||||
|
home[user] = k
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
assign_course(user, crs_uids, home)
|
||||||
|
|
||||||
|
for usr in home:
|
||||||
|
print(usr, home[usr])
|
||||||
|
|
||||||
|
|
||||||
|
for crs in crs_uids.keys():
|
||||||
|
print(usr, home[usr])
|
||||||
|
|
||||||
|
for k, v in sorted(crs_uids.items()):
|
||||||
|
print(k, sorted(v))
|
||||||
|
for item in sorted(v):
|
||||||
|
try:
|
||||||
|
print(item, home[item])
|
||||||
|
except:
|
||||||
|
print('No home for', item, 'found.')
|
23
roles/exam_homes/files/fetchexam
Executable file
23
roles/exam_homes/files/fetchexam
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
#
|
||||||
|
# Backup and remove all student home directories.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
HDIRS='/home/'
|
||||||
|
DIRS=()
|
||||||
|
|
||||||
|
for DIR in $(find $HDIRS -maxdepth 1 -mindepth 1 -type d) ; do
|
||||||
|
H="$(basename $DIR)"
|
||||||
|
if [[ "$H" =~ ^L_ ]] || [[ "$H" =~ ansible ]] ; then
|
||||||
|
echo "Skipping home of '$H'."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
DIRS+=("$DIR")
|
||||||
|
done
|
||||||
|
[[ "${#DIRS[@]}" -eq 0 ]] && exit 0
|
||||||
|
|
||||||
|
AR="homes_$(date -I).tar.gz"
|
||||||
|
tar czf "$AR" -C "$HDIRS" --exclude='.[^/]*' \
|
||||||
|
-P --transform="s%$HDIRS%%" "${DIRS[@]}"
|
||||||
|
echo "Create archive $AR containing: ${DIRS[@]}"
|
12
roles/exam_homes/files/mkDownloads
Executable file
12
roles/exam_homes/files/mkDownloads
Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
#
|
||||||
|
# Prepare Downloads directory.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
HDIRS='/home/'
|
||||||
|
|
||||||
|
if [[ ! -d "$HDIRS/$PAM_USER/Downloads" ]] && [[ ! "$PAM_USER" =~ ^L_ ]] && \
|
||||||
|
[[ ! "$PAM_USER" =~ ansible ]] ; then
|
||||||
|
mkdir --mode=0777 "$HDIRS/$PAM_USER/Downloads"
|
||||||
|
fi
|
6
roles/exam_homes/handlers/main.yml
Normal file
6
roles/exam_homes/handlers/main.yml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
- name: enable archive-homes.timer
|
||||||
|
systemd:
|
||||||
|
name: archive-homes.timer
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
listen: enable archive-homes.timer
|
49
roles/exam_homes/tasks/main.yml
Normal file
49
roles/exam_homes/tasks/main.yml
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
- name: enable pam_mkhomedir.so and pam_exec.so
|
||||||
|
lineinfile:
|
||||||
|
dest: /etc/pam.d/common-session
|
||||||
|
line: "{{ item }}"
|
||||||
|
insertbefore: "# end of pam-auth-update config"
|
||||||
|
loop:
|
||||||
|
- "session optional pam_mkhomedir.so umask=0022"
|
||||||
|
- "session optional pam_exec.so /usr/local/sbin/mkDownloads"
|
||||||
|
|
||||||
|
- name: deploy mkDownloads script
|
||||||
|
copy:
|
||||||
|
src: mkDownloads
|
||||||
|
dest: /usr/local/sbin/mkDownloads
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
# https://serverfault.com/questions/354615/allow-sftp-but-disallow-ssh
|
||||||
|
- name: only allow sftp for most users
|
||||||
|
blockinfile:
|
||||||
|
dest: /etc/ssh/sshd_config.d/local.conf
|
||||||
|
create: true
|
||||||
|
block: |
|
||||||
|
Match User !L_*,!ansible,*
|
||||||
|
PermitTTY no
|
||||||
|
X11Forwarding no
|
||||||
|
AllowTcpForwarding no
|
||||||
|
AllowAgentForwarding no
|
||||||
|
ForceCommand internal-sftp
|
||||||
|
|
||||||
|
- name: deploy archive home script
|
||||||
|
copy:
|
||||||
|
src: archive-homes
|
||||||
|
dest: /usr/local/sbin/archive-homes
|
||||||
|
mode: 0750
|
||||||
|
|
||||||
|
- name: deploy archive home script service and timer
|
||||||
|
copy:
|
||||||
|
src: "{{ item }}"
|
||||||
|
dest: /etc/systemd/system/{{ item }}
|
||||||
|
mode: 0655
|
||||||
|
loop:
|
||||||
|
- archive-homes.service
|
||||||
|
- archive-homes.timer
|
||||||
|
notify: enable archive-homes.timer
|
||||||
|
|
||||||
|
- name: deploy examode helper
|
||||||
|
copy:
|
||||||
|
src: examode.py
|
||||||
|
dest: /usr/local/bin/examode.py
|
||||||
|
mode: 0755
|
Loading…
Add table
Reference in a new issue