mirror of
https://github.com/nextcloud/all-in-one.git
synced 2024-09-20 14:56:08 +08:00
Initial import
This commit is contained in:
commit
2295a33590
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.DS_Store
|
||||||
|
/php/data/containers.json
|
||||||
|
/php/data/configuration.json
|
||||||
|
/php/data/backupsecret.json
|
53
Containers/apache/Caddyfile
Normal file
53
Containers/apache/Caddyfile
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{
|
||||||
|
auto_https disable_redirects
|
||||||
|
|
||||||
|
storage file_system {
|
||||||
|
root /mnt/data/caddy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{$NC_DOMAIN}:443 {
|
||||||
|
|
||||||
|
# Notify Push
|
||||||
|
route /push/* {
|
||||||
|
uri strip_prefix /push
|
||||||
|
reverse_proxy {$NEXTCLOUD_HOST}:7867
|
||||||
|
}
|
||||||
|
|
||||||
|
# Talk
|
||||||
|
route /standalone-signaling/* {
|
||||||
|
uri strip_prefix /standalone-signaling
|
||||||
|
reverse_proxy {$TALK_HOST}:8081
|
||||||
|
}
|
||||||
|
|
||||||
|
# Collabora
|
||||||
|
route /browser/* {
|
||||||
|
reverse_proxy https://{$COLLABORA_HOST}:9980 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route /hosting/* {
|
||||||
|
reverse_proxy https://{$COLLABORA_HOST}:9980 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route /cool/* {
|
||||||
|
reverse_proxy https://{$COLLABORA_HOST}:9980 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Nextcloud
|
||||||
|
route {
|
||||||
|
rewrite /.well-known/carddav /remote.php/dav
|
||||||
|
rewrite /.well-known/caldav /remote.php/dav
|
||||||
|
header Strict-Transport-Security max-age=31536000;
|
||||||
|
reverse_proxy localhost:80
|
||||||
|
}
|
||||||
|
}
|
68
Containers/apache/Dockerfile
Normal file
68
Containers/apache/Dockerfile
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
FROM debian:bullseye
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
RUN mkdir -p /mnt/data; \
|
||||||
|
chown www-data:www-data /mnt/data;
|
||||||
|
|
||||||
|
VOLUME /mnt/data
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
apache2 \
|
||||||
|
supervisor \
|
||||||
|
wget \
|
||||||
|
ca-certificates \
|
||||||
|
openssl \
|
||||||
|
netcat \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN wget "https://caddyserver.com/api/download?os=linux&arch=amd64" -O "/usr/bin/caddy" \
|
||||||
|
&& chmod +x /usr/bin/caddy \
|
||||||
|
&& /usr/bin/caddy version
|
||||||
|
|
||||||
|
RUN a2enmod rewrite \
|
||||||
|
headers \
|
||||||
|
proxy \
|
||||||
|
proxy_fcgi \
|
||||||
|
setenvif \
|
||||||
|
env \
|
||||||
|
mime \
|
||||||
|
dir \
|
||||||
|
authz_core \
|
||||||
|
alias
|
||||||
|
|
||||||
|
COPY nextcloud.conf /etc/apache2/sites-available/
|
||||||
|
|
||||||
|
RUN a2dissite 000-default && \
|
||||||
|
a2dissite default-ssl && \
|
||||||
|
a2ensite nextcloud.conf && \
|
||||||
|
rm -rf /var/www/html/* && \
|
||||||
|
service apache2 restart; \
|
||||||
|
chown www-data:www-data -R /var/log/apache2; \
|
||||||
|
chown -R www-data:www-data /var/run/apache2; \
|
||||||
|
chown -R www-data:www-data /var/www;
|
||||||
|
|
||||||
|
RUN mkdir /var/log/supervisord; \
|
||||||
|
mkdir /var/run/supervisord; \
|
||||||
|
chown www-data:www-data /var/run/supervisord; \
|
||||||
|
chown www-data:www-data /var/log/supervisord;
|
||||||
|
|
||||||
|
COPY Caddyfile /
|
||||||
|
|
||||||
|
COPY start.sh /usr/bin/
|
||||||
|
COPY supervisord.conf /
|
||||||
|
RUN chmod +x /usr/bin/start.sh; \
|
||||||
|
chmod +r /supervisord.conf; \
|
||||||
|
chmod +r /Caddyfile;
|
||||||
|
|
||||||
|
# Give root a random password
|
||||||
|
RUN echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||||
|
|
||||||
|
USER www-data
|
||||||
|
|
||||||
|
ENTRYPOINT ["start.sh"]
|
||||||
|
CMD ["/usr/bin/supervisord", "-c", "/supervisord.conf"]
|
22
Containers/apache/nextcloud.conf
Normal file
22
Containers/apache/nextcloud.conf
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<VirtualHost *:80>
|
||||||
|
# PHP match
|
||||||
|
<FilesMatch "\.php$">
|
||||||
|
SetHandler "proxy:fcgi://nextcloud-aio-nextcloud:9000"
|
||||||
|
</FilesMatch>
|
||||||
|
# Nextcloud dir
|
||||||
|
DocumentRoot /var/www/html/
|
||||||
|
<Directory /var/www/html/>
|
||||||
|
Options Indexes FollowSymLinks
|
||||||
|
Require all granted
|
||||||
|
AllowOverride All
|
||||||
|
Options FollowSymLinks MultiViews
|
||||||
|
Satisfy Any
|
||||||
|
<IfModule mod_dav.c>
|
||||||
|
Dav off
|
||||||
|
</IfModule>
|
||||||
|
</Directory>
|
||||||
|
# Deny access to .ht files
|
||||||
|
<Files ".ht*">
|
||||||
|
Require all denied
|
||||||
|
</Files>
|
||||||
|
</VirtualHost>
|
32
Containers/apache/start.sh
Normal file
32
Containers/apache/start.sh
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -z "$NC_DOMAIN" ]; then
|
||||||
|
echo "NC_DOMAIN and NEXTCLOUD_HOST need to be provided. Exiting!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Need write access to /mnt/data
|
||||||
|
if ! [ -w /mnt/data ]; then
|
||||||
|
echo "Cannot write to /mnt/data"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Only start container if nextcloud is accessible
|
||||||
|
while ! nc -z "$NEXTCLOUD_HOST" 9000; do
|
||||||
|
echo "Waiting for Nextcloud to start..."
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
# Only start container if collabora is started
|
||||||
|
while ! nc -z "$COLLABORA_HOST" 9980; do
|
||||||
|
echo "Waiting for Collabora to start..."
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
# Add caddy path
|
||||||
|
mkdir -p /mnt/data/caddy/
|
||||||
|
|
||||||
|
# Fix apache sturtup
|
||||||
|
rm -f /var/run/apache2/apache2.pid
|
||||||
|
|
||||||
|
exec "$@"
|
23
Containers/apache/supervisord.conf
Normal file
23
Containers/apache/supervisord.conf
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
nodaemon=true
|
||||||
|
logfile=/var/log/supervisord/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord/supervisord.pid
|
||||||
|
childlogdir=/var/log/supervisord/
|
||||||
|
logfile_maxbytes=50MB
|
||||||
|
logfile_backups=10
|
||||||
|
loglevel=error
|
||||||
|
|
||||||
|
[program:apache]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=apachectl -DFOREGROUND
|
||||||
|
|
||||||
|
[program:caddy]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=/usr/bin/caddy run -config /Caddyfile
|
22
Containers/borgbackup/Dockerfile
Normal file
22
Containers/borgbackup/Dockerfile
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
FROM debian:bullseye
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
borgbackup \
|
||||||
|
rsync \
|
||||||
|
fuse \
|
||||||
|
python3-llfuse \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
VOLUME /root
|
||||||
|
|
||||||
|
COPY start.sh /usr/bin/
|
||||||
|
COPY backupscript.sh /
|
||||||
|
RUN chmod +x /usr/bin/start.sh; \
|
||||||
|
chmod +x /backupscript.sh
|
||||||
|
|
||||||
|
USER root
|
||||||
|
ENTRYPOINT ["start.sh"]
|
204
Containers/borgbackup/backupscript.sh
Normal file
204
Containers/borgbackup/backupscript.sh
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
BORG_BACKUP_DIRECTORY="/mnt/borgbackup/borg"
|
||||||
|
|
||||||
|
# Functions
|
||||||
|
get_start_time(){
|
||||||
|
START_TIME=$(date +%s)
|
||||||
|
CURRENT_DATE=$(date --date @"$START_TIME" +"%Y%m%d_%H%M%S")
|
||||||
|
CURRENT_DATE_READABLE=$(date --date @"$START_TIME" +"%d.%m.%Y - %H:%M:%S")
|
||||||
|
}
|
||||||
|
get_expiration_time() {
|
||||||
|
END_TIME=$(date +%s)
|
||||||
|
END_DATE_READABLE=$(date --date @"$END_TIME" +"%d.%m.%Y - %H:%M:%S")
|
||||||
|
DURATION=$((END_TIME-START_TIME))
|
||||||
|
DURATION_SEC=$((DURATION % 60))
|
||||||
|
DURATION_MIN=$(((DURATION / 60) % 60))
|
||||||
|
DURATION_HOUR=$((DURATION / 3600))
|
||||||
|
DURATION_READABLE=$(printf "%02d hours %02d minutes %02d seconds" $DURATION_HOUR $DURATION_MIN $DURATION_SEC)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Export defaults
|
||||||
|
export BORG_PASSPHRASE="$BORG_PASSWORD"
|
||||||
|
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes
|
||||||
|
export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes
|
||||||
|
|
||||||
|
# Test if all volumes aren't empty
|
||||||
|
VOLUME_DIRS="$(find /nextcloud_aio_volumes -mindepth 1 -maxdepth 1 -type d)"
|
||||||
|
mapfile -t VOLUME_DIRS <<< "$VOLUME_DIRS"
|
||||||
|
for directory in "${VOLUME_DIRS[@]}"; do
|
||||||
|
if ! mountpoint -q "$directory"; then
|
||||||
|
echo "$directory is not a mountpoint which is not allowed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if target is mountpoint
|
||||||
|
if ! mountpoint -q /mnt/borgbackup; then
|
||||||
|
echo "/mnt/borgbackup is not a mountpoint which is not allowed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if target is empty
|
||||||
|
if [ "$BORG_MODE" != backup ] && ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||||
|
echo "The repository is empty. cannot perform check or restore."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Break the borg lock if it exists
|
||||||
|
if [ -f "$BORG_BACKUP_DIRECTORY/lock.roster" ]; then
|
||||||
|
echo "Breaking the borg lock..."
|
||||||
|
if ! borg break-lock "$BORG_BACKUP_DIRECTORY"; then
|
||||||
|
echo "Could not break the borg lock!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create lockfile
|
||||||
|
if [ "$BORG_MODE" = backup ] || [ "$BORG_MODE" = restore ]; then
|
||||||
|
touch "/nextcloud_aio_volumes/nextcloud_aio_database_dump/backup-is-running"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do the backup
|
||||||
|
if [ "$BORG_MODE" = backup ]; then
|
||||||
|
|
||||||
|
# Test if important files are present
|
||||||
|
if ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json" ]; then
|
||||||
|
echo "configuration.json not present. Cannot perform the backup!"
|
||||||
|
exit 1
|
||||||
|
elif ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_nextcloud/config/config.php" ]; then
|
||||||
|
echo "config.php is missing cannot perform backup"
|
||||||
|
exit 1
|
||||||
|
elif ! [ -f "/nextcloud_aio_volumes/nextcloud_aio_database_dump/database-dump.sql" ]; then
|
||||||
|
echo "database-dump is missing. cannot perform backup"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test that nothing is empty
|
||||||
|
for directory in "${VOLUME_DIRS[@]}"; do
|
||||||
|
if [ -z "$(ls -A "$directory")" ]; then
|
||||||
|
echo "$directory is empty which is not allowed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Create backup folder
|
||||||
|
mkdir -p "$BORG_BACKUP_DIRECTORY"
|
||||||
|
|
||||||
|
# Initialize the repository if the target is empty
|
||||||
|
if ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||||
|
# Don't initialize if already initialized
|
||||||
|
if [ -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config" ]; then
|
||||||
|
echo "Cannot initialize a new repository as that was already done at least one time."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "initializing repository..."
|
||||||
|
if ! borg init --debug --encryption=repokey-blake2 "$BORG_BACKUP_DIRECTORY"; then
|
||||||
|
echo "Could not initialize borg repository."
|
||||||
|
rm -f "$BORG_BACKUP_DIRECTORY/config"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
borg config "$BORG_BACKUP_DIRECTORY" additional_free_space 2G
|
||||||
|
|
||||||
|
# Fix too large Borg cache
|
||||||
|
# https://borgbackup.readthedocs.io/en/stable/faq.html#the-borg-cache-eats-way-too-much-disk-space-what-can-i-do
|
||||||
|
BORG_ID="$(borg config "$BORG_BACKUP_DIRECTORY" id)"
|
||||||
|
rm -r "/root/.cache/borg/$BORG_ID/chunks.archive.d"
|
||||||
|
touch "/root/.cache/borg/$BORG_ID/chunks.archive.d"
|
||||||
|
|
||||||
|
# Make a backup from the borg config file
|
||||||
|
if ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
|
||||||
|
echo "The borg config file wasn't created. Something is wrong."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
rm -f "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config"
|
||||||
|
if ! cp "$BORG_BACKUP_DIRECTORY/config" "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/borg.config"; then
|
||||||
|
echo "Could not copy config file to second place. Cannot perform backup."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Repository successfully initialized."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Perform backup
|
||||||
|
echo "Performing backup..."
|
||||||
|
|
||||||
|
# Borg options
|
||||||
|
# auto,zstd compression seems to has the best ratio based on:
|
||||||
|
# https://forum.level1techs.com/t/optimal-compression-for-borg-backups/145870/6
|
||||||
|
BORG_OPTS=(--stats --progress --compression "auto,zstd" --exclude-caches --checkpoint-interval 86400)
|
||||||
|
|
||||||
|
# Create the backup
|
||||||
|
echo "Starting the backup..."
|
||||||
|
get_start_time
|
||||||
|
if ! borg create "${BORG_OPTS[@]}" "$BORG_BACKUP_DIRECTORY::$CURRENT_DATE-nextcloud-aio" "/nextcloud_aio_volumes/"; then
|
||||||
|
echo "Deleting the failed backup archive..."
|
||||||
|
borg delete --stats --progress "$BORG_BACKUP_DIRECTORY::$CURRENT_DATE-nextcloud-aio"
|
||||||
|
echo "Backup failed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$CURRENT_DATE,$CURRENT_DATE_READABLE" >> "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
|
||||||
|
chmod +r "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/backup_archives.list"
|
||||||
|
|
||||||
|
# Prune options
|
||||||
|
BORG_PRUNE_OPTS=(--stats --progress --keep-within=7d --keep-weekly=4 --keep-monthly=6 "$BORG_BACKUP_DIRECTORY")
|
||||||
|
|
||||||
|
# Prune archives
|
||||||
|
echo "Pruning the archives..."
|
||||||
|
if ! borg prune --prefix '*_*-nextcloud-aio' "${BORG_PRUNE_OPTS[@]}"; then
|
||||||
|
echo "Failed to prune archives!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Inform user
|
||||||
|
get_expiration_time
|
||||||
|
echo "Backup finished successfully on $END_DATE_READABLE ($DURATION_READABLE)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do the restore
|
||||||
|
if [ "$BORG_MODE" = restore ]; then
|
||||||
|
get_start_time
|
||||||
|
echo "Restoring the last backup..."
|
||||||
|
|
||||||
|
# Perform the restore
|
||||||
|
FIRST_ARCHIVE="$(borg list "$BORG_BACKUP_DIRECTORY" | grep "nextcloud-aio" | awk -F " " '{print $1}' | sort -r | head -1)"
|
||||||
|
mkdir -p /tmp/borg
|
||||||
|
if ! borg mount "$BORG_BACKUP_DIRECTORY::$FIRST_ARCHIVE" /tmp/borg; then
|
||||||
|
echo "Could not mount the backup!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! rsync --stats --archive --human-readable -vv --delete --exclude "nextcloud_aio_mastercontainer/data/backup_archives.list" /tmp/borg/nextcloud_aio_volumes/ /nextcloud_aio_volumes; then
|
||||||
|
echo "Something failed while restoring the boot partition."
|
||||||
|
umount /tmp/borg
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
umount /tmp/borg
|
||||||
|
|
||||||
|
# TODO: reset fetchtimes in configuration.json so that it doesn't get the latest directly...
|
||||||
|
|
||||||
|
# Inform user
|
||||||
|
get_expiration_time
|
||||||
|
echo "Restore finished successfully on $END_DATE_READABLE ($DURATION_READABLE)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do the Backup check
|
||||||
|
if [ "$BORG_MODE" = check ]; then
|
||||||
|
get_start_time
|
||||||
|
echo "Checking the backup integity..."
|
||||||
|
|
||||||
|
# Perform the check
|
||||||
|
if ! borg check --verify-data --progress "$BORG_BACKUP_DIRECTORY"; then
|
||||||
|
echo "Some errors were found while checking the backup integrity!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Inform user
|
||||||
|
get_expiration_time
|
||||||
|
echo "Check finished successfully on $END_DATE_READABLE ($DURATION_READABLE)"
|
||||||
|
exit 0
|
||||||
|
fi
|
31
Containers/borgbackup/start.sh
Normal file
31
Containers/borgbackup/start.sh
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Validate BORG_PASSWORD
|
||||||
|
if [ -z "$BORG_PASSWORD" ]; then
|
||||||
|
echo "BORG_PASSWORD is not allowed to be empty."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export BORG_PASSWORD
|
||||||
|
|
||||||
|
# Validate BORG_MODE
|
||||||
|
if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != restore ] && [ "$BORG_MODE" != check ]; then
|
||||||
|
echo "No correct BORG_MODE mode applied. Valid are 'backup' and 'restore'."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export BORG_MODE
|
||||||
|
|
||||||
|
# Run the backup script
|
||||||
|
if ! bash /backupscript.sh; then
|
||||||
|
FAILED=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove lockfile
|
||||||
|
rm -f "/nextcloud_aio_volumes/nextcloud_aio_database_dump/backup-is-running"
|
||||||
|
|
||||||
|
if [ -n "$FAILED" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
2
Containers/collabora/Dockerfile
Normal file
2
Containers/collabora/Dockerfile
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# From a file located probably somewhere here: https://github.com/CollaboraOnline/online/tree/master/docker
|
||||||
|
FROM collabora/code:latest
|
15
Containers/domaincheck/Dockerfile
Normal file
15
Containers/domaincheck/Dockerfile
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
FROM alpine
|
||||||
|
RUN apk add --update --no-cache lighttpd bash
|
||||||
|
|
||||||
|
RUN adduser -S www-data -G www-data
|
||||||
|
RUN rm -rf /etc/lighttpd/lighttpd.conf
|
||||||
|
COPY lighttpd.conf /etc/lighttpd/lighttpd.conf
|
||||||
|
RUN chmod +r -R /etc/lighttpd && \
|
||||||
|
chown www-data:www-data -R /var/www
|
||||||
|
|
||||||
|
COPY start.sh /
|
||||||
|
RUN chmod +x /start.sh
|
||||||
|
|
||||||
|
USER www-data
|
||||||
|
RUN mkdir -p /var/www/domaincheck/
|
||||||
|
ENTRYPOINT ["/start.sh"]
|
16
Containers/domaincheck/lighttpd.conf
Normal file
16
Containers/domaincheck/lighttpd.conf
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
server.document-root = "/var/www/domaincheck/"
|
||||||
|
|
||||||
|
server.port = 443
|
||||||
|
|
||||||
|
server.username = "www-data"
|
||||||
|
server.groupname = "www-data"
|
||||||
|
|
||||||
|
mimetype.assign = (
|
||||||
|
".html" => "text/html",
|
||||||
|
".txt" => "text/plain",
|
||||||
|
".jpg" => "image/jpeg",
|
||||||
|
".png" => "image/png"
|
||||||
|
)
|
||||||
|
|
||||||
|
static-file.exclude-extensions = ( ".fcgi", ".php", ".rb", "~", ".inc" )
|
||||||
|
index-file.names = ( "index.html" )
|
16
Containers/domaincheck/start.sh
Normal file
16
Containers/domaincheck/start.sh
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -z "$INSTANCE_ID" ]; then
|
||||||
|
echo "You need to provide an instance id."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$INSTANCE_ID" > /var/www/domaincheck/index.html
|
||||||
|
|
||||||
|
# Check config file
|
||||||
|
lighttpd -tt -f /etc/lighttpd/lighttpd.conf
|
||||||
|
|
||||||
|
# Run server
|
||||||
|
lighttpd -D -f /etc/lighttpd/lighttpd.conf
|
||||||
|
|
||||||
|
exec "$@"
|
8
Containers/mastercontainer/.idea/.gitignore
vendored
Normal file
8
Containers/mastercontainer/.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
9
Containers/mastercontainer/.idea/mastercontainer.iml
Normal file
9
Containers/mastercontainer/.idea/mastercontainer.iml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
6
Containers/mastercontainer/.idea/misc.xml
Normal file
6
Containers/mastercontainer/.idea/misc.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
Containers/mastercontainer/.idea/modules.xml
Normal file
8
Containers/mastercontainer/.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/mastercontainer.iml" filepath="$PROJECT_DIR$/.idea/mastercontainer.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
Containers/mastercontainer/.idea/vcs.xml
Normal file
6
Containers/mastercontainer/.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
16
Containers/mastercontainer/Caddyfile
Normal file
16
Containers/mastercontainer/Caddyfile
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
auto_https disable_redirects
|
||||||
|
|
||||||
|
storage file_system {
|
||||||
|
root /mnt/docker-aio-config/caddy/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
https://:8443 {
|
||||||
|
|
||||||
|
reverse_proxy localhost:8000
|
||||||
|
|
||||||
|
tls {
|
||||||
|
on_demand
|
||||||
|
}
|
||||||
|
}
|
88
Containers/mastercontainer/Dockerfile
Normal file
88
Containers/mastercontainer/Dockerfile
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
# From https://github.com/docker-library/php/blob/master/8.0/buster/apache/Dockerfile
|
||||||
|
FROM php:8.0-apache-bullseye
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
# EXPOSE 8080
|
||||||
|
EXPOSE 8443
|
||||||
|
|
||||||
|
RUN mkdir -p /mnt/docker-aio-config/; \
|
||||||
|
chown www-data:www-data /mnt/docker-aio-config;
|
||||||
|
|
||||||
|
VOLUME /mnt/docker-aio-config/
|
||||||
|
|
||||||
|
RUN mkdir -p /var/www/docker-aio; \
|
||||||
|
chown -R www-data:www-data /var/www;
|
||||||
|
|
||||||
|
WORKDIR /var/www/docker-aio
|
||||||
|
|
||||||
|
RUN apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
git \
|
||||||
|
supervisor \
|
||||||
|
openssl \
|
||||||
|
sudo \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN curl "https://caddyserver.com/api/download?os=linux&arch=amd64" -o "/usr/bin/caddy" \
|
||||||
|
&& chmod 0755 /usr/bin/caddy \
|
||||||
|
&& /usr/bin/caddy version
|
||||||
|
|
||||||
|
RUN cd /var/www/docker-aio; \
|
||||||
|
git clone git@github.com:nextcloud/all-in-one.git .; \
|
||||||
|
chown -R www-data:www-data ./; \
|
||||||
|
chmod 770 -R ./
|
||||||
|
|
||||||
|
RUN mkdir -p /etc/apache2/certs && \
|
||||||
|
cd /etc/apache2/certs && \
|
||||||
|
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj "/C=DE/ST=BE/L=Local/O=Dev/CN=nextcloud.local" -keyout ./ssl.key -out ./ssl.crt; \
|
||||||
|
chown www-data:www-data -R /etc/apache2/certs;
|
||||||
|
|
||||||
|
COPY mastercontainer.conf /etc/apache2/sites-available/
|
||||||
|
|
||||||
|
RUN a2enmod rewrite \
|
||||||
|
headers \
|
||||||
|
env \
|
||||||
|
mime \
|
||||||
|
dir \
|
||||||
|
authz_core \
|
||||||
|
proxy \
|
||||||
|
proxy_http \
|
||||||
|
ssl
|
||||||
|
|
||||||
|
RUN rm /etc/apache2/ports.conf; \
|
||||||
|
sed -s -i -e "s/Include ports.conf//" /etc/apache2/apache2.conf; \
|
||||||
|
sed -i "/^Listen /d" /etc/apache2/apache2.conf
|
||||||
|
|
||||||
|
RUN a2dissite 000-default && \
|
||||||
|
a2dissite default-ssl && \
|
||||||
|
a2ensite mastercontainer.conf && \
|
||||||
|
service apache2 restart
|
||||||
|
|
||||||
|
RUN mkdir /var/log/supervisord; \
|
||||||
|
mkdir /var/run/supervisord; \
|
||||||
|
chown www-data:www-data /var/run/supervisord; \
|
||||||
|
chown www-data:www-data /var/log/supervisord;
|
||||||
|
|
||||||
|
RUN mkdir -p /usr/src/php/ext/apcu && curl -fsSL https://pecl.php.net/get/apcu | tar xvz -C "/usr/src/php/ext/apcu" --strip 1 && docker-php-ext-install apcu
|
||||||
|
|
||||||
|
COPY Caddyfile /
|
||||||
|
COPY start.sh /usr/bin/
|
||||||
|
COPY cron.sh /
|
||||||
|
COPY supervisord.conf /
|
||||||
|
RUN chmod +x /usr/bin/start.sh; \
|
||||||
|
chmod +r /supervisord.conf; \
|
||||||
|
chmod +r /Caddyfile; \
|
||||||
|
chmod +x /cron.sh
|
||||||
|
|
||||||
|
# add docker group
|
||||||
|
RUN groupadd -g 998 docker && \
|
||||||
|
usermod -aG docker www-data
|
||||||
|
|
||||||
|
# Give root a random password
|
||||||
|
RUN echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||||
|
|
||||||
|
USER www-data
|
||||||
|
|
||||||
|
ENTRYPOINT ["start.sh"]
|
||||||
|
CMD ["/usr/bin/supervisord", "-c", "/supervisord.conf"]
|
7
Containers/mastercontainer/cron.sh
Normal file
7
Containers/mastercontainer/cron.sh
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
php /var/www/docker-aio/php/src/Cron/cron.php
|
||||||
|
sleep 1d
|
||||||
|
done
|
45
Containers/mastercontainer/mastercontainer.conf
Normal file
45
Containers/mastercontainer/mastercontainer.conf
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
Listen 8000
|
||||||
|
Listen 8080
|
||||||
|
|
||||||
|
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||||
|
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||||
|
|
||||||
|
# Deny access to .ht files
|
||||||
|
<Files ".ht*">
|
||||||
|
Require all denied
|
||||||
|
</Files>
|
||||||
|
|
||||||
|
# Http host
|
||||||
|
<VirtualHost *:8000>
|
||||||
|
# PHP match
|
||||||
|
<FilesMatch "\.php$">
|
||||||
|
SetHandler application/x-httpd-php
|
||||||
|
</FilesMatch>
|
||||||
|
# Master dir
|
||||||
|
DocumentRoot /var/www/docker-aio/php/public/
|
||||||
|
<Directory /var/www/docker-aio/php/public/>
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteRule ^ index.php [QSA,L]
|
||||||
|
Options Indexes FollowSymLinks
|
||||||
|
Require all granted
|
||||||
|
AllowOverride All
|
||||||
|
Options FollowSymLinks MultiViews
|
||||||
|
Satisfy Any
|
||||||
|
<IfModule mod_dav.c>
|
||||||
|
Dav off
|
||||||
|
</IfModule>
|
||||||
|
</Directory>
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
|
# Https host
|
||||||
|
<VirtualHost *:8080>
|
||||||
|
# Proxy to https
|
||||||
|
ProxyPass / http://localhost:8000/
|
||||||
|
ProxyPassReverse / http://localhost:8000/
|
||||||
|
# SSL
|
||||||
|
SSLCertificateKeyFile /etc/apache2/certs/ssl.key
|
||||||
|
SSLCertificateFile /etc/apache2/certs/ssl.crt
|
||||||
|
SSLEngine on
|
||||||
|
SSLProtocol -all +TLSv1.2 +TLSv1.3
|
||||||
|
</VirtualHost>
|
69
Containers/mastercontainer/start.sh
Normal file
69
Containers/mastercontainer/start.sh
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Function to show text in green
|
||||||
|
print_green() {
|
||||||
|
local TEXT="$1"
|
||||||
|
printf "%b%s%b\n" "\e[0;92m" "$TEXT" "\e[0m"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if socket is available and readable
|
||||||
|
if ! [ -a "/var/run/docker.sock" ]; then
|
||||||
|
echo "Docker socket is not available. Cannot continue."
|
||||||
|
exit 1
|
||||||
|
elif ! test -r /var/run/docker.sock; then
|
||||||
|
echo "Docker socket is not readable by the www-data user. Cannot continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if volume is writeable
|
||||||
|
if ! [ -w /mnt/docker-aio-config ]; then
|
||||||
|
echo "/mnt/docker-aio-config is not writeable."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if api version is supported
|
||||||
|
API_VERSION_FILE="$(find ./ -name DockerActionManager.php | head -1)"
|
||||||
|
API_VERSION="$(grep -oP 'const API_VERSION.*\;' "$API_VERSION_FILE" | grep -oP [0-9]+.[0-9]+ | head -1)"
|
||||||
|
API_VERSION_NUMB="$(echo "$API_VERSION" | sed 's/\.//')"
|
||||||
|
LOCAL_API_VERSION_NUMB="$(curl -s --unix-socket /var/run/docker.sock http://"$API_VERSION"/version | sed 's/,/\n/g' | grep ApiVersion | grep -oP [0-9]+.[0-9]+ | head -1 | sed 's/\.//')"
|
||||||
|
if [ -n "$LOCAL_API_VERSION_NUMB" ] && [ -n "$API_VERSION_NUMB" ]; then
|
||||||
|
if ! [ "$LOCAL_API_VERSION_NUMB" -ge "$API_VERSION_NUMB" ]; then
|
||||||
|
echo "Docker v$API_VERSION is not supported by your docker engine. Cannot proceed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "LOCAL_API_VERSION_NUMB or API_VERSION_NUMB are not set correctly. Cannot check if the API version is supported."
|
||||||
|
sleep 10
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Adjust data permissions
|
||||||
|
mkdir -p /mnt/docker-aio-config/data/
|
||||||
|
mkdir -p /mnt/docker-aio-config/session/
|
||||||
|
|
||||||
|
# Adjust caddy permissions
|
||||||
|
mkdir -p /mnt/docker-aio-config/caddy/
|
||||||
|
|
||||||
|
# Adjust certs
|
||||||
|
GENERATED_CERTS="/mnt/docker-aio-config/certs"
|
||||||
|
TMP_CERTS="/etc/apache2/certs"
|
||||||
|
mkdir -p "$GENERATED_CERTS"
|
||||||
|
cd "$GENERATED_CERTS"
|
||||||
|
if ! [ -f ./ssl.crt ] && ! [ -f ./ssl.key ]; then
|
||||||
|
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj "/C=DE/ST=BE/L=Local/O=Dev/CN=nextcloud.local" -keyout ./ssl.key -out ./ssl.crt
|
||||||
|
fi
|
||||||
|
if [ -f ./ssl.crt ] && [ -f ./ssl.key ]; then
|
||||||
|
cd "$TMP_CERTS"
|
||||||
|
rm ./ssl.crt
|
||||||
|
rm ./ssl.key
|
||||||
|
cp "$GENERATED_CERTS/ssl.crt" ./
|
||||||
|
cp "$GENERATED_CERTS/ssl.key" ./
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_green "Initial startup of Nextcloud All In One complete!
|
||||||
|
You should be able to open the Nextcloud AIO Interface now on port 8080 of this server!
|
||||||
|
E.g. https://internal.ip.of.this.server:8080
|
||||||
|
|
||||||
|
If your server has port 80 and 8443 open and you point a domain to your server, you can get a valid certificate automatially by opening the Nextcloud AIO Interface via:
|
||||||
|
https://your-domain-that-points-to-this-server.tld:8443"
|
||||||
|
|
||||||
|
exec "$@"
|
30
Containers/mastercontainer/supervisord.conf
Normal file
30
Containers/mastercontainer/supervisord.conf
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
nodaemon=true
|
||||||
|
logfile=/var/log/supervisord/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord/supervisord.pid
|
||||||
|
childlogdir=/var/log/supervisord/
|
||||||
|
logfile_maxbytes=50MB
|
||||||
|
logfile_backups=10
|
||||||
|
loglevel=error
|
||||||
|
|
||||||
|
[program:apache]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=apache2-foreground
|
||||||
|
|
||||||
|
[program:caddy]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=/usr/bin/caddy run -config /Caddyfile
|
||||||
|
|
||||||
|
[program:cron]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=/cron.sh
|
244
Containers/nextcloud/Dockerfile
Normal file
244
Containers/nextcloud/Dockerfile
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
# From https://github.com/nextcloud/docker/blob/master/22/fpm/Dockerfile
|
||||||
|
FROM php:8.0-fpm-bullseye
|
||||||
|
|
||||||
|
# entrypoint.sh and cron.sh dependencies
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
rsync \
|
||||||
|
bzip2 \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*;
|
||||||
|
|
||||||
|
# install the PHP extensions we need
|
||||||
|
# see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html
|
||||||
|
ENV PHP_MEMORY_LIMIT 512M
|
||||||
|
ENV PHP_UPLOAD_LIMIT 512M
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
savedAptMark="$(apt-mark showmanual)"; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
libcurl4-openssl-dev \
|
||||||
|
libevent-dev \
|
||||||
|
libfreetype6-dev \
|
||||||
|
libicu-dev \
|
||||||
|
libjpeg-dev \
|
||||||
|
libldap2-dev \
|
||||||
|
libmcrypt-dev \
|
||||||
|
libmemcached-dev \
|
||||||
|
libpng-dev \
|
||||||
|
libpq-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
libmagickwand-dev \
|
||||||
|
libzip-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
libgmp-dev \
|
||||||
|
; \
|
||||||
|
\
|
||||||
|
debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \
|
||||||
|
docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \
|
||||||
|
docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \
|
||||||
|
docker-php-ext-install -j "$(nproc)" \
|
||||||
|
bcmath \
|
||||||
|
exif \
|
||||||
|
gd \
|
||||||
|
intl \
|
||||||
|
ldap \
|
||||||
|
opcache \
|
||||||
|
pcntl \
|
||||||
|
pdo_mysql \
|
||||||
|
pdo_pgsql \
|
||||||
|
zip \
|
||||||
|
gmp \
|
||||||
|
; \
|
||||||
|
\
|
||||||
|
# pecl will claim success even if one install fails, so we need to perform each install separately
|
||||||
|
pecl install APCu-5.1.20; \
|
||||||
|
pecl install memcached-3.1.5; \
|
||||||
|
pecl install redis-5.3.4; \
|
||||||
|
pecl install imagick-3.5.1; \
|
||||||
|
\
|
||||||
|
docker-php-ext-enable \
|
||||||
|
apcu \
|
||||||
|
memcached \
|
||||||
|
redis \
|
||||||
|
imagick \
|
||||||
|
; \
|
||||||
|
rm -r /tmp/pear; \
|
||||||
|
\
|
||||||
|
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
|
||||||
|
apt-mark auto '.*' > /dev/null; \
|
||||||
|
apt-mark manual $savedAptMark; \
|
||||||
|
ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \
|
||||||
|
| awk '/=>/ { print $3 }' \
|
||||||
|
| sort -u \
|
||||||
|
| xargs -r dpkg-query -S \
|
||||||
|
| cut -d: -f1 \
|
||||||
|
| sort -u \
|
||||||
|
| xargs -rt apt-mark manual; \
|
||||||
|
\
|
||||||
|
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# set recommended PHP.ini settings
|
||||||
|
# see https://docs.nextcloud.com/server/stable/admin_manual/configuration_server/server_tuning.html#enable-php-opcache
|
||||||
|
RUN { \
|
||||||
|
echo 'opcache.enable=1'; \
|
||||||
|
echo 'opcache.interned_strings_buffer=8'; \
|
||||||
|
echo 'opcache.max_accelerated_files=10000'; \
|
||||||
|
echo 'opcache.memory_consumption=128'; \
|
||||||
|
echo 'opcache.save_comments=1'; \
|
||||||
|
echo 'opcache.revalidate_freq=1'; \
|
||||||
|
} > /usr/local/etc/php/conf.d/opcache-recommended.ini; \
|
||||||
|
\
|
||||||
|
echo 'apc.enable_cli=1' >> /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini; \
|
||||||
|
\
|
||||||
|
{ \
|
||||||
|
echo 'memory_limit=${PHP_MEMORY_LIMIT}'; \
|
||||||
|
echo 'upload_max_filesize=${PHP_UPLOAD_LIMIT}'; \
|
||||||
|
echo 'post_max_size=${PHP_UPLOAD_LIMIT}'; \
|
||||||
|
} > /usr/local/etc/php/conf.d/nextcloud.ini; \
|
||||||
|
\
|
||||||
|
mkdir /var/www/data; \
|
||||||
|
chown -R www-data:root /var/www; \
|
||||||
|
chmod -R g=u /var/www
|
||||||
|
|
||||||
|
VOLUME /var/www/html
|
||||||
|
|
||||||
|
|
||||||
|
ENV NEXTCLOUD_VERSION 22.2.3
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
fetchDeps=" \
|
||||||
|
gnupg \
|
||||||
|
dirmngr \
|
||||||
|
"; \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends $fetchDeps; \
|
||||||
|
\
|
||||||
|
curl -fsSL -o nextcloud.tar.bz2 \
|
||||||
|
"https://download.nextcloud.com/server/releases/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2"; \
|
||||||
|
curl -fsSL -o nextcloud.tar.bz2.asc \
|
||||||
|
"https://download.nextcloud.com/server/releases/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2.asc"; \
|
||||||
|
export GNUPGHOME="$(mktemp -d)"; \
|
||||||
|
# gpg key from https://nextcloud.com/nextcloud.asc
|
||||||
|
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \
|
||||||
|
gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2; \
|
||||||
|
tar -xjf nextcloud.tar.bz2 -C /usr/src/; \
|
||||||
|
gpgconf --kill all; \
|
||||||
|
rm nextcloud.tar.bz2.asc nextcloud.tar.bz2; \
|
||||||
|
rm -rf "$GNUPGHOME" /usr/src/nextcloud/updater; \
|
||||||
|
mkdir -p /usr/src/nextcloud/data; \
|
||||||
|
mkdir -p /usr/src/nextcloud/custom_apps; \
|
||||||
|
chmod +x /usr/src/nextcloud/occ; \
|
||||||
|
\
|
||||||
|
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY *.sh upgrade.exclude /
|
||||||
|
COPY config/* /usr/src/nextcloud/config/
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
CMD ["php-fpm"]
|
||||||
|
|
||||||
|
# Template from https://github.com/nextcloud/docker/blob/master/.examples/dockerfiles/full/fpm/Dockerfile
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
ffmpeg \
|
||||||
|
libmagickcore-6.q16-6-extra \
|
||||||
|
procps \
|
||||||
|
smbclient \
|
||||||
|
supervisor \
|
||||||
|
# libreoffice \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
savedAptMark="$(apt-mark showmanual)"; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
libbz2-dev \
|
||||||
|
libc-client-dev \
|
||||||
|
libkrb5-dev \
|
||||||
|
libsmbclient-dev \
|
||||||
|
; \
|
||||||
|
\
|
||||||
|
docker-php-ext-configure imap --with-kerberos --with-imap-ssl; \
|
||||||
|
docker-php-ext-install \
|
||||||
|
bz2 \
|
||||||
|
imap \
|
||||||
|
; \
|
||||||
|
pecl install smbclient; \
|
||||||
|
docker-php-ext-enable smbclient; \
|
||||||
|
\
|
||||||
|
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
|
||||||
|
apt-mark auto '.*' > /dev/null; \
|
||||||
|
apt-mark manual $savedAptMark; \
|
||||||
|
ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \
|
||||||
|
| awk '/=>/ { print $3 }' \
|
||||||
|
| sort -u \
|
||||||
|
| xargs -r dpkg-query -S \
|
||||||
|
| cut -d: -f1 \
|
||||||
|
| sort -u \
|
||||||
|
| xargs -rt apt-mark manual; \
|
||||||
|
\
|
||||||
|
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN mkdir -p \
|
||||||
|
/var/log/supervisord \
|
||||||
|
/var/run/supervisord \
|
||||||
|
;
|
||||||
|
|
||||||
|
COPY supervisord.conf /
|
||||||
|
|
||||||
|
ENV NEXTCLOUD_UPDATE=1
|
||||||
|
|
||||||
|
CMD ["/usr/bin/supervisord", "-c", "/supervisord.conf"]
|
||||||
|
|
||||||
|
# Custom:
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
netcat \
|
||||||
|
openssl \
|
||||||
|
gnupg \
|
||||||
|
dirmngr \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN chown www-data:root -R /usr/src && \
|
||||||
|
chown www-data:root -R /usr/local/etc/php/conf.d && \
|
||||||
|
chown www-data:root -R /var/log/supervisord/ && \
|
||||||
|
chown www-data:root -R /var/run/supervisord/ && \
|
||||||
|
mkdir -p /var/log/nextcloud/ && \
|
||||||
|
chown -R www-data:root /var/log/nextcloud/
|
||||||
|
|
||||||
|
COPY start.sh /
|
||||||
|
COPY notify.sh /
|
||||||
|
RUN chmod +x /start.sh && \
|
||||||
|
chmod +r /supervisord.conf && \
|
||||||
|
chmod +x /entrypoint.sh && \
|
||||||
|
chmod +r /upgrade.exclude && \
|
||||||
|
chmod +x /cron.sh && \
|
||||||
|
chmod +x /notify.sh
|
||||||
|
|
||||||
|
RUN mkdir /mnt/ncdata; \
|
||||||
|
chown www-data:www-data /mnt/ncdata;
|
||||||
|
|
||||||
|
VOLUME /mnt/ncdata
|
||||||
|
|
||||||
|
# Give root a random password
|
||||||
|
RUN echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||||
|
|
||||||
|
USER www-data
|
||||||
|
ENTRYPOINT ["/start.sh"]
|
4
Containers/nextcloud/config/apcu.config.php
Normal file
4
Containers/nextcloud/config/apcu.config.php
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
$CONFIG = array (
|
||||||
|
'memcache.local' => '\OC\Memcache\APCu',
|
||||||
|
);
|
15
Containers/nextcloud/config/apps.config.php
Normal file
15
Containers/nextcloud/config/apps.config.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
$CONFIG = array (
|
||||||
|
'apps_paths' => array (
|
||||||
|
0 => array (
|
||||||
|
'path' => OC::$SERVERROOT.'/apps',
|
||||||
|
'url' => '/apps',
|
||||||
|
'writable' => false,
|
||||||
|
),
|
||||||
|
1 => array (
|
||||||
|
'path' => OC::$SERVERROOT.'/custom_apps',
|
||||||
|
'url' => '/custom_apps',
|
||||||
|
'writable' => true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
17
Containers/nextcloud/config/redis.config.php
Normal file
17
Containers/nextcloud/config/redis.config.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
if (getenv('REDIS_HOST')) {
|
||||||
|
$CONFIG = array(
|
||||||
|
'memcache.distributed' => '\OC\Memcache\Redis',
|
||||||
|
'memcache.locking' => '\OC\Memcache\Redis',
|
||||||
|
'redis' => array(
|
||||||
|
'host' => getenv('REDIS_HOST'),
|
||||||
|
'password' => (string) getenv('REDIS_HOST_PASSWORD'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (getenv('REDIS_HOST_PORT') !== false) {
|
||||||
|
$CONFIG['redis']['port'] = (int) getenv('REDIS_HOST_PORT');
|
||||||
|
} elseif (getenv('REDIS_HOST')[0] != '/') {
|
||||||
|
$CONFIG['redis']['port'] = 6379;
|
||||||
|
}
|
||||||
|
}
|
25
Containers/nextcloud/config/reverse-proxy.config.php
Normal file
25
Containers/nextcloud/config/reverse-proxy.config.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
$overwriteHost = getenv('OVERWRITEHOST');
|
||||||
|
if ($overwriteHost) {
|
||||||
|
$CONFIG['overwritehost'] = $overwriteHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
$overwriteProtocol = getenv('OVERWRITEPROTOCOL');
|
||||||
|
if ($overwriteProtocol) {
|
||||||
|
$CONFIG['overwriteprotocol'] = $overwriteProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
$overwriteWebRoot = getenv('OVERWRITEWEBROOT');
|
||||||
|
if ($overwriteWebRoot) {
|
||||||
|
$CONFIG['overwritewebroot'] = $overwriteWebRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
$overwriteCondAddr = getenv('OVERWRITECONDADDR');
|
||||||
|
if ($overwriteCondAddr) {
|
||||||
|
$CONFIG['overwritecondaddr'] = $overwriteCondAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
$trustedProxies = getenv('TRUSTED_PROXIES');
|
||||||
|
if ($trustedProxies) {
|
||||||
|
$CONFIG['trusted_proxies'] = array_filter(array_map('trim', explode(' ', $trustedProxies)));
|
||||||
|
}
|
7
Containers/nextcloud/cron.sh
Normal file
7
Containers/nextcloud/cron.sh
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
php -f /var/www/html/cron.php &
|
||||||
|
sleep 5m
|
||||||
|
done
|
254
Containers/nextcloud/entrypoint.sh
Normal file
254
Containers/nextcloud/entrypoint.sh
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# version_greater A B returns whether A > B
|
||||||
|
version_greater() {
|
||||||
|
[ "$(printf '%s\n' "$@" | sort -t '.' -n -k1,1 -k2,2 -k3,3 -k4,4 | head -n 1)" != "$1" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# return true if specified directory is empty
|
||||||
|
directory_empty() {
|
||||||
|
[ -z "$(ls -A "$1/")" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Configuring Redis as session handler"
|
||||||
|
cat << REDIS_CONF > /usr/local/etc/php/conf.d/redis-session.ini
|
||||||
|
session.save_handler = redis
|
||||||
|
session.save_path = "tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}?auth=${REDIS_HOST_PASSWORD}"
|
||||||
|
redis.session.locking_enabled = 1
|
||||||
|
redis.session.lock_retries = -1
|
||||||
|
# redis.session.lock_wait_time is specified in microseconds.
|
||||||
|
# Wait 10ms before retrying the lock rather than the default 2ms.
|
||||||
|
redis.session.lock_wait_time = 10000
|
||||||
|
REDIS_CONF
|
||||||
|
|
||||||
|
if [ -f /var/www/html/version.php ]; then
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')"
|
||||||
|
else
|
||||||
|
installed_version="0.0.0.0"
|
||||||
|
fi
|
||||||
|
if [ -f "/usr/src/nextcloud/version.php" ]; then
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
image_version="$(php -r 'require "/usr/src/nextcloud/version.php"; echo implode(".", $OC_Version);')"
|
||||||
|
else
|
||||||
|
image_version="$installed_version"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# unset admin password
|
||||||
|
if [ "$installed_version" != "0.0.0.0" ]; then
|
||||||
|
unset ADMIN_PASSWORD
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if version_greater "$image_version" "$installed_version"; then
|
||||||
|
# Check if it skips a major version
|
||||||
|
INSTALLED_MAJOR="${installed_version%%.*}"
|
||||||
|
IMAGE_MAJOR="${image_version%%.*}"
|
||||||
|
if [ "$installed_version" != "0.0.0.0" ] && [ "$((IMAGE_MAJOR - INSTALLED_MAJOR))" -gt 1 ]; then
|
||||||
|
set -ex
|
||||||
|
NEXT_MAJOR="$((INSTALLED_MAJOR + 1))"
|
||||||
|
curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/latest-${NEXT_MAJOR}.tar.bz2"
|
||||||
|
curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/latest-${NEXT_MAJOR}.tar.bz2.asc"
|
||||||
|
export GNUPGHOME="$(mktemp -d)"
|
||||||
|
# gpg key from https://nextcloud.com/nextcloud.asc
|
||||||
|
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A
|
||||||
|
gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2
|
||||||
|
mkdir -p /usr/src/tmp
|
||||||
|
tar -xjf nextcloud.tar.bz2 -C /usr/src/tmp/
|
||||||
|
gpgconf --kill all
|
||||||
|
rm nextcloud.tar.bz2.asc nextcloud.tar.bz2
|
||||||
|
rm -rf "$GNUPGHOME" /usr/src/tmp/nextcloud/updater
|
||||||
|
mkdir -p /usr/src/tmp/nextcloud/data
|
||||||
|
mkdir -p /usr/src/tmp/nextcloud/custom_apps
|
||||||
|
chmod +x /usr/src/tmp/nextcloud/occ
|
||||||
|
cp /usr/src/nextcloud/config/* /usr/src/tmp/nextcloud/config/
|
||||||
|
mv /usr/src/nextcloud /usr/src/temp-nextcloud
|
||||||
|
mv /usr/src/tmp/nextcloud /usr/src/nextcloud
|
||||||
|
rm -r /usr/src/tmp
|
||||||
|
rm -r /usr/src/temp-nextcloud
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
image_version="$(php -r 'require "/usr/src/nextcloud/version.php"; echo implode(".", $OC_Version);')"
|
||||||
|
IMAGE_MAJOR="${image_version%%.*}"
|
||||||
|
set +ex
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$installed_version" != "0.0.0.0" ]; then
|
||||||
|
while true; do
|
||||||
|
echo -e "Checking connection to appstore"
|
||||||
|
CURL_STATUS="$(curl -LI "https://apps.nextcloud.com/" -o /dev/null -w '%{http_code}\n' -s)"
|
||||||
|
if [[ "$CURL_STATUS" = "200" ]]
|
||||||
|
then
|
||||||
|
echo "Appstore is reachable"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
echo "Curl didn't produce a 200 status, is appstore reachable?"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
php /var/www/html/occ maintenance:mode --off
|
||||||
|
|
||||||
|
echo "Getting and backing up the status of apps for later, this might take a while..."
|
||||||
|
php /var/www/html/occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before
|
||||||
|
|
||||||
|
if [ "$((IMAGE_MAJOR - INSTALLED_MAJOR))" -eq 1 ]; then
|
||||||
|
php /var/www/html/occ config:system:delete app_install_overwrite
|
||||||
|
fi
|
||||||
|
|
||||||
|
php /var/www/html/occ app:update --all
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Initializing nextcloud $image_version ..."
|
||||||
|
rsync -rlD --delete --exclude-from=/upgrade.exclude /usr/src/nextcloud/ /var/www/html/
|
||||||
|
|
||||||
|
for dir in config data custom_apps themes; do
|
||||||
|
if [ ! -d "/var/www/html/$dir" ] || directory_empty "/var/www/html/$dir"; then
|
||||||
|
rsync -rlD --include "/$dir/" --exclude '/*' /usr/src/nextcloud/ /var/www/html/
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
rsync -rlD --include '/version.php' --exclude '/*' /usr/src/nextcloud/ /var/www/html/
|
||||||
|
echo "Initializing finished"
|
||||||
|
|
||||||
|
#install
|
||||||
|
if [ "$installed_version" = "0.0.0.0" ]; then
|
||||||
|
echo "New nextcloud instance"
|
||||||
|
|
||||||
|
INSTALL_OPTIONS=(-n --admin-user "$ADMIN_USER" --admin-pass "$ADMIN_PASSWORD")
|
||||||
|
if [ -n "${NEXTCLOUD_DATA_DIR}" ]; then
|
||||||
|
INSTALL_OPTIONS+=(--data-dir "$NEXTCLOUD_DATA_DIR")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing with PostgreSQL database"
|
||||||
|
INSTALL_OPTIONS+=(--database pgsql --database-name "$POSTGRES_DB" --database-user "$POSTGRES_USER" --database-pass "$POSTGRES_PASSWORD" --database-host "$POSTGRES_HOST")
|
||||||
|
|
||||||
|
echo "starting nextcloud installation"
|
||||||
|
max_retries=10
|
||||||
|
try=0
|
||||||
|
until php /var/www/html/occ maintenance:install "${INSTALL_OPTIONS[@]}" || [ "$try" -gt "$max_retries" ]
|
||||||
|
do
|
||||||
|
echo "retrying install..."
|
||||||
|
try=$((try+1))
|
||||||
|
sleep 10s
|
||||||
|
done
|
||||||
|
if [ "$try" -gt "$max_retries" ]; then
|
||||||
|
echo "installing of nextcloud failed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# unset admin password
|
||||||
|
unset ADMIN_PASSWORD
|
||||||
|
|
||||||
|
# Apply log settings
|
||||||
|
echo "Applying default settings..."
|
||||||
|
mkdir -p /var/www/html/data
|
||||||
|
php /var/www/html/occ config:system:set loglevel --value=2
|
||||||
|
php /var/www/html/occ config:system:set log_type --value=file
|
||||||
|
php /var/www/html/occ config:system:set logfile --value="/var/log/nextcloud/nextcloud.log"
|
||||||
|
php /var/www/html/occ config:system:set log_rotate_size --value="10485760"
|
||||||
|
php /var/www/html/occ app:enable admin_audit
|
||||||
|
php /var/www/html/occ config:app:set admin_audit logfile --value="/var/log/nextcloud/audit.log"
|
||||||
|
php /var/www/html/occ config:system:set log.condition apps 0 --value="admin_audit"
|
||||||
|
|
||||||
|
# Apply preview settings
|
||||||
|
echo "Applying preview settings..."
|
||||||
|
php /var/www/html/occ config:system:set preview_max_x --value="2048"
|
||||||
|
php /var/www/html/occ config:system:set preview_max_y --value="2048"
|
||||||
|
php /var/www/html/occ config:system:set jpeg_quality --value="60"
|
||||||
|
php /var/www/html/occ config:app:set preview jpeg_quality --value="60"
|
||||||
|
php /var/www/html/occ config:system:delete enabledPreviewProviders
|
||||||
|
php /var/www/html/occ config:system:set enabledPreviewProviders 1 --value="OC\\Preview\\Image"
|
||||||
|
php /var/www/html/occ config:system:set enabledPreviewProviders 2 --value="OC\\Preview\\MarkDown"
|
||||||
|
php /var/www/html/occ config:system:set enabledPreviewProviders 3 --value="OC\\Preview\\MP3"
|
||||||
|
php /var/www/html/occ config:system:set enabledPreviewProviders 4 --value="OC\\Preview\\TXT"
|
||||||
|
php /var/www/html/occ config:system:set enabledPreviewProviders 5 --value="OC\\Preview\\OpenDocument"
|
||||||
|
php /var/www/html/occ config:system:set enabledPreviewProviders 6 --value="OC\\Preview\\Movie"
|
||||||
|
php /var/www/html/occ config:system:set enable_previews --value=true --type=boolean
|
||||||
|
|
||||||
|
# Apply other settings
|
||||||
|
echo "Applying other settings..."
|
||||||
|
php /var/www/html/occ config:system:set upgrade.disable-web --type=bool --value=true
|
||||||
|
php /var/www/html/occ config:app:set updatenotification notify_groups --value="[]"
|
||||||
|
php /var/www/html/occ config:system:set mail_smtpmode --value="smtp"
|
||||||
|
php /var/www/html/occ config:system:set trashbin_retention_obligation --value="auto, 30"
|
||||||
|
php /var/www/html/occ config:system:set versions_retention_obligation --value="auto, 30"
|
||||||
|
php /var/www/html/occ config:system:set activity_expire_days --value="30"
|
||||||
|
php /var/www/html/occ config:system:set simpleSignUpLink.shown --type=bool --value=false
|
||||||
|
php /var/www/html/occ config:system:set share_folder --value="/Shared"
|
||||||
|
|
||||||
|
#upgrade
|
||||||
|
else
|
||||||
|
while [ -n "$(pgrep -f cron.php)" ]
|
||||||
|
do
|
||||||
|
echo "Waiting for Nextclouds cronjob to finish..."
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Upgrading nextcloud from $installed_version to $image_version..."
|
||||||
|
if ! php /var/www/html/occ upgrade || ! php /var/www/html/occ -V; then
|
||||||
|
echo "Upgrade failed. Please restore from backup."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
php /var/www/html/occ app:list | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after
|
||||||
|
echo "The following apps have been disabled:"
|
||||||
|
diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1
|
||||||
|
rm -f /tmp/list_before /tmp/list_after
|
||||||
|
|
||||||
|
# Apply optimization
|
||||||
|
echo "Doing some optimizations..."
|
||||||
|
php /var/www/html/occ maintenance:repair
|
||||||
|
php /var/www/html/occ db:add-missing-indices
|
||||||
|
php /var/www/html/occ db:add-missing-columns
|
||||||
|
php /var/www/html/occ db:add-missing-primary-keys
|
||||||
|
yes | php /var/www/html/occ db:convert-filecache-bigint
|
||||||
|
php /var/www/html/occ maintenance:mimetype:update-js
|
||||||
|
php /var/www/html/occ maintenance:mimetype:update-db
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Apply one-click-instance settings
|
||||||
|
echo "Applying one-click-instance settings..."
|
||||||
|
php /var/www/html/occ config:system:set one-click-instance --value=true --type=bool
|
||||||
|
php /var/www/html/occ config:system:set one-click-instance.user-limit --value=100 --type=int
|
||||||
|
|
||||||
|
# Apply network settings
|
||||||
|
echo "Applying network settings..."
|
||||||
|
php /var/www/html/occ config:system:set trusted_domains 1 --value="$NC_DOMAIN"
|
||||||
|
php /var/www/html/occ config:system:set overwrite.cli.url --value="https://$NC_DOMAIN/"
|
||||||
|
php /var/www/html/occ config:system:set htaccess.RewriteBase --value="/"
|
||||||
|
php /var/www/html/occ maintenance:update:htaccess
|
||||||
|
|
||||||
|
# Notify push
|
||||||
|
if ! [ -d "/var/www/html/custom_apps/notify_push" ]; then
|
||||||
|
php /var/www/html/occ app:install notify_push
|
||||||
|
elif [ "$(php /var/www/html/occ config:app:get notify_push enabled)" = "no" ]; then
|
||||||
|
php /var/www/html/occ app:enable notify_push
|
||||||
|
else
|
||||||
|
php /var/www/html/occ app:update notify_push
|
||||||
|
fi
|
||||||
|
php /var/www/html/occ config:app:set notify_push base_endpoint --value="https://$NC_DOMAIN/push"
|
||||||
|
|
||||||
|
# Collabora
|
||||||
|
if ! [ -d "/var/www/html/custom_apps/richdocuments" ]; then
|
||||||
|
php /var/www/html/occ app:install richdocuments
|
||||||
|
elif [ "$(php /var/www/html/occ config:app:get richdocuments enabled)" = "no" ]; then
|
||||||
|
php /var/www/html/occ app:enable richdocuments
|
||||||
|
else
|
||||||
|
php /var/www/html/occ app:update richdocuments
|
||||||
|
fi
|
||||||
|
php /var/www/html/occ config:app:set richdocuments wopi_url --value="https://$NC_DOMAIN/"
|
||||||
|
# php /var/www/html/occ richdocuments:activate-config
|
||||||
|
|
||||||
|
# Talk
|
||||||
|
if ! [ -d "/var/www/html/custom_apps/spreed" ]; then
|
||||||
|
php /var/www/html/occ app:install spreed
|
||||||
|
elif [ "$(php /var/www/html/occ config:app:get spreed enabled)" = "no" ]; then
|
||||||
|
php /var/www/html/occ app:enable spreed
|
||||||
|
else
|
||||||
|
php /var/www/html/occ app:update spreed
|
||||||
|
fi
|
||||||
|
STUN_SERVERS="[\"$NC_DOMAIN:3478\"]"
|
||||||
|
TURN_SERVERS="[{\"server\":\"$NC_DOMAIN:3478\",\"secret\":\"$TURN_SECRET\",\"protocols\":\"udp,tcp\"}]"
|
||||||
|
SIGNALING_SERVERS="{\"servers\":[{\"server\":\"https://$NC_DOMAIN/standalone-signaling/\",\"verify\":true}],\"secret\":\"$SIGNALING_SECRET\"}"
|
||||||
|
php /var/www/html/occ config:app:set spreed stun_servers --value="$STUN_SERVERS" --output json
|
||||||
|
php /var/www/html/occ config:app:set spreed turn_servers --value="$TURN_SERVERS" --output json
|
||||||
|
php /var/www/html/occ config:app:set spreed signaling_servers --value="$SIGNALING_SERVERS" --output json
|
29
Containers/nextcloud/notify.sh
Normal file
29
Containers/nextcloud/notify.sh
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SUBJECT="$1"
|
||||||
|
MESSAGE="$2"
|
||||||
|
|
||||||
|
if [ "$(php /var/www/html/occ config:app:get notificaations enabled)" = "no" ]; then
|
||||||
|
echo "Cannot send notification as notification app is not enabled."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Posting notifications to users that are admins..."
|
||||||
|
NC_USERS=$(php /var/www/html/occ user:list | sed 's|^ - ||g' | sed 's|:.*||')
|
||||||
|
mapfile -t NC_USERS <<< "$NC_USERS"
|
||||||
|
for user in "${NC_USERS[@]}"
|
||||||
|
do
|
||||||
|
if php /var/www/html/occ user:info "$user" | cut -d "-" -f2 | grep -x -q " admin"
|
||||||
|
then
|
||||||
|
NC_ADMIN_USER+=("$user")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for admin in "${NC_ADMIN_USER[@]}"
|
||||||
|
do
|
||||||
|
echo "Posting '$SUBJECT' to: $admin"
|
||||||
|
php /var/www/html/occ notification:generate "$admin" "$NC_DOMAIN: $SUBJECT" -l "$MESSAGE"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Done!"
|
||||||
|
exit 0
|
14
Containers/nextcloud/start.sh
Normal file
14
Containers/nextcloud/start.sh
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Only start container if database is accessible
|
||||||
|
while ! nc -z "$POSTGRES_HOST" 5432; do
|
||||||
|
echo "Waiting for database to start..."
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
# Run original entrypoint
|
||||||
|
if ! bash /entrypoint.sh; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
30
Containers/nextcloud/supervisord.conf
Normal file
30
Containers/nextcloud/supervisord.conf
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# From https://github.com/nextcloud/docker/blob/master/.examples/dockerfiles/full/fpm/supervisord.conf
|
||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
logfile=/var/log/supervisord/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord/supervisord.pid
|
||||||
|
childlogdir=/var/log/supervisord/
|
||||||
|
logfile_maxbytes=50MB ; maximum size of logfile before rotation
|
||||||
|
logfile_backups=10 ; number of backed up logfiles
|
||||||
|
loglevel=error
|
||||||
|
|
||||||
|
[program:php-fpm]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=php-fpm
|
||||||
|
|
||||||
|
[program:cron]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=/cron.sh
|
||||||
|
|
||||||
|
[program:notify-push]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=/var/www/html/custom_apps/notify_push/bin/x86_64/notify_push /var/www/html/config/config.php --port 7867 --redis-url redis://:%(ENV_REDIS_HOST_PASSWORD)s@%(ENV_REDIS_HOST)s
|
5
Containers/nextcloud/upgrade.exclude
Normal file
5
Containers/nextcloud/upgrade.exclude
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/config/
|
||||||
|
/data/
|
||||||
|
/custom_apps/
|
||||||
|
/themes/
|
||||||
|
/version.php
|
24
Containers/postgresql/Dockerfile
Normal file
24
Containers/postgresql/Dockerfile
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# From https://github.com/docker-library/postgres/blob/master/13/buster/Dockerfile
|
||||||
|
FROM postgres:13-buster
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
openssl \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY start.sh /usr/bin/
|
||||||
|
RUN chmod +x /usr/bin/start.sh
|
||||||
|
|
||||||
|
RUN mkdir /mnt/data; \
|
||||||
|
chown postgres:postgres /mnt/data;
|
||||||
|
|
||||||
|
VOLUME /mnt/data
|
||||||
|
|
||||||
|
# Give root a random password
|
||||||
|
RUN echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||||
|
|
||||||
|
USER postgres
|
||||||
|
ENTRYPOINT ["start.sh"]
|
87
Containers/postgresql/start.sh
Normal file
87
Containers/postgresql/start.sh
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
DATADIR="/var/lib/postgresql/data"
|
||||||
|
DUMP_DIR="/mnt/data"
|
||||||
|
DUMP_FILE="$DUMP_DIR/database-dump.sql"
|
||||||
|
export PGPASSWORD="$POSTGRES_PASSWORD"
|
||||||
|
|
||||||
|
# Don't start database as long as backup is running
|
||||||
|
while [ -f "$DUMP_DIR/backup-is-running" ]; do
|
||||||
|
echo "Waiting for backup container to finish..."
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if dump dir is writeable
|
||||||
|
if ! [ -w "$DUMP_DIR" ]; then
|
||||||
|
echo "DUMP dir is not writeable by postgres user."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test if some things match
|
||||||
|
if ( [ -f "$DATADIR/PG_VERSION" ] && [ "$PG_MAJOR" != "$(cat "$DATADIR/PG_VERSION")" ] ) \
|
||||||
|
|| ( ! [ -f "$DATADIR/PG_VERSION" ] && [ -f "$DUMP_FILE" ] ); then
|
||||||
|
# The DUMP_file must be provided
|
||||||
|
if ! [ -f "$DUMP_FILE" ]; then
|
||||||
|
echo "Unable to restore the database because the database dump is missing."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Inform
|
||||||
|
echo "Restoring from database dump."
|
||||||
|
|
||||||
|
# Exit if any command fails
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Remove old database files
|
||||||
|
rm -rf "$DATADIR/"*
|
||||||
|
|
||||||
|
# Change database port to a random port temporarily
|
||||||
|
export PGPORT=11000
|
||||||
|
|
||||||
|
# Create new database
|
||||||
|
exec docker-entrypoint.sh postgres &
|
||||||
|
|
||||||
|
# Wait 2s for creation
|
||||||
|
sleep 2s
|
||||||
|
|
||||||
|
# Restore database
|
||||||
|
echo "Restoring the database from database dump"
|
||||||
|
psql "$POSTGRES_DB" -U "$POSTGRES_USER" < "$DUMP_FILE"
|
||||||
|
|
||||||
|
# Shut down the database to be able to start it again
|
||||||
|
pg_ctl stop -m fast
|
||||||
|
|
||||||
|
# Change database port back to default
|
||||||
|
export PGPORT=5432
|
||||||
|
|
||||||
|
# Don't exit if command fails anymore
|
||||||
|
set +e
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cover the last case
|
||||||
|
if ! [ -f "$DATADIR/PG_VERSION" ] && ! [ -f "$DUMP_FILE" ]; then
|
||||||
|
# Remove old database files if somehow there should be some
|
||||||
|
rm -rf "$DATADIR/"*
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Catch docker stop attempts
|
||||||
|
trap 'true' SIGINT SIGTERM
|
||||||
|
|
||||||
|
# Start the database
|
||||||
|
exec docker-entrypoint.sh postgres &
|
||||||
|
wait $!
|
||||||
|
|
||||||
|
# Continue with shutdown procedure: do database dump, etc.
|
||||||
|
rm -f "$DUMP_FILE.temp"
|
||||||
|
if pg_dump --username "$POSTGRES_USER" "$POSTGRES_DB" > "$DUMP_FILE.temp"; then
|
||||||
|
rm -f "$DUMP_FILE"
|
||||||
|
mv "$DUMP_FILE.temp" "$DUMP_FILE"
|
||||||
|
pg_ctl stop -m fast
|
||||||
|
echo 'Database dump successful!'
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
pg_ctl stop -m fast
|
||||||
|
echo "Database dump unsucessful!"
|
||||||
|
exit 1
|
||||||
|
fi
|
19
Containers/redis/Dockerfile
Normal file
19
Containers/redis/Dockerfile
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# From https://github.com/docker-library/redis/blob/master/6.2/Dockerfile
|
||||||
|
FROM redis:6.2-buster
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
openssl \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY start.sh /usr/bin/
|
||||||
|
RUN chmod +x /usr/bin/start.sh
|
||||||
|
|
||||||
|
# Give root a random password
|
||||||
|
RUN echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||||
|
|
||||||
|
USER redis
|
||||||
|
ENTRYPOINT ["start.sh"]
|
10
Containers/redis/start.sh
Normal file
10
Containers/redis/start.sh
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Run redis with a password if provided
|
||||||
|
if [ -n "$REDIS_HOST_PASSWORD" ]; then
|
||||||
|
exec redis-server --requirepass "$REDIS_HOST_PASSWORD"
|
||||||
|
else
|
||||||
|
exec redis-server
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
64
Containers/talk/Dockerfile
Normal file
64
Containers/talk/Dockerfile
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
FROM ubuntu:focal
|
||||||
|
|
||||||
|
EXPOSE 3478
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
openssl \
|
||||||
|
coturn \
|
||||||
|
supervisor \
|
||||||
|
curl \
|
||||||
|
ca-certificates \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
curl -sL -o "/etc/apt/trusted.gpg.d/morph027-nats-server.asc" "https://packaging.gitlab.io/nats-server/gpg.key"; \
|
||||||
|
echo "deb https://packaging.gitlab.io/nats-server nats main" > /etc/apt/sources.list.d/morph027-nats-server.list; \
|
||||||
|
. /etc/lsb-release; \
|
||||||
|
curl -sL -o "/etc/apt/trusted.gpg.d/morph027-janus.asc" "https://packaging.gitlab.io/janus/gpg.key"; \
|
||||||
|
echo "deb https://packaging.gitlab.io/janus/$DISTRIB_CODENAME $DISTRIB_CODENAME main" > /etc/apt/sources.list.d/morph027-janus.list; \
|
||||||
|
curl -sL -o "/etc/apt/trusted.gpg.d/morph027-nextcloud-spreed-signaling.asc" "https://packaging.gitlab.io/nextcloud-spreed-signaling/gpg.key"; \
|
||||||
|
echo "deb https://packaging.gitlab.io/nextcloud-spreed-signaling signaling main" > /etc/apt/sources.list.d/morph027-nextcloud-spreed-signaling.list
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
nats-server \
|
||||||
|
janus \
|
||||||
|
nextcloud-spreed-signaling \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN adduser --system --group talk
|
||||||
|
|
||||||
|
RUN mkdir /var/log/supervisord; \
|
||||||
|
mkdir /var/run/supervisord; \
|
||||||
|
chown talk:talk /var/run/supervisord; \
|
||||||
|
chown talk:talk /var/log/supervisord;
|
||||||
|
|
||||||
|
COPY start.sh /usr/bin/
|
||||||
|
COPY supervisord.conf /
|
||||||
|
RUN chmod +x /usr/bin/start.sh; \
|
||||||
|
chmod +r /supervisord.conf; \
|
||||||
|
touch /etc/turnserver.conf; \
|
||||||
|
chown talk:talk /etc/turnserver.conf; \
|
||||||
|
sed -i '/TURNSERVER_ENABLED/c\TURNSERVER_ENABLED=1' /etc/default/coturn; \
|
||||||
|
mkdir -p /var/tmp;
|
||||||
|
|
||||||
|
RUN mkdir -p /etc/nats; \
|
||||||
|
echo "listen: 127.0.0.1:4222" > /etc/nats/nats.conf; \
|
||||||
|
chown talk:talk -R /etc/nats; \
|
||||||
|
chown talk:talk -R /etc/janus; \
|
||||||
|
chown talk:talk -R /etc/signaling; \
|
||||||
|
chown talk:talk -R /usr/share/janus
|
||||||
|
|
||||||
|
# Give root a random password
|
||||||
|
RUN echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||||
|
|
||||||
|
USER talk
|
||||||
|
ENTRYPOINT ["start.sh"]
|
||||||
|
CMD ["/usr/bin/supervisord", "-c", "/supervisord.conf"]
|
67
Containers/talk/start.sh
Normal file
67
Containers/talk/start.sh
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
if [ -z "$NC_DOMAIN" ]; then
|
||||||
|
echo "You need to provide the NC_DOMAIN."
|
||||||
|
exit 1
|
||||||
|
elif [ -z "$TURN_SECRET" ]; then
|
||||||
|
echo "You need to provide the TURN_SECRET."
|
||||||
|
exit 1
|
||||||
|
elif [ -z "$JANUS_API_KEY" ]; then
|
||||||
|
echo "You need to provide the JANUS_API_KEY."
|
||||||
|
exit 1
|
||||||
|
elif [ -z "$SIGNALING_SECRET" ]; then
|
||||||
|
echo "You need to provide the JANUS_API_KEY."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Turn
|
||||||
|
cat << TURN_CONF > "/etc/turnserver.conf"
|
||||||
|
listening-port=3478
|
||||||
|
fingerprint
|
||||||
|
use-auth-secret
|
||||||
|
static-auth-secret=$TURN_SECRET
|
||||||
|
realm=$NC_DOMAIN
|
||||||
|
total-quota=100
|
||||||
|
bps-capacity=0
|
||||||
|
stale-nonce
|
||||||
|
no-multicast-peers
|
||||||
|
simple-log
|
||||||
|
pidfile=/var/tmp/turnserver.pid
|
||||||
|
TURN_CONF
|
||||||
|
|
||||||
|
# Janus
|
||||||
|
sed -i "s|#turn_rest_api_key.*|turn_rest_api_key = $JANUS_API_KEY|" /etc/janus/janus.jcfg
|
||||||
|
sed -i "s|#full_trickle|full_trickle|g" /etc/janus/janus.jcfg
|
||||||
|
sed -i 's|#interface.*|interface = "lo"|g' /etc/janus/janus.transport.websockets.jcfg
|
||||||
|
sed -i 's|#ws_interface.*|ws_interface = "lo"|g' /etc/janus/janus.transport.websockets.jcfg
|
||||||
|
|
||||||
|
# Signling
|
||||||
|
cat << SIGNALING_CONF > "/etc/signaling/server.conf"
|
||||||
|
[http]
|
||||||
|
listen = 0.0.0.0:8081
|
||||||
|
[app]
|
||||||
|
debug = false
|
||||||
|
[sessions]
|
||||||
|
hashkey = $(openssl rand -hex 16)
|
||||||
|
blockkey = $(openssl rand -hex 16)
|
||||||
|
[clients]
|
||||||
|
internalsecret = $(openssl rand -hex 16)
|
||||||
|
[backend]
|
||||||
|
allowed = ${NC_DOMAIN}
|
||||||
|
allowall = false
|
||||||
|
secret = ${SIGNALING_SECRET}
|
||||||
|
timeout = 10
|
||||||
|
connectionsperhost = 8
|
||||||
|
[nats]
|
||||||
|
url = nats://127.0.0.1:4222
|
||||||
|
[mcu]
|
||||||
|
type = janus
|
||||||
|
url = ws://127.0.0.1:8188
|
||||||
|
[turn]
|
||||||
|
apikey = ${JANUS_API_KEY}
|
||||||
|
secret = ${TURN_SECRET}
|
||||||
|
servers = turn:$NC_DOMAIN:3478?transport=tcp,turn:$NC_DOMAIN:3478?transport=udp
|
||||||
|
SIGNALING_CONF
|
||||||
|
|
||||||
|
exec "$@"
|
37
Containers/talk/supervisord.conf
Normal file
37
Containers/talk/supervisord.conf
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
nodaemon=true
|
||||||
|
logfile=/var/log/supervisord/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord/supervisord.pid
|
||||||
|
childlogdir=/var/log/supervisord/
|
||||||
|
logfile_maxbytes=50MB
|
||||||
|
logfile_backups=10
|
||||||
|
loglevel=error
|
||||||
|
|
||||||
|
[program:turnserver]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=turnserver
|
||||||
|
|
||||||
|
[program:nats-server]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=nats-server -c /etc/nats/nats.conf
|
||||||
|
|
||||||
|
[program:janus]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=janus
|
||||||
|
|
||||||
|
[program:signaling]
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
command=signaling -config /etc/signaling/server.conf
|
28
Containers/watchtower/Dockerfile
Normal file
28
Containers/watchtower/Dockerfile
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# From https://github.com/containrrr/watchtower/blob/main/dockerfiles/Dockerfile.self-contained
|
||||||
|
FROM containrrr/watchtower:latest as watchtower
|
||||||
|
|
||||||
|
FROM debian:bullseye
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates \
|
||||||
|
openssl \
|
||||||
|
; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY --from=watchtower /watchtower /
|
||||||
|
|
||||||
|
COPY start.sh /
|
||||||
|
RUN chmod +x /start.sh
|
||||||
|
|
||||||
|
# Give root a random password
|
||||||
|
RUN echo "root:$(openssl rand -base64 12)" | chpasswd
|
||||||
|
|
||||||
|
# add docker group
|
||||||
|
RUN groupadd -g 998 docker && \
|
||||||
|
usermod -aG docker nobody
|
||||||
|
|
||||||
|
USER nobody
|
||||||
|
ENTRYPOINT ["/start.sh"]
|
19
Containers/watchtower/start.sh
Normal file
19
Containers/watchtower/start.sh
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Check if socket is available and readable
|
||||||
|
if ! [ -a "/var/run/docker.sock" ]; then
|
||||||
|
echo "Docker socket is not available. Cannot continue."
|
||||||
|
exit 1
|
||||||
|
elif ! [ -r "/var/run/docker.sock" ]; then
|
||||||
|
echo "Docker socket is not readable by the nobody user. Cannot continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$CONTAINER_TO_UPDATE" ]; then
|
||||||
|
exec /watchtower --cleanup --run-once "$CONTAINER_TO_UPDATE"
|
||||||
|
else
|
||||||
|
echo "'CONTAINER_TO_UPDATE' is not set. Cannot update anything."
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
exec "$@"
|
19
app/.editorconfig
Normal file
19
app/.editorconfig
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# https://editorconfig.org
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = tab
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.feature]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.yml]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
32
app/appinfo/info.xml
Normal file
32
app/appinfo/info.xml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
|
||||||
|
<id>nextcloud-aio</id>
|
||||||
|
<name>Nextcloud All In One</name>
|
||||||
|
<summary>Provides a login link for admins.</summary>
|
||||||
|
<description>Add a link to the admin settings that gives access to the Nextcloud All In One admin interface</description>
|
||||||
|
<version>0.1.0</version>
|
||||||
|
<licence>agpl</licence>
|
||||||
|
<author>Azul</author>
|
||||||
|
<namespace>AllInOne</namespace>
|
||||||
|
<default_enable/>
|
||||||
|
<category>monitoring</category>
|
||||||
|
<bugs>https://github.com/nextcloud/all-in-one/issues</bugs>
|
||||||
|
<dependencies>
|
||||||
|
<nextcloud min-version="22" max-version="23"/>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<settings>
|
||||||
|
<admin>OCA\AllInOne\Settings\Admin</admin>
|
||||||
|
</settings>
|
||||||
|
|
||||||
|
<!-- not implemented yet - but might be useful:
|
||||||
|
<background-jobs>
|
||||||
|
<job>OCA\AllInOne\Notification\BackgroundJob</job>
|
||||||
|
</background-jobs>
|
||||||
|
<commands>
|
||||||
|
<command>OCA\UpdateNotification\Command\Check</command>
|
||||||
|
</commands>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</info>
|
7
app/composer/autoload.php
Normal file
7
app/composer/autoload.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
|
return ComposerAutoloaderInitAllInOne::getLoader();
|
13
app/composer/composer.json
Normal file
13
app/composer/composer.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"config" : {
|
||||||
|
"vendor-dir": ".",
|
||||||
|
"optimize-autoloader": true,
|
||||||
|
"classmap-authoritative": true,
|
||||||
|
"autoloader-suffix": "AllInOne"
|
||||||
|
},
|
||||||
|
"autoload" : {
|
||||||
|
"psr-4": {
|
||||||
|
"OCA\\AllInOne\\": "../lib/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
app/composer/composer.lock
generated
Normal file
18
app/composer/composer.lock
generated
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "d751713988987e9331980363e24189ce",
|
||||||
|
"packages": [],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": [],
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": [],
|
||||||
|
"platform-dev": [],
|
||||||
|
"plugin-api-version": "2.1.0"
|
||||||
|
}
|
481
app/composer/composer/ClassLoader.php
Normal file
481
app/composer/composer/ClassLoader.php
Normal file
|
@ -0,0 +1,481 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
|
*
|
||||||
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
*
|
||||||
|
* // register classes with namespaces
|
||||||
|
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||||
|
* $loader->add('Symfony', __DIR__.'/framework');
|
||||||
|
*
|
||||||
|
* // activate the autoloader
|
||||||
|
* $loader->register();
|
||||||
|
*
|
||||||
|
* // to enable searching the include path (eg. for PEAR packages)
|
||||||
|
* $loader->setUseIncludePath(true);
|
||||||
|
*
|
||||||
|
* In this example, if you try to use a class in the Symfony\Component
|
||||||
|
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||||
|
* the autoloader will first look for the class under the component/
|
||||||
|
* directory, and it will then fallback to the framework/ directory if not
|
||||||
|
* found before giving up.
|
||||||
|
*
|
||||||
|
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see https://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see https://www.php-fig.org/psr/psr-4/
|
||||||
|
*/
|
||||||
|
class ClassLoader
|
||||||
|
{
|
||||||
|
private $vendorDir;
|
||||||
|
|
||||||
|
// PSR-4
|
||||||
|
private $prefixLengthsPsr4 = array();
|
||||||
|
private $prefixDirsPsr4 = array();
|
||||||
|
private $fallbackDirsPsr4 = array();
|
||||||
|
|
||||||
|
// PSR-0
|
||||||
|
private $prefixesPsr0 = array();
|
||||||
|
private $fallbackDirsPsr0 = array();
|
||||||
|
|
||||||
|
private $useIncludePath = false;
|
||||||
|
private $classMap = array();
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
private $missingClasses = array();
|
||||||
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
private static $registeredLoaders = array();
|
||||||
|
|
||||||
|
public function __construct($vendorDir = null)
|
||||||
|
{
|
||||||
|
$this->vendorDir = $vendorDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrefixes()
|
||||||
|
{
|
||||||
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrefixesPsr4()
|
||||||
|
{
|
||||||
|
return $this->prefixDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFallbackDirs()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFallbackDirsPsr4()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassMap()
|
||||||
|
{
|
||||||
|
return $this->classMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $classMap Class to filename map
|
||||||
|
*/
|
||||||
|
public function addClassMap(array $classMap)
|
||||||
|
{
|
||||||
|
if ($this->classMap) {
|
||||||
|
$this->classMap = array_merge($this->classMap, $classMap);
|
||||||
|
} else {
|
||||||
|
$this->classMap = $classMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix, either
|
||||||
|
* appending or prepending to the ones previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param array|string $paths The PSR-0 root directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*/
|
||||||
|
public function add($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->fallbackDirsPsr0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$this->fallbackDirsPsr0,
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $prefix[0];
|
||||||
|
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($prepend) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->prefixesPsr0[$first][$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$this->prefixesPsr0[$first][$prefix],
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace, either
|
||||||
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param array|string $paths The PSR-4 base directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
// Register directories for the root namespace.
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->fallbackDirsPsr4
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$this->fallbackDirsPsr4,
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||||
|
// Register directories for a new namespace.
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
} elseif ($prepend) {
|
||||||
|
// Prepend directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->prefixDirsPsr4[$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Append directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$this->prefixDirsPsr4[$prefix],
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix,
|
||||||
|
* replacing any others previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param array|string $paths The PSR-0 base directories
|
||||||
|
*/
|
||||||
|
public function set($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr0 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace,
|
||||||
|
* replacing any others previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param array|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setPsr4($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr4 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on searching the include path for class files.
|
||||||
|
*
|
||||||
|
* @param bool $useIncludePath
|
||||||
|
*/
|
||||||
|
public function setUseIncludePath($useIncludePath)
|
||||||
|
{
|
||||||
|
$this->useIncludePath = $useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to check if the autoloader uses the include path to check
|
||||||
|
* for classes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUseIncludePath()
|
||||||
|
{
|
||||||
|
return $this->useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||||
|
*
|
||||||
|
* @param string|null $apcuPrefix
|
||||||
|
*/
|
||||||
|
public function setApcuPrefix($apcuPrefix)
|
||||||
|
{
|
||||||
|
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApcuPrefix()
|
||||||
|
{
|
||||||
|
return $this->apcuPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @param bool $prepend Whether to prepend the autoloader or not
|
||||||
|
*/
|
||||||
|
public function register($prepend = false)
|
||||||
|
{
|
||||||
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
|
||||||
|
if (null === $this->vendorDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prepend) {
|
||||||
|
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||||
|
} else {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this instance as an autoloader.
|
||||||
|
*/
|
||||||
|
public function unregister()
|
||||||
|
{
|
||||||
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
|
||||||
|
if (null !== $this->vendorDir) {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class or interface.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
* @return true|null True if loaded, null otherwise
|
||||||
|
*/
|
||||||
|
public function loadClass($class)
|
||||||
|
{
|
||||||
|
if ($file = $this->findFile($class)) {
|
||||||
|
includeFile($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the path to the file where the class is defined.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
*
|
||||||
|
* @return string|false The path if found, false otherwise
|
||||||
|
*/
|
||||||
|
public function findFile($class)
|
||||||
|
{
|
||||||
|
// class map lookup
|
||||||
|
if (isset($this->classMap[$class])) {
|
||||||
|
return $this->classMap[$class];
|
||||||
|
}
|
||||||
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||||
|
if ($hit) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
// Search for Hack files if we are running on HHVM
|
||||||
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
apcu_add($this->apcuPrefix.$class, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $file) {
|
||||||
|
// Remember that this class does not exist.
|
||||||
|
$this->missingClasses[$class] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
||||||
|
*
|
||||||
|
* @return self[]
|
||||||
|
*/
|
||||||
|
public static function getRegisteredLoaders()
|
||||||
|
{
|
||||||
|
return self::$registeredLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findFileWithExtension($class, $ext)
|
||||||
|
{
|
||||||
|
// PSR-4 lookup
|
||||||
|
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
|
||||||
|
$first = $class[0];
|
||||||
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
|
$subPath = $class;
|
||||||
|
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||||
|
$subPath = substr($subPath, 0, $lastPos);
|
||||||
|
$search = $subPath . '\\';
|
||||||
|
if (isset($this->prefixDirsPsr4[$search])) {
|
||||||
|
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||||
|
if (file_exists($file = $dir . $pathEnd)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-4 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 lookup
|
||||||
|
if (false !== $pos = strrpos($class, '\\')) {
|
||||||
|
// namespaced class name
|
||||||
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||||
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||||
|
} else {
|
||||||
|
// PEAR-like class name
|
||||||
|
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->prefixesPsr0[$first])) {
|
||||||
|
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||||
|
if (0 === strpos($class, $prefix)) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 include paths.
|
||||||
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope isolated include.
|
||||||
|
*
|
||||||
|
* Prevents access to $this/self from included files.
|
||||||
|
*/
|
||||||
|
function includeFile($file)
|
||||||
|
{
|
||||||
|
include $file;
|
||||||
|
}
|
337
app/composer/composer/InstalledVersions.php
Normal file
337
app/composer/composer/InstalledVersions.php
Normal file
|
@ -0,0 +1,337 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer;
|
||||||
|
|
||||||
|
use Composer\Autoload\ClassLoader;
|
||||||
|
use Composer\Semver\VersionParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is copied in every Composer installed project and available to all
|
||||||
|
*
|
||||||
|
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||||
|
*
|
||||||
|
* To require it's presence, you can require `composer-runtime-api ^2.0`
|
||||||
|
*/
|
||||||
|
class InstalledVersions
|
||||||
|
{
|
||||||
|
private static $installed;
|
||||||
|
private static $canGetVendors;
|
||||||
|
private static $installedByVendor = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackages()
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
$packages[] = array_keys($installed['versions']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 === \count($packages)) {
|
||||||
|
return $packages[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names with a specific type e.g. 'library'
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackagesByType($type)
|
||||||
|
{
|
||||||
|
$packagesByType = array();
|
||||||
|
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
foreach ($installed['versions'] as $name => $package) {
|
||||||
|
if (isset($package['type']) && $package['type'] === $type) {
|
||||||
|
$packagesByType[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packagesByType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package is installed
|
||||||
|
*
|
||||||
|
* This also returns true if the package name is provided or replaced by another package
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @param bool $includeDevRequirements
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (isset($installed['versions'][$packageName])) {
|
||||||
|
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package satisfies a version constraint
|
||||||
|
*
|
||||||
|
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||||
|
*
|
||||||
|
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||||
|
*
|
||||||
|
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||||
|
* @param string $packageName
|
||||||
|
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||||
|
{
|
||||||
|
$constraint = $parser->parseConstraints($constraint);
|
||||||
|
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||||
|
|
||||||
|
return $provided->matches($constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||||
|
*
|
||||||
|
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||||
|
* whether a given version of a package is installed, and not just whether it exists
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string Version constraint usable with composer/semver
|
||||||
|
*/
|
||||||
|
public static function getVersionRanges($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ranges = array();
|
||||||
|
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(' || ', $ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getPrettyVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||||
|
*/
|
||||||
|
public static function getReference($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['reference'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||||
|
*/
|
||||||
|
public static function getInstallPath($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
|
||||||
|
*/
|
||||||
|
public static function getRootPackage()
|
||||||
|
{
|
||||||
|
$installed = self::getInstalled();
|
||||||
|
|
||||||
|
return $installed[0]['root'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw installed.php data for custom implementations
|
||||||
|
*
|
||||||
|
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}
|
||||||
|
*/
|
||||||
|
public static function getRawData()
|
||||||
|
{
|
||||||
|
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
self::$installed = include __DIR__ . '/installed.php';
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||||
|
*
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
|
||||||
|
*/
|
||||||
|
public static function getAllRawData()
|
||||||
|
{
|
||||||
|
return self::getInstalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lets you reload the static array from another file
|
||||||
|
*
|
||||||
|
* This is only useful for complex integrations in which a project needs to use
|
||||||
|
* this class but then also needs to execute another project's autoloader in process,
|
||||||
|
* and wants to ensure both projects have access to their version of installed.php.
|
||||||
|
*
|
||||||
|
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||||
|
* the data it needs from this class, then call reload() with
|
||||||
|
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||||
|
* the project in which it runs can then also use this class safely, without
|
||||||
|
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||||
|
*
|
||||||
|
* @param array[] $data A vendor/composer/installed.php data set
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data
|
||||||
|
*/
|
||||||
|
public static function reload($data)
|
||||||
|
{
|
||||||
|
self::$installed = $data;
|
||||||
|
self::$installedByVendor = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
|
||||||
|
*/
|
||||||
|
private static function getInstalled()
|
||||||
|
{
|
||||||
|
if (null === self::$canGetVendors) {
|
||||||
|
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed = array();
|
||||||
|
|
||||||
|
if (self::$canGetVendors) {
|
||||||
|
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||||
|
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir];
|
||||||
|
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
|
||||||
|
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||||
|
self::$installed = $installed[count($installed) - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
self::$installed = require __DIR__ . '/installed.php';
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$installed[] = self::$installed;
|
||||||
|
|
||||||
|
return $installed;
|
||||||
|
}
|
||||||
|
}
|
21
app/composer/composer/LICENSE
Normal file
21
app/composer/composer/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
11
app/composer/composer/autoload_classmap.php
Normal file
11
app/composer/composer/autoload_classmap.php
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = $vendorDir;
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||||
|
'OCA\\AllInOne\\Settings\\Admin' => $baseDir . '/../lib/Settings/Admin.php',
|
||||||
|
);
|
9
app/composer/composer/autoload_namespaces.php
Normal file
9
app/composer/composer/autoload_namespaces.php
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_namespaces.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = $vendorDir;
|
||||||
|
|
||||||
|
return array(
|
||||||
|
);
|
10
app/composer/composer/autoload_psr4.php
Normal file
10
app/composer/composer/autoload_psr4.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = $vendorDir;
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'OCA\\AllInOne\\' => array($baseDir . '/../lib'),
|
||||||
|
);
|
46
app/composer/composer/autoload_real.php
Normal file
46
app/composer/composer/autoload_real.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_real.php @generated by Composer
|
||||||
|
|
||||||
|
class ComposerAutoloaderInitAllInOne
|
||||||
|
{
|
||||||
|
private static $loader;
|
||||||
|
|
||||||
|
public static function loadClassLoader($class)
|
||||||
|
{
|
||||||
|
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||||
|
require __DIR__ . '/ClassLoader.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Composer\Autoload\ClassLoader
|
||||||
|
*/
|
||||||
|
public static function getLoader()
|
||||||
|
{
|
||||||
|
if (null !== self::$loader) {
|
||||||
|
return self::$loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
spl_autoload_register(array('ComposerAutoloaderInitAllInOne', 'loadClassLoader'), true, true);
|
||||||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||||
|
spl_autoload_unregister(array('ComposerAutoloaderInitAllInOne', 'loadClassLoader'));
|
||||||
|
|
||||||
|
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||||
|
if ($useStaticLoader) {
|
||||||
|
require __DIR__ . '/autoload_static.php';
|
||||||
|
|
||||||
|
call_user_func(\Composer\Autoload\ComposerStaticInitAllInOne::getInitializer($loader));
|
||||||
|
} else {
|
||||||
|
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||||
|
if ($classMap) {
|
||||||
|
$loader->addClassMap($classMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$loader->setClassMapAuthoritative(true);
|
||||||
|
$loader->register(true);
|
||||||
|
|
||||||
|
return $loader;
|
||||||
|
}
|
||||||
|
}
|
37
app/composer/composer/autoload_static.php
Normal file
37
app/composer/composer/autoload_static.php
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_static.php @generated by Composer
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
class ComposerStaticInitAllInOne
|
||||||
|
{
|
||||||
|
public static $prefixLengthsPsr4 = array (
|
||||||
|
'O' =>
|
||||||
|
array (
|
||||||
|
'OCA\\AllInOne\\' => 13,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixDirsPsr4 = array (
|
||||||
|
'OCA\\AllInOne\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/../lib',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $classMap = array (
|
||||||
|
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||||
|
'OCA\\AllInOne\\Settings\\Admin' => __DIR__ . '/..' . '/../lib/Settings/Admin.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
{
|
||||||
|
return \Closure::bind(function () use ($loader) {
|
||||||
|
$loader->prefixLengthsPsr4 = ComposerStaticInitAllInOne::$prefixLengthsPsr4;
|
||||||
|
$loader->prefixDirsPsr4 = ComposerStaticInitAllInOne::$prefixDirsPsr4;
|
||||||
|
$loader->classMap = ComposerStaticInitAllInOne::$classMap;
|
||||||
|
|
||||||
|
}, null, ClassLoader::class);
|
||||||
|
}
|
||||||
|
}
|
5
app/composer/composer/installed.json
Normal file
5
app/composer/composer/installed.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"packages": [],
|
||||||
|
"dev": true,
|
||||||
|
"dev-package-names": []
|
||||||
|
}
|
23
app/composer/composer/installed.php
Normal file
23
app/composer/composer/installed.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?php return array(
|
||||||
|
'root' => array(
|
||||||
|
'pretty_version' => 'dev-master',
|
||||||
|
'version' => 'dev-master',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'reference' => '1b16a136ebd8f63e09df061d383f34170e2cef35',
|
||||||
|
'name' => '__root__',
|
||||||
|
'dev' => true,
|
||||||
|
),
|
||||||
|
'versions' => array(
|
||||||
|
'__root__' => array(
|
||||||
|
'pretty_version' => 'dev-master',
|
||||||
|
'version' => 'dev-master',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'reference' => '1b16a136ebd8f63e09df061d383f34170e2cef35',
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
83
app/lib/Settings/Admin.php
Normal file
83
app/lib/Settings/Admin.php
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2021, Azul <azul@riseup.net>
|
||||||
|
*
|
||||||
|
* @author Azul <azul@riseup.net>
|
||||||
|
*
|
||||||
|
* @license AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\AllInOne\Settings;
|
||||||
|
|
||||||
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use OCP\IDateTimeFormatter;
|
||||||
|
use OCP\L10N\IFactory;
|
||||||
|
use OCP\Settings\ISettings;
|
||||||
|
|
||||||
|
class Admin implements ISettings {
|
||||||
|
/** @var IConfig */
|
||||||
|
private $config;
|
||||||
|
/** @var IDateTimeFormatter */
|
||||||
|
private $dateTimeFormatter;
|
||||||
|
/** @var IFactory */
|
||||||
|
private $l10nFactory;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
IConfig $config,
|
||||||
|
IDateTimeFormatter $dateTimeFormatter,
|
||||||
|
IFactory $l10nFactory
|
||||||
|
) {
|
||||||
|
$this->config = $config;
|
||||||
|
$this->dateTimeFormatter = $dateTimeFormatter;
|
||||||
|
$this->l10nFactory = $l10nFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TemplateResponse
|
||||||
|
*/
|
||||||
|
public function getForm(): TemplateResponse {
|
||||||
|
$lastUpdateCheckTimestamp = $this->config->getAppValue('core', 'lastupdatedat');
|
||||||
|
$lastUpdateCheck = $this->dateTimeFormatter->formatDateTime($lastUpdateCheckTimestamp);
|
||||||
|
|
||||||
|
$token = urlencode(getenv('AIO_TOKEN'));
|
||||||
|
$params = [
|
||||||
|
'AIOLoginUrl' => 'https://' . getenv('AIO_URL') . '/api/auth/getlogin' . '?token=' . $token,
|
||||||
|
];
|
||||||
|
|
||||||
|
return new TemplateResponse('nextcloud-aio', 'admin', $params, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string the section ID, e.g. 'sharing'
|
||||||
|
*/
|
||||||
|
public function getSection(): string {
|
||||||
|
return 'overview';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int whether the form should be rather on the top or bottom of
|
||||||
|
* the admin section. The forms are arranged in ascending order of the
|
||||||
|
* priority values. It is required to return a value between 0 and 100.
|
||||||
|
*
|
||||||
|
* E.g.: 70
|
||||||
|
*/
|
||||||
|
public function getPriority(): int {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
7
app/readme.md
Normal file
7
app/readme.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
## How to develope the app?
|
||||||
|
|
||||||
|
Please note that in order to check if an app is already downloaded
|
||||||
|
Nextcloud will look for a folder with the same name as the app.
|
||||||
|
|
||||||
|
Therefore you need to add the app to one of the app directories
|
||||||
|
naming the directory `docker-aio`.
|
15
app/templates/admin.php
Normal file
15
app/templates/admin.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright (c) 2021 Azul <azul@riseup.net>
|
||||||
|
*
|
||||||
|
* @author Azul <azul@riseup.net>
|
||||||
|
*
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later. See the COPYING file.
|
||||||
|
*/
|
||||||
|
/** @var array $_ */ ?>
|
||||||
|
<div id="allinone" class="section">
|
||||||
|
<h2><?php p($l->t('Nextcloud All In One'));?></h2>
|
||||||
|
<a href="<?php p($_['AIOLoginUrl']);?>" class="button" target="_blank" rel="noopener">Open Nextcloud AIO Interface ↗</a>
|
||||||
|
</div>
|
40
develop.md
Normal file
40
develop.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
## Developer channel
|
||||||
|
If you want to switch to the develop channel, you simply stop and delete the mastercontainer and create a new one with a changed tag to develop:
|
||||||
|
```shell
|
||||||
|
sudo docker run -it \
|
||||||
|
--name nextcloud-aio-mastercontainer \
|
||||||
|
--restart always \
|
||||||
|
-p 80:80 \
|
||||||
|
-p 8080:8080 \
|
||||||
|
-p 8443:8443 \
|
||||||
|
--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||||
|
nextcloud/all-in-one:develop
|
||||||
|
```
|
||||||
|
And you are done :)
|
||||||
|
It will now also select the developer channel for all other containers automatically.
|
||||||
|
|
||||||
|
## How to promote builds from develop to latest
|
||||||
|
|
||||||
|
You can use the Docker CLI to promote builds from develop to latest. Make sure to adjust:
|
||||||
|
|
||||||
|
- $name
|
||||||
|
- $digest
|
||||||
|
|
||||||
|
```shell
|
||||||
|
export AIO_NAME=$name
|
||||||
|
export AIO_DIGEST=$digest
|
||||||
|
docker pull nextcloud/$AIO_NAME@sha256:$AIO_DIGEST
|
||||||
|
docker tag nextcloud/$AIO_NAME@sha256:$AIO_DIGEST nextcloud/$AIO_NAME\:latest
|
||||||
|
docker push nextcloud/$AIO_NAME\:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
To automatically promoted the latest develop version you can use the following script:
|
||||||
|
|
||||||
|
**WARNING:** Make sure to verify that the latest develop tag is what you really want to deploy since someone could have pushed to main and created a new container in between.
|
||||||
|
```shell
|
||||||
|
export AIO_NAME=$name
|
||||||
|
docker pull nextcloud/$AIO_NAME\:develop
|
||||||
|
docker tag nextcloud/$AIO_NAME\:develop nextcloud/$AIO_NAME\:latest
|
||||||
|
docker push nextcloud/$AIO_NAME\:latest
|
||||||
|
```
|
3
php/.gitignore
vendored
Normal file
3
php/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/php/data/configuration.json
|
||||||
|
/php/data/containers.json
|
||||||
|
|
8
php/.idea/.gitignore
vendored
Normal file
8
php/.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
34
php/.idea/aio.iml
Normal file
34
php/.idea/aio.iml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="AIO\" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-server-middleware" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/psr7" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/guzzle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-client" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-message" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/promises" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-factory" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/http-interop/http-factory-guzzle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-server-handler" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/slim/slim" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/ralouphie/getallheaders" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/fast-route" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/opis/closure" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/php-di/slim-bridge" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/php-di/invoker" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/php-di/php-di" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/php-di/phpdoc-reader" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/slim/twig-view" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-ctype" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
8
php/.idea/modules.xml
Normal file
8
php/.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/aio.iml" filepath="$PROJECT_DIR$/.idea/aio.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
34
php/.idea/php.xml
Normal file
34
php/.idea/php.xml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PhpIncludePathManager">
|
||||||
|
<include_path>
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/http-server-middleware" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/guzzlehttp/guzzle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/http-client" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/http-message" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/guzzlehttp/promises" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/http-factory" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/http-interop/http-factory-guzzle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/http-server-handler" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/slim/slim" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/ralouphie/getallheaders" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/nikic/fast-route" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/opis/closure" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/php-di/slim-bridge" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/php-di/invoker" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/php-di/php-di" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/php-di/phpdoc-reader" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/slim/twig-view" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/twig/twig" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
|
||||||
|
</include_path>
|
||||||
|
</component>
|
||||||
|
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
|
||||||
|
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
php/.idea/vcs.xml
Normal file
6
php/.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
15
php/README.md
Normal file
15
php/README.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# PHP Docker Controller
|
||||||
|
|
||||||
|
This is the code for the PHP Docker controller.
|
||||||
|
|
||||||
|
## How to run
|
||||||
|
|
||||||
|
Running this locally requires Docker Engine on the same machine.
|
||||||
|
If this is the case, just execute the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd public/
|
||||||
|
php -S 0.0.0.0:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then access the web interface at `localhost:8080`.
|
20
php/composer.json
Normal file
20
php/composer.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"AIO\\": ["src/"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-sodium": "*",
|
||||||
|
"ext-curl": "*",
|
||||||
|
"slim/slim": "4.*",
|
||||||
|
"php-di/slim-bridge": "^3.1",
|
||||||
|
"guzzlehttp/guzzle": "^7.3",
|
||||||
|
"guzzlehttp/psr7": "^1.8",
|
||||||
|
"http-interop/http-factory-guzzle": "^1.2",
|
||||||
|
"slim/twig-view": "^3.2",
|
||||||
|
"slim/csrf": "^1.2",
|
||||||
|
"ext-apcu": "*"
|
||||||
|
}
|
||||||
|
}
|
1529
php/composer.lock
generated
Normal file
1529
php/composer.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
288
php/containers.json
Normal file
288
php/containers.json
Normal file
|
@ -0,0 +1,288 @@
|
||||||
|
{
|
||||||
|
"production": [
|
||||||
|
{
|
||||||
|
"dependsOn": [
|
||||||
|
"nextcloud-aio-nextcloud",
|
||||||
|
"nextcloud-aio-collabora",
|
||||||
|
"nextcloud-aio-talk"
|
||||||
|
],
|
||||||
|
"identifier": "nextcloud-aio-apache",
|
||||||
|
"displayName": "Apache",
|
||||||
|
"containerName": "nextcloud/aio-apache",
|
||||||
|
"ports": [
|
||||||
|
"443/tcp"
|
||||||
|
],
|
||||||
|
"internalPorts": [
|
||||||
|
"443"
|
||||||
|
],
|
||||||
|
"secrets": [],
|
||||||
|
"environmentVariables": [
|
||||||
|
"NC_DOMAIN=%NC_DOMAIN%",
|
||||||
|
"NEXTCLOUD_HOST=nextcloud-aio-nextcloud",
|
||||||
|
"COLLABORA_HOST=nextcloud-aio-collabora",
|
||||||
|
"TALK_HOST=nextcloud-aio-talk"
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_nextcloud",
|
||||||
|
"location": "/var/www/html",
|
||||||
|
"writeable": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_apache",
|
||||||
|
"location": "/mnt/data",
|
||||||
|
"writeable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"maxShutdownTime": 10,
|
||||||
|
"restartPolicy": "unless-stopped"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependsOn": [],
|
||||||
|
"identifier": "nextcloud-aio-database",
|
||||||
|
"displayName": "Database",
|
||||||
|
"containerName": "nextcloud/aio-postgresql",
|
||||||
|
"ports": [],
|
||||||
|
"internalPorts": [
|
||||||
|
"5432"
|
||||||
|
],
|
||||||
|
"secrets": [
|
||||||
|
"DATABASE_PASSWORD"
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_database",
|
||||||
|
"location": "/var/lib/postgresql/data",
|
||||||
|
"writeable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_database_dump",
|
||||||
|
"location": "/mnt/data",
|
||||||
|
"writeable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"environmentVariables": [
|
||||||
|
"POSTGRES_PASSWORD=%DATABASE_PASSWORD%",
|
||||||
|
"POSTGRES_DB=nextcloud_database",
|
||||||
|
"POSTGRES_USER=nextcloud"
|
||||||
|
],
|
||||||
|
"maxShutdownTime": 1800,
|
||||||
|
"restartPolicy": "unless-stopped"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependsOn": [
|
||||||
|
"nextcloud-aio-database",
|
||||||
|
"nextcloud-aio-redis"
|
||||||
|
],
|
||||||
|
"identifier": "nextcloud-aio-nextcloud",
|
||||||
|
"displayName": "Nextcloud",
|
||||||
|
"containerName": "nextcloud/aio-nextcloud",
|
||||||
|
"ports": [],
|
||||||
|
"internalPorts": [
|
||||||
|
"9000"
|
||||||
|
],
|
||||||
|
"secrets": [
|
||||||
|
"DATABASE_PASSWORD",
|
||||||
|
"REDIS_PASSWORD",
|
||||||
|
"NEXTCLOUD_PASSWORD",
|
||||||
|
"TURN_SECRET",
|
||||||
|
"SIGNALING_SECRET"
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_nextcloud",
|
||||||
|
"location": "/var/www/html",
|
||||||
|
"writeable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_nextcloud_data",
|
||||||
|
"location": "/mnt/ncdata",
|
||||||
|
"writeable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"environmentVariables": [
|
||||||
|
"POSTGRES_HOST=nextcloud-aio-database",
|
||||||
|
"POSTGRES_PASSWORD=%DATABASE_PASSWORD%",
|
||||||
|
"POSTGRES_DB=nextcloud_database",
|
||||||
|
"POSTGRES_USER=nextcloud",
|
||||||
|
"REDIS_HOST=nextcloud-aio-redis",
|
||||||
|
"REDIS_HOST_PASSWORD=%REDIS_PASSWORD%",
|
||||||
|
"AIO_TOKEN=%AIO_TOKEN%",
|
||||||
|
"NC_DOMAIN=%NC_DOMAIN%",
|
||||||
|
"ADMIN_USER=admin",
|
||||||
|
"ADMIN_PASSWORD=%NEXTCLOUD_PASSWORD%",
|
||||||
|
"NEXTCLOUD_DATA_DIR=/mnt/ncdata",
|
||||||
|
"OVERWRITEHOST=%NC_DOMAIN%",
|
||||||
|
"OVERWRITEPROTOCOL=https",
|
||||||
|
"TRUSTED_PROXIES=127.0.0.1",
|
||||||
|
"TURN_SECRET=%TURN_SECRET%",
|
||||||
|
"SIGNALING_SECRET=%SIGNALING_SECRET%",
|
||||||
|
"AIO_URL=%AIO_URL%"
|
||||||
|
],
|
||||||
|
"maxShutdownTime": 10,
|
||||||
|
"restartPolicy": "unless-stopped"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependsOn": [],
|
||||||
|
"identifier": "nextcloud-aio-redis",
|
||||||
|
"displayName": "Redis",
|
||||||
|
"containerName": "nextcloud/aio-redis",
|
||||||
|
"ports": [],
|
||||||
|
"internalPorts": [
|
||||||
|
"6379"
|
||||||
|
],
|
||||||
|
"environmentVariables": [
|
||||||
|
"REDIS_HOST_PASSWORD=%REDIS_PASSWORD%"
|
||||||
|
],
|
||||||
|
"volumes": [],
|
||||||
|
"secrets": [
|
||||||
|
"REDIS_PASSWORD"
|
||||||
|
],
|
||||||
|
"maxShutdownTime": 10,
|
||||||
|
"restartPolicy": "unless-stopped"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependsOn": [],
|
||||||
|
"identifier": "nextcloud-aio-collabora",
|
||||||
|
"displayName": "Collabora",
|
||||||
|
"containerName": "nextcloud/aio-collabora",
|
||||||
|
"ports": [],
|
||||||
|
"internalPorts": [
|
||||||
|
"9980"
|
||||||
|
],
|
||||||
|
"environmentVariables": [
|
||||||
|
"domain=%NC_DOMAIN%"
|
||||||
|
],
|
||||||
|
"volumes": [],
|
||||||
|
"secrets": [],
|
||||||
|
"maxShutdownTime": 10,
|
||||||
|
"restartPolicy": "unless-stopped"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependsOn": [],
|
||||||
|
"identifier": "nextcloud-aio-talk",
|
||||||
|
"displayName": "Talk",
|
||||||
|
"containerName": "nextcloud/aio-talk",
|
||||||
|
"ports": [
|
||||||
|
"3478/tcp",
|
||||||
|
"3478/udp"
|
||||||
|
],
|
||||||
|
"internalPorts": [
|
||||||
|
"3478"
|
||||||
|
],
|
||||||
|
"environmentVariables": [
|
||||||
|
"NC_DOMAIN=%NC_DOMAIN%",
|
||||||
|
"TURN_SECRET=%TURN_SECRET%",
|
||||||
|
"SIGNALING_SECRET=%SIGNALING_SECRET%",
|
||||||
|
"JANUS_API_KEY=%JANUS_API_KEY%"
|
||||||
|
],
|
||||||
|
"volumes": [],
|
||||||
|
"secrets": [
|
||||||
|
"TURN_SECRET",
|
||||||
|
"SIGNALING_SECRET",
|
||||||
|
"JANUS_API_KEY"
|
||||||
|
],
|
||||||
|
"maxShutdownTime": 10,
|
||||||
|
"restartPolicy": "unless-stopped"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependsOn": [],
|
||||||
|
"identifier": "nextcloud-aio-borgbackup",
|
||||||
|
"displayName": "Borgbackup",
|
||||||
|
"containerName": "nextcloud/aio-borgbackup",
|
||||||
|
"ports": [],
|
||||||
|
"internalPorts": [],
|
||||||
|
"environmentVariables": [
|
||||||
|
"BORG_PASSWORD=%BORGBACKUP_PASSWORD%",
|
||||||
|
"BORG_MODE=%BORGBACKUP_MODE%"
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_backup_cache",
|
||||||
|
"location": "/root",
|
||||||
|
"writeable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_nextcloud",
|
||||||
|
"location": "/nextcloud_aio_volumes/nextcloud_aio_nextcloud",
|
||||||
|
"writeable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_nextcloud_data",
|
||||||
|
"location": "/nextcloud_aio_volumes/nextcloud_aio_nextcloud_data",
|
||||||
|
"writeable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_database",
|
||||||
|
"location": "/nextcloud_aio_volumes/nextcloud_aio_database",
|
||||||
|
"writeable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_database_dump",
|
||||||
|
"location": "/nextcloud_aio_volumes/nextcloud_aio_database_dump",
|
||||||
|
"writeable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_apache",
|
||||||
|
"location": "/nextcloud_aio_volumes/nextcloud_aio_apache",
|
||||||
|
"writeable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nextcloud_aio_mastercontainer",
|
||||||
|
"location": "/nextcloud_aio_volumes/nextcloud_aio_mastercontainer",
|
||||||
|
"writeable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "%BORGBACKUP_HOST_LOCATION%",
|
||||||
|
"location": "/mnt/borgbackup",
|
||||||
|
"writeable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"secrets": [
|
||||||
|
"BORGBACKUP_PASSWORD"
|
||||||
|
],
|
||||||
|
"maxShutdownTime": 10,
|
||||||
|
"restartPolicy": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependsOn": [],
|
||||||
|
"identifier": "nextcloud-aio-watchtower",
|
||||||
|
"displayName": "Watchtower",
|
||||||
|
"containerName": "nextcloud/aio-watchtower",
|
||||||
|
"ports": [],
|
||||||
|
"internalPorts": [],
|
||||||
|
"environmentVariables": [
|
||||||
|
"CONTAINER_TO_UPDATE=nextcloud-aio-mastercontainer"
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "/var/run/docker.sock",
|
||||||
|
"location": "/var/run/docker.sock",
|
||||||
|
"writeable": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"secrets": [],
|
||||||
|
"maxShutdownTime": 10,
|
||||||
|
"restartPolicy": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependsOn": [],
|
||||||
|
"identifier": "nextcloud-aio-domaincheck",
|
||||||
|
"displayName": "Domaincheck",
|
||||||
|
"containerName": "nextcloud/aio-domaincheck",
|
||||||
|
"ports": [
|
||||||
|
"443/tcp"
|
||||||
|
],
|
||||||
|
"internalPorts": [],
|
||||||
|
"environmentVariables": [
|
||||||
|
"INSTANCE_ID=%INSTANCE_ID%"
|
||||||
|
],
|
||||||
|
"volumes": [],
|
||||||
|
"secrets": [
|
||||||
|
"INSTANCE_ID"
|
||||||
|
],
|
||||||
|
"maxShutdownTime": 1,
|
||||||
|
"restartPolicy": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
0
php/data/.gitkeep
Normal file
0
php/data/.gitkeep
Normal file
1
php/public/.well-known/aio.txt
Normal file
1
php/public/.well-known/aio.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
I_AM_HERE
|
79
php/public/forms.js
Normal file
79
php/public/forms.js
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
"use strict";
|
||||||
|
(function (){
|
||||||
|
var lastError;
|
||||||
|
|
||||||
|
function showError(message) {
|
||||||
|
const body = document.getElementsByTagName('body')[0]
|
||||||
|
const toast = document.createElement("div")
|
||||||
|
toast.className = "toast error"
|
||||||
|
toast.prepend(message)
|
||||||
|
if (lastError) {
|
||||||
|
lastError.remove()
|
||||||
|
}
|
||||||
|
lastError = toast
|
||||||
|
body.prepend(toast)
|
||||||
|
setTimeout(toast.remove.bind(toast), 3000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleEvent(e) {
|
||||||
|
const xhr = e.target;
|
||||||
|
if (xhr.status === 201) {
|
||||||
|
window.location.replace(xhr.getResponseHeader('Location'));
|
||||||
|
}
|
||||||
|
if (xhr.status === 422) {
|
||||||
|
showError(xhr.response);
|
||||||
|
}
|
||||||
|
if (xhr.status === 500) {
|
||||||
|
showError("Server error. Please see the logs for details.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function disable(element) {
|
||||||
|
document.getElementById('overlay').classList.add('loading');
|
||||||
|
element.classList.add('loading');
|
||||||
|
element.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function enable(element) {
|
||||||
|
document.getElementById('overlay').classList.remove('loading');
|
||||||
|
element.classList.remove('loading');
|
||||||
|
element.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initForm(form) {
|
||||||
|
function submit(event)
|
||||||
|
{
|
||||||
|
if (lastError) {
|
||||||
|
lastError.remove()
|
||||||
|
}
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.addEventListener('load', handleEvent);
|
||||||
|
xhr.addEventListener('error', () => showError("Failed to talk to server."));
|
||||||
|
xhr.addEventListener('load', () => enable(event.submitter));
|
||||||
|
xhr.addEventListener('error', () => enable(event.submitter));
|
||||||
|
xhr.open(form.method, form.getAttribute("action"));
|
||||||
|
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||||
|
disable(event.submitter);
|
||||||
|
xhr.send(new URLSearchParams(new FormData(form)));
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
form.onsubmit = submit;
|
||||||
|
console.info(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initForms() {
|
||||||
|
const forms = document.querySelectorAll('form.xhr')
|
||||||
|
console.info("Making " + forms.length + " form(s) use XHR.");
|
||||||
|
for (const form of forms) {
|
||||||
|
initForm(form);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
// Loading hasn't finished yet
|
||||||
|
document.addEventListener('DOMContentLoaded', initForms);
|
||||||
|
} else { // `DOMContentLoaded` has already fired
|
||||||
|
initForms();
|
||||||
|
}
|
||||||
|
})()
|
BIN
php/public/img/background.png
Normal file
BIN
php/public/img/background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
BIN
php/public/img/favicon.png
Normal file
BIN
php/public/img/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 88 KiB |
3
php/public/img/logo-blue.svg
Normal file
3
php/public/img/logo-blue.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 10 KiB |
1
php/public/img/logo.svg
Normal file
1
php/public/img/logo.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg width="256" height="128" version="1.1" viewBox="0 0 256 128" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke-width="22"><circle cx="40" cy="64" r="26" stroke="#ffffff" fill="none"/><circle cx="216" cy="64" r="26" stroke="#ffffff" fill="none"/><circle cx="128" cy="64" r="46" stroke="#ffffff" fill="none"/></g></svg>
|
After Width: | Height: | Size: 330 B |
140
php/public/index.php
Normal file
140
php/public/index.php
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
// increase memory limit to 2GB
|
||||||
|
ini_set('memory_limit', '2048M');
|
||||||
|
|
||||||
|
// set max execution time to 2h just in case of a very slow internet connection
|
||||||
|
ini_set('max_execution_time', '7200');
|
||||||
|
|
||||||
|
use DI\Container;
|
||||||
|
use Slim\Csrf\Guard;
|
||||||
|
use Slim\Factory\AppFactory;
|
||||||
|
use Slim\Views\Twig;
|
||||||
|
use Slim\Views\TwigMiddleware;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$container = \AIO\DependencyInjection::GetContainer();
|
||||||
|
$dataConst = $container->get(\AIO\Data\DataConst::class);
|
||||||
|
ini_set('session.save_path', $dataConst->GetSessionDirectory());
|
||||||
|
|
||||||
|
// Auto logout on browser close
|
||||||
|
ini_set('session.cookie_lifetime', '0');
|
||||||
|
|
||||||
|
// Make sure to delete all stale sessions after at least one day
|
||||||
|
ini_set('session.gc_maxlifetime', '86400');
|
||||||
|
ini_set('session.gc_probability', '1');
|
||||||
|
ini_set('session.gc_divisor', '1');
|
||||||
|
|
||||||
|
// Create app
|
||||||
|
AppFactory::setContainer($container);
|
||||||
|
$app = AppFactory::create();
|
||||||
|
$responseFactory = $app->getResponseFactory();
|
||||||
|
|
||||||
|
// Register Middleware On Container
|
||||||
|
$container->set(Guard::class, function () use ($responseFactory) {
|
||||||
|
$guard = new Guard($responseFactory);
|
||||||
|
$guard->setPersistentTokenMode(true);
|
||||||
|
return $guard;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register Middleware To Be Executed On All Routes
|
||||||
|
session_start();
|
||||||
|
$app->add(Guard::class);
|
||||||
|
|
||||||
|
// Create Twig
|
||||||
|
$twig = Twig::create(__DIR__ . '/../templates/', ['cache' => false]);
|
||||||
|
$app->add(TwigMiddleware::create($app, $twig));
|
||||||
|
$twig->addExtension(new \AIO\Twig\CsrfExtension($container->get(Guard::class)));
|
||||||
|
|
||||||
|
// Auth Middleware
|
||||||
|
$app->add(new \AIO\Middleware\AuthMiddleware($container->get(\AIO\Auth\AuthManager::class)));
|
||||||
|
|
||||||
|
// API
|
||||||
|
$app->post('/api/docker/watchtower', AIO\Controller\DockerController::class . ':StartWatchtowerContainer');
|
||||||
|
$app->post('/api/docker/start', AIO\Controller\DockerController::class . ':StartContainer');
|
||||||
|
$app->post('/api/docker/backup', AIO\Controller\DockerController::class . ':StartBackupContainerBackup');
|
||||||
|
$app->post('/api/docker/backup-check', AIO\Controller\DockerController::class . ':StartBackupContainerCheck');
|
||||||
|
$app->post('/api/docker/restore', AIO\Controller\DockerController::class . ':StartBackupContainerRestore');
|
||||||
|
$app->post('/api/docker/stop', AIO\Controller\DockerController::class . ':StopContainer');
|
||||||
|
$app->get('/api/docker/logs', AIO\Controller\DockerController::class . ':GetLogs');
|
||||||
|
$app->post('/api/auth/login', AIO\Controller\LoginController::class . ':TryLogin');
|
||||||
|
$app->get('/api/auth/getlogin', AIO\Controller\LoginController::class . ':GetTryLogin');
|
||||||
|
$app->post('/api/auth/logout', AIO\Controller\LoginController::class . ':Logout');
|
||||||
|
$app->post('/api/configuration', \AIO\Controller\ConfigurationController::class . ':SetConfig');
|
||||||
|
|
||||||
|
// Views
|
||||||
|
$app->get('/containers', function ($request, $response, $args) use ($container) {
|
||||||
|
$view = Twig::fromRequest($request);
|
||||||
|
/** @var \AIO\Data\ConfigurationManager $configurationManager */
|
||||||
|
$configurationManager = $container->get(\AIO\Data\ConfigurationManager::class);
|
||||||
|
$dockerActionManger = $container->get(\AIO\Docker\DockerActionManager::class);
|
||||||
|
$dockerActionManger->ConnectMasterContainerToNetwork();
|
||||||
|
$dockerController = $container->get(\AIO\Controller\DockerController::class);
|
||||||
|
$dockerController->StartDomaincheckContainer();
|
||||||
|
$view->addExtension(new \AIO\Twig\ClassExtension());
|
||||||
|
return $view->render($response, 'containers.twig', [
|
||||||
|
'domain' => $configurationManager->GetDomain(),
|
||||||
|
'borg_backup_host_location' => $configurationManager->GetBorgBackupHostLocation(),
|
||||||
|
'borg_backup_mode' => $configurationManager->GetBorgBackupMode(),
|
||||||
|
'nextcloud_password' => $configurationManager->GetSecret('NEXTCLOUD_PASSWORD'),
|
||||||
|
'containers' => (new \AIO\ContainerDefinitionFetcher($container->get(\AIO\Data\ConfigurationManager::class), $container))->FetchDefinition(),
|
||||||
|
'borgbackup_password' => $configurationManager->GetSecret('BORGBACKUP_PASSWORD'),
|
||||||
|
'is_mastercontainer_update_available' => $dockerActionManger->IsMastercontainerUpdateAvailable(),
|
||||||
|
'has_backup_run_once' => $configurationManager->hasBackupRunOnce(),
|
||||||
|
'backup_exit_code' => $dockerActionManger->GetBackupcontainerExitCode(),
|
||||||
|
'was_start_button_clicked' => $configurationManager->wasStartButtonClicked(),
|
||||||
|
'has_update_available' => $dockerActionManger->isAnyUpdateAvailable(),
|
||||||
|
'last_backup_time' => $configurationManager->GetLastBackupTime(),
|
||||||
|
]);
|
||||||
|
})->setName('profile');
|
||||||
|
$app->get('/login', function ($request, $response, $args) {
|
||||||
|
$view = Twig::fromRequest($request);
|
||||||
|
return $view->render($response, 'login.twig');
|
||||||
|
});
|
||||||
|
$app->get('/setup', function ($request, $response, $args) use ($container) {
|
||||||
|
$view = Twig::fromRequest($request);
|
||||||
|
/** @var \AIO\Data\Setup $setup */
|
||||||
|
$setup = $container->get(\AIO\Data\Setup::class);
|
||||||
|
|
||||||
|
if(!$setup->CanBeInstalled()) {
|
||||||
|
return $view->render(
|
||||||
|
$response,
|
||||||
|
'already-installed.twig'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $view->render(
|
||||||
|
$response,
|
||||||
|
'setup.twig',
|
||||||
|
[
|
||||||
|
'password' => $setup->Setup(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Auth Redirector
|
||||||
|
$app->get('/', function (\Psr\Http\Message\RequestInterface $request, \Psr\Http\Message\ResponseInterface $response, $args) use ($container) {
|
||||||
|
$authManager = $container->get(\AIO\Auth\AuthManager::class);
|
||||||
|
|
||||||
|
/** @var \AIO\Data\Setup $setup */
|
||||||
|
$setup = $container->get(\AIO\Data\Setup::class);
|
||||||
|
if($setup->CanBeInstalled()) {
|
||||||
|
return $response
|
||||||
|
->withHeader('Location', '/setup')
|
||||||
|
->withStatus(302);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($authManager->IsAuthenticated()) {
|
||||||
|
return $response
|
||||||
|
->withHeader('Location', '/containers')
|
||||||
|
->withStatus(302);
|
||||||
|
} else {
|
||||||
|
return $response
|
||||||
|
->withHeader('Location', '/login')
|
||||||
|
->withStatus(302);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$app->run();
|
206
php/public/style.css
Normal file
206
php/public/style.css
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
html, body {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Cantarell, Ubuntu, Helvetica Neue, Arial, Noto Color Emoji, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
padding: 6px 16px;
|
||||||
|
width: auto;
|
||||||
|
min-height: 34px;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color:#0082c9;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 100px;
|
||||||
|
margin: 3px 3px 3px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
color: white;
|
||||||
|
border: 1px solid black;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.error {
|
||||||
|
background-color: #e9322d;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.toast.error {
|
||||||
|
border-left-color: #e9322d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
display: inline-block;
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
vertical-align: text-bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
border-radius: 50%
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
span.success {
|
||||||
|
background-color: #46ba61;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.running {
|
||||||
|
background-color: rgb(255, 208, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.toast.success {
|
||||||
|
border-left-color: #46ba61;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.toast {
|
||||||
|
border-left: 3px solid;
|
||||||
|
right: 10px;
|
||||||
|
min-width: 200px;
|
||||||
|
box-shadow: 0 0 6px 0 rgba(77, 77, 77, 0.3);
|
||||||
|
padding: 12px;
|
||||||
|
margin-top: 45px;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: none;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login {
|
||||||
|
padding: 50px;
|
||||||
|
background-color: white;
|
||||||
|
width: 500px;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login > .monospace {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login > form > input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login > img {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login > .button {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 33px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #0082c9;
|
||||||
|
background-image: linear-gradient(
|
||||||
|
40deg
|
||||||
|
, #0082c9 0%, #30b6ff 100%);
|
||||||
|
background-size: contain;
|
||||||
|
background-image: url('/img/background.png'), linear-gradient(
|
||||||
|
40deg
|
||||||
|
, #0082c9 0%, #30b6ff 100%);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 20px;
|
||||||
|
max-width: 100%;
|
||||||
|
word-break: break-word;
|
||||||
|
max-width: 450px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
background-image: url('/img/logo.svg');
|
||||||
|
height: 50px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
display: inline-flex;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center center;
|
||||||
|
width: 62px;
|
||||||
|
position: absolute;
|
||||||
|
left: 12px;
|
||||||
|
top: 1px;
|
||||||
|
bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: #0082c9;
|
||||||
|
background-image: linear-gradient(40deg, #0082c9 0%, #30b6ff 100%);
|
||||||
|
height: 50px;
|
||||||
|
justify-content: space-between;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay {
|
||||||
|
position: fixed; /* Sit on top of the page content */
|
||||||
|
display: none; /* Hidden by default */
|
||||||
|
width: 100%; /* Full width (cover the whole page) */
|
||||||
|
height: 100%; /* Full height (cover the whole page) */
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: rgba(0,0,0,0.5); /* Black background with opacity */
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay.loading {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
border: 16px solid #f3f3f3;
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top: 16px solid #3498db;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
-webkit-animation: spin 2s linear infinite; /* Safari */
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(50% - 60px);
|
||||||
|
left: calc(50% - 60px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Safari */
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% { -webkit-transform: rotate(0deg); }
|
||||||
|
100% { -webkit-transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
0
php/session/.gitkeep
Normal file
0
php/session/.gitkeep
Normal file
1
php/session/sess_d8lq5p5ckura6e1dnda62i0it9
Normal file
1
php/session/sess_d8lq5p5ckura6e1dnda62i0it9
Normal file
|
@ -0,0 +1 @@
|
||||||
|
csrf|a:1:{s:17:"csrf61a4cf452d1d1";s:32:"aca558848ae342fdf00f078576fbf5cb";}aio_authenticated|b:1;
|
34
php/src/Auth/AuthManager.php
Normal file
34
php/src/Auth/AuthManager.php
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Auth;
|
||||||
|
|
||||||
|
use AIO\Data\ConfigurationManager;
|
||||||
|
|
||||||
|
class AuthManager {
|
||||||
|
private const SESSION_KEY = 'aio_authenticated';
|
||||||
|
private ConfigurationManager $configurationManager;
|
||||||
|
|
||||||
|
public function __construct(ConfigurationManager $configurationManager) {
|
||||||
|
$this->configurationManager = $configurationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function CheckCredentials(string $username, string $password) : bool {
|
||||||
|
if($username === $this->configurationManager->GetUserName()) {
|
||||||
|
return hash_equals($this->configurationManager->GetPassword(), $password);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function CheckToken(string $token) : bool {
|
||||||
|
return hash_equals($this->configurationManager->GetToken(), $token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function SetAuthState(bool $isLoggedIn) : void {
|
||||||
|
$_SESSION[self::SESSION_KEY] = $isLoggedIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function IsAuthenticated() : bool {
|
||||||
|
return isset($_SESSION[self::SESSION_KEY]) && $_SESSION[self::SESSION_KEY] === true;
|
||||||
|
}
|
||||||
|
}
|
7801
php/src/Auth/PasswordGenerator.php
Normal file
7801
php/src/Auth/PasswordGenerator.php
Normal file
File diff suppressed because it is too large
Load diff
112
php/src/Container/Container.php
Normal file
112
php/src/Container/Container.php
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container;
|
||||||
|
|
||||||
|
use AIO\Container\State\IContainerState;
|
||||||
|
use AIO\Data\ConfigurationManager;
|
||||||
|
use AIO\Docker\DockerActionManager;
|
||||||
|
use AIO\ContainerDefinitionFetcher;
|
||||||
|
|
||||||
|
class Container {
|
||||||
|
private string $identifier;
|
||||||
|
private string $displayName;
|
||||||
|
private string $containerName;
|
||||||
|
private string $restartPolicy;
|
||||||
|
private int $maxShutdownTime;
|
||||||
|
private ContainerPorts $ports;
|
||||||
|
private ContainerInternalPorts $internalPorts;
|
||||||
|
private ContainerVolumes $volumes;
|
||||||
|
private ContainerEnvironmentVariables $containerEnvironmentVariables;
|
||||||
|
/** @var string[] */
|
||||||
|
private array $dependsOn;
|
||||||
|
/** @var string[] */
|
||||||
|
private array $secrets;
|
||||||
|
private DockerActionManager $dockerActionManager;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
string $identifier,
|
||||||
|
string $displayName,
|
||||||
|
string $containerName,
|
||||||
|
string $restartPolicy,
|
||||||
|
int $maxShutdownTime,
|
||||||
|
ContainerPorts $ports,
|
||||||
|
ContainerInternalPorts $internalPorts,
|
||||||
|
ContainerVolumes $volumes,
|
||||||
|
ContainerEnvironmentVariables $containerEnvironmentVariables,
|
||||||
|
array $dependsOn,
|
||||||
|
array $secrets,
|
||||||
|
DockerActionManager $dockerActionManager
|
||||||
|
) {
|
||||||
|
$this->identifier = $identifier;
|
||||||
|
$this->displayName = $displayName;
|
||||||
|
$this->containerName = $containerName;
|
||||||
|
$this->restartPolicy = $restartPolicy;
|
||||||
|
$this->maxShutdownTime = $maxShutdownTime;
|
||||||
|
$this->ports = $ports;
|
||||||
|
$this->internalPorts = $internalPorts;
|
||||||
|
$this->volumes = $volumes;
|
||||||
|
$this->containerEnvironmentVariables = $containerEnvironmentVariables;
|
||||||
|
$this->dependsOn = $dependsOn;
|
||||||
|
$this->secrets = $secrets;
|
||||||
|
$this->dockerActionManager = $dockerActionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetIdentifier() : string {
|
||||||
|
return $this->identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetDisplayName() : string {
|
||||||
|
return $this->displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetContainerName() : string {
|
||||||
|
return $this->containerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetRestartPolicy() : string {
|
||||||
|
return $this->restartPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetMaxShutdownTime() : int {
|
||||||
|
return $this->maxShutdownTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetSecrets() : array {
|
||||||
|
return $this->secrets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetPorts() : ContainerPorts {
|
||||||
|
return $this->ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetInternalPorts() : ContainerInternalPorts {
|
||||||
|
return $this->internalPorts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetVolumes() : ContainerVolumes {
|
||||||
|
return $this->volumes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetRunningState() : IContainerState {
|
||||||
|
return $this->dockerActionManager->GetContainerRunningState($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetUpdateState() : IContainerState {
|
||||||
|
return $this->dockerActionManager->GetContainerUpdateState($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetStartingState() : IContainerState {
|
||||||
|
return $this->dockerActionManager->GetContainerStartingState($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function GetDependsOn() : array {
|
||||||
|
return $this->dependsOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetEnvironmentVariables() : ContainerEnvironmentVariables {
|
||||||
|
return $this->containerEnvironmentVariables;
|
||||||
|
}
|
||||||
|
}
|
19
php/src/Container/ContainerEnvironmentVariables.php
Normal file
19
php/src/Container/ContainerEnvironmentVariables.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container;
|
||||||
|
|
||||||
|
class ContainerEnvironmentVariables {
|
||||||
|
/** @var string[] */
|
||||||
|
private array $variables = [];
|
||||||
|
|
||||||
|
public function AddVariable(string $variable) : void {
|
||||||
|
$this->variables[] = $variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function GetVariables() : array {
|
||||||
|
return $this->variables;
|
||||||
|
}
|
||||||
|
}
|
19
php/src/Container/ContainerInternalPorts.php
Normal file
19
php/src/Container/ContainerInternalPorts.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container;
|
||||||
|
|
||||||
|
class ContainerInternalPorts {
|
||||||
|
/** @var string[] */
|
||||||
|
private array $internalPorts = [];
|
||||||
|
|
||||||
|
public function AddInternalPort(string $internalPort) : void {
|
||||||
|
$this->internalPorts[] = $internalPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function GetInternalPorts() : array {
|
||||||
|
return $this->internalPorts;
|
||||||
|
}
|
||||||
|
}
|
19
php/src/Container/ContainerPorts.php
Normal file
19
php/src/Container/ContainerPorts.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container;
|
||||||
|
|
||||||
|
class ContainerPorts {
|
||||||
|
/** @var string[] */
|
||||||
|
private array $ports = [];
|
||||||
|
|
||||||
|
public function AddPort(string $port) : void {
|
||||||
|
$this->ports[] = $port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function GetPorts() : array {
|
||||||
|
return $this->ports;
|
||||||
|
}
|
||||||
|
}
|
19
php/src/Container/ContainerVolume.php
Normal file
19
php/src/Container/ContainerVolume.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container;
|
||||||
|
|
||||||
|
class ContainerVolume {
|
||||||
|
public string $name;
|
||||||
|
public string $mountPoint;
|
||||||
|
public bool $isWritable;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
string $name,
|
||||||
|
string $mountPoint,
|
||||||
|
bool $isWritable
|
||||||
|
) {
|
||||||
|
$this->name = $name;
|
||||||
|
$this->mountPoint = $mountPoint;
|
||||||
|
$this->isWritable = $isWritable;
|
||||||
|
}
|
||||||
|
}
|
19
php/src/Container/ContainerVolumes.php
Normal file
19
php/src/Container/ContainerVolumes.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container;
|
||||||
|
|
||||||
|
class ContainerVolumes {
|
||||||
|
/** @var ContainerVolume[] */
|
||||||
|
private array $volumes = [];
|
||||||
|
|
||||||
|
public function AddVolume(ContainerVolume $volume) {
|
||||||
|
$this->volumes[] = $volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ContainerVolume[]
|
||||||
|
*/
|
||||||
|
public function GetVolumes() : array {
|
||||||
|
return $this->volumes;
|
||||||
|
}
|
||||||
|
}
|
5
php/src/Container/State/IContainerState.php
Normal file
5
php/src/Container/State/IContainerState.php
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container\State;
|
||||||
|
|
||||||
|
interface IContainerState {}
|
6
php/src/Container/State/ImageDoesNotExistState.php
Normal file
6
php/src/Container/State/ImageDoesNotExistState.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container\State;
|
||||||
|
|
||||||
|
class ImageDoesNotExistState implements IContainerState
|
||||||
|
{}
|
6
php/src/Container/State/RunningState.php
Normal file
6
php/src/Container/State/RunningState.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container\State;
|
||||||
|
|
||||||
|
class RunningState implements IContainerState
|
||||||
|
{}
|
6
php/src/Container/State/StartingState.php
Normal file
6
php/src/Container/State/StartingState.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container\State;
|
||||||
|
|
||||||
|
class StartingState implements IContainerState
|
||||||
|
{}
|
6
php/src/Container/State/StoppedState.php
Normal file
6
php/src/Container/State/StoppedState.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container\State;
|
||||||
|
|
||||||
|
class StoppedState implements IContainerState
|
||||||
|
{}
|
6
php/src/Container/State/VersionDifferentState.php
Normal file
6
php/src/Container/State/VersionDifferentState.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container\State;
|
||||||
|
|
||||||
|
class VersionDifferentState implements IContainerState
|
||||||
|
{}
|
6
php/src/Container/State/VersionEqualState.php
Normal file
6
php/src/Container/State/VersionEqualState.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container\State;
|
||||||
|
|
||||||
|
class VersionEqualState implements IContainerState
|
||||||
|
{}
|
136
php/src/ContainerDefinitionFetcher.php
Normal file
136
php/src/ContainerDefinitionFetcher.php
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO;
|
||||||
|
|
||||||
|
use AIO\Container\Container;
|
||||||
|
use AIO\Container\ContainerEnvironmentVariables;
|
||||||
|
use AIO\Container\ContainerPorts;
|
||||||
|
use AIO\Container\ContainerInternalPorts;
|
||||||
|
use AIO\Container\ContainerVolume;
|
||||||
|
use AIO\Container\ContainerVolumes;
|
||||||
|
use AIO\Container\State\RunningState;
|
||||||
|
use AIO\Data\ConfigurationManager;
|
||||||
|
use AIO\Data\DataConst;
|
||||||
|
use AIO\Docker\DockerActionManager;
|
||||||
|
|
||||||
|
class ContainerDefinitionFetcher
|
||||||
|
{
|
||||||
|
private ConfigurationManager $configurationManager;
|
||||||
|
private \DI\Container $container;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
ConfigurationManager $configurationManager,
|
||||||
|
\DI\Container $container
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->configurationManager = $configurationManager;
|
||||||
|
$this->container = $container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetContainerById(string $id): ?Container
|
||||||
|
{
|
||||||
|
$containers = $this->FetchDefinition();
|
||||||
|
|
||||||
|
foreach ($containers as $container) {
|
||||||
|
if ($container->GetIdentifier() === $id) {
|
||||||
|
return $container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function GetDefinition(bool $latest): array
|
||||||
|
{
|
||||||
|
$data = json_decode(file_get_contents(__DIR__ . '/../containers.json'), true);
|
||||||
|
|
||||||
|
$containers = [];
|
||||||
|
foreach ($data['production'] as $entry) {
|
||||||
|
$ports = new ContainerPorts();
|
||||||
|
foreach ($entry['ports'] as $port) {
|
||||||
|
$ports->AddPort($port);
|
||||||
|
}
|
||||||
|
|
||||||
|
$internalPorts = new ContainerInternalPorts();
|
||||||
|
foreach ($entry['internalPorts'] as $internalPort) {
|
||||||
|
$internalPorts->AddInternalPort($internalPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
$volumes = new ContainerVolumes();
|
||||||
|
foreach ($entry['volumes'] as $value) {
|
||||||
|
if($value['name'] === '%BORGBACKUP_HOST_LOCATION%') {
|
||||||
|
$value['name'] = $this->configurationManager->GetBorgBackupHostLocation();
|
||||||
|
if($value['name'] === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$volumes->AddVolume(
|
||||||
|
new ContainerVolume(
|
||||||
|
$value['name'],
|
||||||
|
$value['location'],
|
||||||
|
$value['writeable']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$variables = new ContainerEnvironmentVariables();
|
||||||
|
foreach ($entry['environmentVariables'] as $value) {
|
||||||
|
$variables->AddVariable($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$containers[] = new Container(
|
||||||
|
$entry['identifier'],
|
||||||
|
$entry['displayName'],
|
||||||
|
$entry['containerName'],
|
||||||
|
$entry['restartPolicy'],
|
||||||
|
$entry['maxShutdownTime'],
|
||||||
|
$ports,
|
||||||
|
$internalPorts,
|
||||||
|
$volumes,
|
||||||
|
$variables,
|
||||||
|
$entry['dependsOn'],
|
||||||
|
$entry['secrets'],
|
||||||
|
$this->container->get(DockerActionManager::class)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function FetchDefinition(): array
|
||||||
|
{
|
||||||
|
if (!file_exists(DataConst::GetDataDirectory() . '/containers.json')) {
|
||||||
|
$containers = $this->GetDefinition(true);
|
||||||
|
} else {
|
||||||
|
$containers = $this->GetDefinition(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$borgBackupMode = $this->configurationManager->GetBorgBackupMode();
|
||||||
|
$fetchLatest = false;
|
||||||
|
|
||||||
|
foreach ($containers as $container) {
|
||||||
|
|
||||||
|
if ($container->GetIdentifier() === 'nextcloud-aio-borgbackup') {
|
||||||
|
if ($container->GetRunningState() === RunningState::class) {
|
||||||
|
if ($borgBackupMode !== 'backup' && $borgBackupMode !== 'restore') {
|
||||||
|
$fetchLatest = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$fetchLatest = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} elseif ($container->GetIdentifier() === 'nextcloud-aio-watchtower' && $container->GetRunningState() === RunningState::class) {
|
||||||
|
return $containers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($fetchLatest === true) {
|
||||||
|
$containers = $this->GetDefinition(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $containers;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue