Compare commits
No commits in common. "369bdc18387bdc9706cc8e211fbff1f1e643e7ef" and "5ba1a70ff2c804d2f588b14fb50dae209892ba21" have entirely different histories.
369bdc1838
...
5ba1a70ff2
6 changed files with 55 additions and 122 deletions
100
manage.py
100
manage.py
|
@ -14,14 +14,15 @@ def backupProj(project):
|
||||||
|
|
||||||
|
|
||||||
def getImageId (image):
|
def getImageId (image):
|
||||||
return runPodman("image", ["inspect", "--format", "{{.Id}}", image]).stdout.strip()
|
return subprocess.run(["podman", "image", "inspect", "--format", "{{.Id}}", image], capture_output=True, text=True).stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
def getUid(service):
|
def getUid(service):
|
||||||
if service in env['users'].keys():
|
if service in env['users'].keys():
|
||||||
return env['users'][service] + env['uid_shift']
|
user = env['users'][service] + env['uid_shift']
|
||||||
else:
|
else:
|
||||||
return env['podman_uid']
|
user = 1000
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
def pullProj(project):
|
def pullProj(project):
|
||||||
|
@ -33,7 +34,7 @@ def pullProj(project):
|
||||||
pulledImages = []
|
pulledImages = []
|
||||||
for image in images:
|
for image in images:
|
||||||
currentId = getImageId(image)
|
currentId = getImageId(image)
|
||||||
runPodman("pull", image)
|
subprocess.run(["podman", "pull", image])
|
||||||
pulledId = getImageId(image)
|
pulledId = getImageId(image)
|
||||||
if currentId != pulledId:
|
if currentId != pulledId:
|
||||||
pulledImages += image
|
pulledImages += image
|
||||||
|
@ -56,50 +57,17 @@ def renderFile(templateFile):
|
||||||
outputFile.close()
|
outputFile.close()
|
||||||
|
|
||||||
|
|
||||||
def runPodman(cmd, args):
|
|
||||||
if isinstance(args, str):
|
|
||||||
args = args.split(' ')
|
|
||||||
|
|
||||||
if cmd == 'compose':
|
|
||||||
runArgs = ["podman-compose"] + args
|
|
||||||
else:
|
|
||||||
runArgs = ["podman", cmd] + args
|
|
||||||
|
|
||||||
if env['rootless']:
|
|
||||||
return subprocess.run(runArgs, capture_output=True, text=True)
|
|
||||||
else:
|
|
||||||
return runSudo(runArgs)
|
|
||||||
|
|
||||||
|
|
||||||
def runSudo(args):
|
|
||||||
if isinstance(args, str):
|
|
||||||
args = args.split(' ')
|
|
||||||
|
|
||||||
child = subprocess.Popen(["sudo"] + args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
||||||
|
|
||||||
if re.search('^\\[sudo\\] password for .+', child.stdout.read().strip()):
|
|
||||||
child.communicate(input=input().encode())[0]
|
|
||||||
|
|
||||||
child.wait()
|
|
||||||
|
|
||||||
stderr = child.stderr.read().strip()
|
|
||||||
if stderr != '':
|
|
||||||
print(stderr, file=sys.stderr)
|
|
||||||
|
|
||||||
return child
|
|
||||||
|
|
||||||
|
|
||||||
def setCertPerms(service):
|
def setCertPerms(service):
|
||||||
dirs = ["/etc/letsencrypt", "/etc/letsencrypt/live", "/etc/letsencrypt/archive"]
|
for path in ["/etc/letsencrypt", "/etc/letsencrypt/live", "/etc/letsencrypt/archive"]:
|
||||||
|
setOwner(path, 0, 0)
|
||||||
|
setPerms(path, 751)
|
||||||
|
|
||||||
pkeyFile = env['certs'][service]['pkey']
|
pkeyFile = env['certs'][service]['pkey']
|
||||||
|
|
||||||
domain_dir = re.search('.+(?=\\/.+$)', pkeyFile).group(0)
|
domain_dir = re.search('.+(?=\\/.+$)', pkeyFile).group(0)
|
||||||
dirs += [domain_dir, re.sub('live', 'archive', domain_dir)]
|
for path in [domain_dir, re.sub('live', 'archive', domain_dir)]:
|
||||||
|
setOwner(path, env['host_uid'], getUid(service))
|
||||||
for path in dirs:
|
setPerms(path, 550)
|
||||||
setOwner(path, 0, env['podman_uid'])
|
|
||||||
setPerms(path, 711)
|
|
||||||
|
|
||||||
setOwner(pkeyFile, 0, getUid(service))
|
setOwner(pkeyFile, 0, getUid(service))
|
||||||
setPerms(pkeyFile, 640)
|
setPerms(pkeyFile, 640)
|
||||||
|
@ -109,8 +77,8 @@ def setNftables():
|
||||||
renderFile("nftables.conf.mako")
|
renderFile("nftables.conf.mako")
|
||||||
if not filecmp.cmp("nftables.conf.rendered", "/etc/nftables.conf"):
|
if not filecmp.cmp("nftables.conf.rendered", "/etc/nftables.conf"):
|
||||||
print("nftables.conf changed, copying new version.")
|
print("nftables.conf changed, copying new version.")
|
||||||
runSudo(["cp", "nftables.conf.rendered", "/etc/nftables.conf"])
|
sudoRun(["cp", "nftables.conf.rendered", "/etc/nftables.conf"])
|
||||||
runSudo(["systemctl", "restart", "nftables"])
|
sudoRun(["systemctl", "restart", "nftables"])
|
||||||
else:
|
else:
|
||||||
print("nftables.conf unchanged.")
|
print("nftables.conf unchanged.")
|
||||||
|
|
||||||
|
@ -124,7 +92,7 @@ def setOwner(path, uid=None, gid=None):
|
||||||
|
|
||||||
if stat.st_uid != uid or stat.st_gid != gid:
|
if stat.st_uid != uid or stat.st_gid != gid:
|
||||||
print(f"Changing ownership of {path} to {uid}:{gid} from {stat.st_uid}:{stat.st_gid}.")
|
print(f"Changing ownership of {path} to {uid}:{gid} from {stat.st_uid}:{stat.st_gid}.")
|
||||||
runSudo(["chown", f"{uid}:{gid}", path])
|
sudoRun(["chown", f"{uid}:{gid}", path])
|
||||||
else:
|
else:
|
||||||
print(f"Ownership of {path} already set to {uid}:{gid}.")
|
print(f"Ownership of {path} already set to {uid}:{gid}.")
|
||||||
|
|
||||||
|
@ -135,10 +103,10 @@ def setPerms(path, mode):
|
||||||
curMode = oct(stat.st_mode)[-3:]
|
curMode = oct(stat.st_mode)[-3:]
|
||||||
if mode != curMode:
|
if mode != curMode:
|
||||||
print(f"Changing permissions of {path} to {mode} from {curMode}.")
|
print(f"Changing permissions of {path} to {mode} from {curMode}.")
|
||||||
if stat.st_uid == os.getuid():
|
if stat.st_uid == env['host_uid']:
|
||||||
subprocess.run(["chmod", mode, path])
|
subprocess.run(["chmod", mode, path])
|
||||||
else:
|
else:
|
||||||
runSudo(["chmod", mode, path])
|
subprocess.run(["sudo", "chmod", mode, path])
|
||||||
else:
|
else:
|
||||||
print(f"Permissions of {path} already set to {mode}.")
|
print(f"Permissions of {path} already set to {mode}.")
|
||||||
|
|
||||||
|
@ -148,15 +116,6 @@ def setupProj(project):
|
||||||
|
|
||||||
backupProj(project)
|
backupProj(project)
|
||||||
|
|
||||||
if project == 'diun':
|
|
||||||
if not os.path.isfile(env['socket']):
|
|
||||||
if env['rootless']:
|
|
||||||
subprocess.run(["systemctl", "--user", "restart", "podman.socket"])
|
|
||||||
else:
|
|
||||||
runSudo("systemctl restart podman.socket")
|
|
||||||
setPerms(env['socket'], 660)
|
|
||||||
setOwner(env['socket'], env['podman_uid'], getUid('diun'))
|
|
||||||
|
|
||||||
if project in env['certs'].keys():
|
if project in env['certs'].keys():
|
||||||
setCertPerms(project)
|
setCertPerms(project)
|
||||||
|
|
||||||
|
@ -164,18 +123,22 @@ def setupProj(project):
|
||||||
renderFile(templateFile)
|
renderFile(templateFile)
|
||||||
renderedFilename = re.sub('\\.mako$', '.rendered', templateFile)
|
renderedFilename = re.sub('\\.mako$', '.rendered', templateFile)
|
||||||
setPerms(renderedFilename, 640)
|
setPerms(renderedFilename, 640)
|
||||||
setOwner(renderedFilename, os.getuid(), getUid(project))
|
setOwner(renderedFilename, env['host_uid'], getUid(project))
|
||||||
|
|
||||||
upProj(project)
|
upProj(project)
|
||||||
|
|
||||||
|
|
||||||
def upProj(project):
|
def sudoRun(args):
|
||||||
if runPodman("container", ["exists", project]).returncode == 0:
|
child = subprocess.Popen(["sudo"] + args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||||
print(f"Tearing down stack for project {project}.")
|
if re.search('^\\[sudo\\] password for .+', child.stdout.read().strip()):
|
||||||
runPodman("compose", ["-f", f"projects/{project}/compose.yaml.rendered", "down"])
|
child.communicate(input=input().encode())[0]
|
||||||
|
|
||||||
|
|
||||||
|
def upProj(project):
|
||||||
print(f"Creating & starting stack for project {project}.")
|
print(f"Creating & starting stack for project {project}.")
|
||||||
runPodman("compose", ["-f", f"projects/{project}/compose.yaml.rendered", "up", "-d"])
|
if subprocess.run(["podman", "container", "exists", project]).returncode == 0:
|
||||||
|
subprocess.run(["podman-compose", "-f", f"projects/{project}/compose.yaml.rendered", "down"])
|
||||||
|
subprocess.run(["podman-compose", "-f", f"projects/{project}/compose.yaml.rendered", "up", "-d"])
|
||||||
|
|
||||||
|
|
||||||
def updateProj(project):
|
def updateProj(project):
|
||||||
|
@ -197,14 +160,13 @@ def main():
|
||||||
|
|
||||||
with open(envFile, 'r') as envfile, open(secretsFile, 'r') as secretsfile:
|
with open(envFile, 'r') as envfile, open(secretsFile, 'r') as secretsfile:
|
||||||
global env, secrets
|
global env, secrets
|
||||||
env = yaml.safe_load(Template(filename=envFile).render())
|
env = yaml.safe_load(envfile)
|
||||||
|
env = yaml.safe_load(Template(filename=envFile).render(env=env))
|
||||||
secrets = yaml.safe_load(secretsfile)
|
secrets = yaml.safe_load(secretsfile)
|
||||||
|
|
||||||
setOwner(secretsFile, os.getuid(), os.getgid())
|
setOwner(secretsFile, env['host_uid'], env['host_uid'])
|
||||||
setPerms(secretsFile, 600)
|
setPerms(secretsFile, 600)
|
||||||
|
|
||||||
print("\nUsing socket " + env['socket'] + ".")
|
|
||||||
|
|
||||||
print("\nChoose action:")
|
print("\nChoose action:")
|
||||||
print("[1/S] Setup project")
|
print("[1/S] Setup project")
|
||||||
print("[2/U] Update project")
|
print("[2/U] Update project")
|
||||||
|
|
|
@ -2,6 +2,7 @@ services:
|
||||||
coturn:
|
coturn:
|
||||||
container_name: coturn
|
container_name: coturn
|
||||||
image: docker.io/coturn/coturn:4-alpine
|
image: docker.io/coturn/coturn:4-alpine
|
||||||
|
network_mode: pasta
|
||||||
restart: always
|
restart: always
|
||||||
user: ${env['users']['coturn']}:${env['users']['coturn']}
|
user: ${env['users']['coturn']}:${env['users']['coturn']}
|
||||||
ports:
|
ports:
|
||||||
|
@ -17,4 +18,3 @@ services:
|
||||||
- ${env['certs']['coturn']['cert']}:/etc/coturn/cert.pem:ro
|
- ${env['certs']['coturn']['cert']}:/etc/coturn/cert.pem:ro
|
||||||
- ${env['certs']['coturn']['pkey']}:/etc/coturn/pkey.pem:ro
|
- ${env['certs']['coturn']['pkey']}:/etc/coturn/pkey.pem:ro
|
||||||
|
|
||||||
${env['networks_attr']}
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ services:
|
||||||
diun:
|
diun:
|
||||||
container_name: diun
|
container_name: diun
|
||||||
image: docker.io/crazymax/diun:4
|
image: docker.io/crazymax/diun:4
|
||||||
|
network_mode: pasta
|
||||||
restart: always
|
restart: always
|
||||||
user: ${env['users']['diun']}:${env['users']['diun']}
|
|
||||||
command: serve
|
command: serve
|
||||||
env_file: .env.rendered
|
env_file: .env.rendered
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -11,7 +11,5 @@ services:
|
||||||
- ./images.yml:/etc/diun/images.yml:ro
|
- ./images.yml:/etc/diun/images.yml:ro
|
||||||
- data:/data
|
- data:/data
|
||||||
|
|
||||||
${env['networks_attr']}
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
data:
|
data:
|
||||||
|
|
|
@ -2,6 +2,7 @@ services:
|
||||||
homepage:
|
homepage:
|
||||||
container_name: homepage
|
container_name: homepage
|
||||||
image: git.ahur.ac/viyurz/homepage:latest
|
image: git.ahur.ac/viyurz/homepage:latest
|
||||||
|
network_mode: pasta
|
||||||
restart: always
|
restart: always
|
||||||
user: ${env['users']['homepage']}:${env['users']['homepage']}
|
user: ${env['users']['homepage']}:${env['users']['homepage']}
|
||||||
ports:
|
ports:
|
||||||
|
|
40
pyenv.yml
40
pyenv.yml
|
@ -1,23 +1,10 @@
|
||||||
domain: viyurz.fr
|
domain: viyurz.fr
|
||||||
timezone: "Europe/Paris"
|
timezone: "Europe/Paris"
|
||||||
|
host_uid: 1000
|
||||||
|
socket: "/run/user/${env['host_uid']}/podman/podman.sock"
|
||||||
|
|
||||||
<%!
|
# UID shift for mapping between host & containers
|
||||||
import os, subprocess
|
uid_shift: 99999
|
||||||
|
|
||||||
uid = os.getuid()
|
|
||||||
rootless = os.path.exists(f"/run/user/{uid}/podman/podman.sock")
|
|
||||||
%>
|
|
||||||
% if rootless:
|
|
||||||
rootless: true
|
|
||||||
podman_uid: ${uid}
|
|
||||||
uid_shift: ${int(subprocess.run(['sh', '-c', "grep " + os.getlogin() + " /etc/subuid | cut -d ':' -f 2"], capture_output=True, text=True).stdout.strip()) - 1}
|
|
||||||
socket: "/run/user/${uid}/podman/podman.sock"
|
|
||||||
% else:
|
|
||||||
rootless: false
|
|
||||||
podman_uid: 0
|
|
||||||
uid_shift: 0
|
|
||||||
socket: "/run/podman/podman.sock"
|
|
||||||
% endif
|
|
||||||
|
|
||||||
|
|
||||||
# cifs_credentials is undefined when we run the backup playbook
|
# cifs_credentials is undefined when we run the backup playbook
|
||||||
|
@ -56,23 +43,17 @@ cifs_mounts:
|
||||||
dir_mode: 750
|
dir_mode: 750
|
||||||
|
|
||||||
|
|
||||||
borg_repodir: "{env['cifs_mounts']['backups']['path']}/borg"
|
borg_repodir: "${env['cifs_mounts']['backups']['path']}/borg"
|
||||||
borg_passphrase_file: /etc/borg-passphrase.txt
|
borg_passphrase_file: /etc/borg-passphrase.txt
|
||||||
|
|
||||||
|
|
||||||
certs:
|
certs:
|
||||||
coturn:
|
coturn:
|
||||||
cert: "/etc/letsencrypt/live/turn.viyurz.fr/fullchain.pem"
|
cert: "/etc/letsencrypt/live/turn.${env['domain']}/fullchain.pem"
|
||||||
pkey: "/etc/letsencrypt/live/turn.viyurz.fr/privkey.pem"
|
pkey: "/etc/letsencrypt/live/turn.${env['domain']}/privkey.pem"
|
||||||
mailserver:
|
mailserver:
|
||||||
cert: "/etc/letsencrypt/live/mail.viyurz.fr/fullchain.pem"
|
cert: "/etc/letsencrypt/live/mail.${env['domain']}/fullchain.pem"
|
||||||
pkey: "/etc/letsencrypt/live/mail.viyurz.fr/privkey.pem"
|
pkey: "/etc/letsencrypt/live/mail.${env['domain']}/privkey.pem"
|
||||||
|
|
||||||
|
|
||||||
networks_attr: |
|
|
||||||
networks:
|
|
||||||
default:
|
|
||||||
enable_ipv6: true
|
|
||||||
|
|
||||||
|
|
||||||
# Ports exposed to host
|
# Ports exposed to host
|
||||||
|
@ -108,7 +89,6 @@ ports:
|
||||||
# UID in containers
|
# UID in containers
|
||||||
users:
|
users:
|
||||||
coturn: 666
|
coturn: 666
|
||||||
diun: 1011
|
|
||||||
etebase: 373
|
etebase: 373
|
||||||
fireshare: 1007
|
fireshare: 1007
|
||||||
hedgedoc: 1004
|
hedgedoc: 1004
|
||||||
|
@ -138,6 +118,6 @@ volumes:
|
||||||
stump_configdir: /mnt/stump/config
|
stump_configdir: /mnt/stump/config
|
||||||
stump_datadir: /mnt/stump/data
|
stump_datadir: /mnt/stump/data
|
||||||
synapse_datadir: /mnt/synapsedata
|
synapse_datadir: /mnt/synapsedata
|
||||||
syncthing_datadir: "{env['cifs_mounts']['syncthing']['path']}"
|
syncthing_datadir: "${env['cifs_mounts']['syncthing']['path']}"
|
||||||
uptime_kuma_datadir: /mnt/uptimekumadata
|
uptime_kuma_datadir: /mnt/uptimekumadata
|
||||||
vaultwarden_datadir: /mnt/vwdata
|
vaultwarden_datadir: /mnt/vwdata
|
||||||
|
|
30
setup.sh
30
setup.sh
|
@ -6,27 +6,15 @@ if [[ $(whoami) == "root" ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
while ! [[ "$podman_mode" =~ ^(rootful|rootless)$ ]]; do
|
sudo apt install -y aardvark-dns dbus-user-session nftables passt podman podman-compose python3-mako uidmap
|
||||||
read -rp "Rootful or rootless Podman? " podman_mode
|
|
||||||
|
|
||||||
|
for unit in podman.service podman.socket podman-auto-update.service podman-auto-update.timer podman-clean-transient.service podman-restart.service; do
|
||||||
|
sudo systemctl disable --now "$unit"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
declare -a podman_units=(podman.service podman.socket podman-auto-update.service podman-auto-update.timer podman-clean-transient.service podman-restart.service)
|
sudo loginctl enable-linger $USER
|
||||||
|
|
||||||
|
|
||||||
if [[ "$podman_mode" == "rootless" ]]; then
|
|
||||||
sudo apt install -y aardvark-dns dbus-user-session nftables passt podman podman-compose python3-mako uidmap
|
|
||||||
|
|
||||||
sudo loginctl enable-linger "$USER"
|
|
||||||
|
|
||||||
sudo systemctl disable --now "${podman_units[@]}"
|
|
||||||
systemctl --user enable --now "${podman_units[@]}"
|
|
||||||
else
|
|
||||||
sudo apt install -y aardvark-dns nftables podman podman-compose python3-mako
|
|
||||||
|
|
||||||
systemctl --user disable --now "${podman_units[@]}"
|
|
||||||
sudo systemctl enable --now "${podman_units[@]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
declare -A sysctl_vars=(
|
declare -A sysctl_vars=(
|
||||||
|
@ -39,8 +27,12 @@ echo -n "" | sudo tee /etc/sysctl.d/podman.conf
|
||||||
for key in "${!sysctl_vars[@]}"; do
|
for key in "${!sysctl_vars[@]}"; do
|
||||||
value="${sysctl_vars[$key]}"
|
value="${sysctl_vars[$key]}"
|
||||||
echo "$key = $value" | sudo tee -a /etc/sysctl.d/podman.conf
|
echo "$key = $value" | sudo tee -a /etc/sysctl.d/podman.conf
|
||||||
|
sudo sysctl -p
|
||||||
done
|
done
|
||||||
sudo sysctl -p
|
|
||||||
|
|
||||||
|
|
||||||
|
for unit in podman.service podman.socket podman-restart.service; do
|
||||||
|
systemctl --user enable --now "$unit"
|
||||||
|
done
|
||||||
|
|
||||||
sudo systemctl enable --now nftables
|
sudo systemctl enable --now nftables
|
||||||
|
|
Loading…
Reference in a new issue