Version 3
Support for multiple libraries synchronization (#44, #43, #41) Support for Docker Secrets (#25) Support for Seafile client's version through Docker tags (#9) Mock Seafile server for testings (#6) Revised project layout and workflow (#38, #39) Working Docker Hub description publishing (#10)
This commit is contained in:
55
seafile-client/Dockerfile
Normal file
55
seafile-client/Dockerfile
Normal file
@@ -0,0 +1,55 @@
|
||||
ARG TARGET=unstable
|
||||
FROM debian:${TARGET}-slim
|
||||
|
||||
ARG UID
|
||||
ARG GID
|
||||
ENV UID 1000
|
||||
ENV GID 1000
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install \
|
||||
--no-install-recommends \
|
||||
--yes \
|
||||
seafile-cli \
|
||||
oathtool \
|
||||
ca-certificates \
|
||||
gnupg \
|
||||
sudo && \
|
||||
apt-get clean && apt-get autoclean && \
|
||||
rm -rf \
|
||||
/var/log/fsck/*.log \
|
||||
/var/log/apt/*.log \
|
||||
/var/cache/debconf/*.dat-old \
|
||||
/var/lib/apt/lists/*
|
||||
|
||||
COPY --chmod=755 entrypoint-docker.sh /entrypoint.sh
|
||||
COPY issue /etc/issue
|
||||
|
||||
RUN echo '[ ! -z $TERM ] && cat /etc/issue' >> /root/.bashrc && \
|
||||
groupadd --gid $GID seafile && \
|
||||
useradd --uid $UID --gid $GID --shell /bin/bash --create-home seafile && \
|
||||
mkdir /library /seafile && \
|
||||
chown seafile:seafile /seafile /library && \
|
||||
apt-cache show seafile-cli | grep 'Version: ' | awk '{print $2}' > /SEAFILE_VERSION
|
||||
|
||||
COPY --chmod=755 --chown=seafile:seafile entrypoint-seafile.py /home/seafile/entrypoint.py
|
||||
|
||||
ARG CREATED
|
||||
ARG REVISION
|
||||
ARG VERSION
|
||||
LABEL org.opencontainers.image.created=${CREATED}
|
||||
LABEL org.opencontainers.image.authors="flow.gunso@gmail.com"
|
||||
LABEL org.opencontainers.image.url="https://hub.docker.com/r/flowgunso/seafile-client"
|
||||
LABEL org.opencontainers.image.documentation="https://gitlab.com/flwgns-docker/seafile-client"
|
||||
LABEL org.opencontainers.image.source="https://gitlab.com/flwgns-docker/seafile-client"
|
||||
LABEL org.opencontainers.image.version=${VERSION}
|
||||
LABEL org.opencontainers.image.revision=${REVISION}
|
||||
LABEL org.opencontainers.image.licenses="GPL-3.0"
|
||||
LABEL org.opencontainers.image.title="Seafile Docker client"
|
||||
LABEL org.opencontainers.image.description="Sync Seafile librairies within Docker containers."
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["/home/seafile/entrypoint.py"]
|
||||
HEALTHCHECK \
|
||||
CMD ["/entrypoint.sh", "/home/seafile/entrypoint.py", "--healthcheck"]
|
||||
@@ -1,66 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Docker Seafile client, help you mount a Seafile library as a volume.
|
||||
# Copyright (C) 2019-2020, flow.gunso@gmail.com
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
function fail_with_message {
|
||||
echo "$1"
|
||||
echo "Exiting container."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check mandatory Seafile configuration have been properly set.
|
||||
[[ -z "$SEAF_SERVER_URL" ]] && fail_with_message "The \$SEAF_SERVER_URL is not defined."
|
||||
[[ -z "$SEAF_USERNAME" ]] && fail_with_message "The \$SEAF_USERNAME is not defined."
|
||||
[[ -z "$SEAF_PASSWORD" ]] && fail_with_message "The \$SEAF_PASSWORD is not defined."
|
||||
[[ -z "$SEAF_LIBRARY_UUID" ]] && fail_with_message "The \$SEAF_LIBRARY_UUID is not defined."
|
||||
[[ -n "$SEAF_UPLOAD_LIMIT" && $SEAF_UPLOAD_LIMIT =~ ^[0-9]+$ && "$SEAF_UPLOAD_LIMIT" -gt 0 ]] && \
|
||||
fail_with_message "The \$SEAF_UPLOAD_LIMIT is not an integer greater than 0."
|
||||
[[ -n "$SEAF_DOWNLOAD_LIMIT" && $SEAF_DOWNLOAD_LIMIT =~ ^[0-9]+$ && "$SEAF_DOWNLOAD_LIMIT" -gt 0 ]] && \
|
||||
fail_with_message "The \$SEAF_DOWNLOAD_LIMIT is not an integer greater than 0."
|
||||
|
||||
# Update the user ID, if the $UID changed.
|
||||
# TODO: What if the $UID already exists ?
|
||||
[[ "$UID" != "1000" ]] && usermod -u $UID $UNAME
|
||||
|
||||
# Change the group, if the $GID changed.
|
||||
if [ "$GID" != "1000" ]; then
|
||||
getent group | grep ":$GID:" >/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
usermod -g $GID -G 1000 $UNAME
|
||||
else
|
||||
groupmod -g $GID $UNAME
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set the files ownership.
|
||||
#chown $UID.$GID /home/seafuser/healthcheck.sh
|
||||
chown $UID.$GID /home/seafuser/entrypoint.sh
|
||||
chown $UID.$GID -R /library
|
||||
|
||||
# Run the Seafile client as the container user.
|
||||
su - $UNAME << EO
|
||||
export SEAF_SERVER_URL=$SEAF_SERVER_URL
|
||||
export SEAF_USERNAME=$SEAF_USERNAME
|
||||
export SEAF_PASSWORD=$SEAF_PASSWORD
|
||||
export SEAF_LIBRARY_UUID=$SEAF_LIBRARY_UUID
|
||||
[[ "$SEAF_SKIP_SSL_CERT" ]] && export SEAF_SKIP_SSL_CERT=$SEAF_SKIP_SSL_CERT
|
||||
[[ "$SEAF_UPLOAD_LIMIT" ]] && export SEAF_UPLOAD_LIMIT=$SEAF_UPLOAD_LIMIT
|
||||
[[ "$SEAF_DOWNLOAD_LIMIT" ]] && export SEAF_DOWNLOAD_LIMIT=$SEAF_DOWNLOAD_LIMIT
|
||||
[[ "$SEAF_2FA_SECRET" ]] && export SEAF_2FA_SECRET=$SEAF_2FA_SECRET
|
||||
[[ "$SEAF_LIBRARY_PASSWORD" ]] && export SEAF_LIBRARY_PASSWORD=$SEAF_LIBRARY_PASSWORD
|
||||
/bin/bash /home/seafuser/entrypoint.sh
|
||||
EO
|
||||
@@ -16,9 +16,14 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# Grab the status of the active repos then return as healthy/unhealthy
|
||||
# depending the healthy statuses.
|
||||
#!/bin/bash
|
||||
|
||||
su - $UNAME << EO
|
||||
~/healthcheck.py -c ~/.seafile/seafile-data/ $SEAF_LIBRARY_UUID
|
||||
EO
|
||||
set -e
|
||||
|
||||
groupmod -g $GID seafile &> /dev/null
|
||||
usermod -u $UID -g $GID seafile &> /dev/null
|
||||
|
||||
sudo \
|
||||
-HE \
|
||||
-u seafile \
|
||||
-- "$@"
|
||||
310
seafile-client/entrypoint-seafile.py
Executable file
310
seafile-client/entrypoint-seafile.py
Executable file
@@ -0,0 +1,310 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
import seafile
|
||||
|
||||
|
||||
class BadConfiguration(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_configuration(variable: str, *args) -> Any:
|
||||
"""Helper function to get a configuration.
|
||||
see https://gitlab.com/-/snippets/1941025
|
||||
"""
|
||||
|
||||
# Assign the default value from the first item of *args.
|
||||
if args:
|
||||
default = args[0]
|
||||
|
||||
# Try to get the variable from a Docker Secret.
|
||||
try:
|
||||
file = os.environ[f"{variable}_FILE"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
with open(file, "rt") as fo:
|
||||
return fo.read()
|
||||
|
||||
# Try to get the variable from an environment variable.
|
||||
try:
|
||||
return os.environ[variable]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# Try to return the default value,
|
||||
# if no default exist, then it is a required variable.
|
||||
try:
|
||||
return default
|
||||
except UnboundLocalError:
|
||||
raise BadConfiguration(
|
||||
f"Environment variable {variable} was not found but is required."
|
||||
)
|
||||
|
||||
class Client:
|
||||
|
||||
def __init__(self) -> None:
|
||||
# Client configuration
|
||||
self.username: str = get_configuration("SEAF_USERNAME")
|
||||
self.password: str = get_configuration("SEAF_PASSWORD")
|
||||
self.url: str = get_configuration("SEAF_SERVER_URL")
|
||||
self.skip_ssl_cert: bool = bool(get_configuration("SEAF_SKIP_SSL_CERT", None))
|
||||
self.upload_limit: int = get_configuration("SEAF_UPLOAD_LIMIT", None)
|
||||
self.download_limit: int = get_configuration("SEAF_DOWNLOAD_LIMIT", None)
|
||||
self.mfa_secret: str = get_configuration("SEAF_2FA_SECRET", None)
|
||||
|
||||
# Paths
|
||||
self.ini = Path.home().joinpath(".ccnet", "seafile.ini")
|
||||
self.log = Path.home().joinpath(".ccnet", "logs", "seafile.log")
|
||||
self.seafile = Path("/seafile")
|
||||
self.socket = self.seafile.joinpath("seafile-data", "seafile.sock")
|
||||
self.target = Path("/library")
|
||||
|
||||
# Binaries, instances.
|
||||
if self.socket.exists():
|
||||
self.rpc = seafile.RpcClient(str(self.socket))
|
||||
|
||||
self.binary = ["seaf-cli"]
|
||||
self._get_librairies()
|
||||
|
||||
def _get_librairies(self):
|
||||
self.libraries = {}
|
||||
|
||||
# Single library use case. Mutually exclusive to mulitple labraries use case.
|
||||
single_library_variables = ["SEAF_LIBRARY", "SEAF_LIBRARY_UUID", "SEAF_LIBRARY_PASSWORD"]
|
||||
if any(environ in single_library_variables for environ in os.environ):
|
||||
logger.info("Single library detected. Multiple libraries will be ignored.")
|
||||
library = {}
|
||||
|
||||
# Grab the UUID, usin both the
|
||||
uuid = None
|
||||
if legacy := os.getenv("SEAF_LIBRARY_UUID", None):
|
||||
logger.warning("SEAF_LIBRARY_UUID is obsolete, please use SEAF_LIBRARY instead.")
|
||||
uuid = legacy
|
||||
if current := os.getenv("SEAF_LIBRARY", None):
|
||||
uuid = current
|
||||
|
||||
# Exit if no UUID was provided, continue otherwise.
|
||||
if uuid is None:
|
||||
raise Exception("Please provide an UUID with SEAF_LIBRARY for single library usage.")
|
||||
library["uuid"] = uuid
|
||||
|
||||
if password := os.getenv("SEAF_LIBRARY_PASSWORD", None):
|
||||
library["password"] = password
|
||||
|
||||
# Assign and return a default library.
|
||||
self.libraries["_"] = library
|
||||
return
|
||||
|
||||
# Multiple libraries use case.
|
||||
# Loop over all sorted variables prefixed with SEAF_LIBRARY.
|
||||
for variable in sorted(os.environ):
|
||||
if variable.startswith("SEAF_LIBRARY"):
|
||||
|
||||
# Get the variable name.
|
||||
name = variable.split("_")[2]
|
||||
|
||||
# Read the password as a secret.
|
||||
if "_PASSWORD" in variable:
|
||||
password = get_configuration(variable, None)
|
||||
try:
|
||||
if password:
|
||||
self.libraries[name]["password"] = password
|
||||
except KeyError:
|
||||
logger.warning(f"Cannot set a password to unknown library {name}")
|
||||
|
||||
# Or got the name, build the dictionary with the name and uuid.
|
||||
else:
|
||||
self.libraries[name] = {}
|
||||
uuid = os.environ[variable]
|
||||
self.libraries[name]["uuid"] = uuid
|
||||
|
||||
def initialize(self):
|
||||
# Initialize the Seafile client.
|
||||
logger.info("Initializing `seaf-cli`.")
|
||||
if not self.ini.exists():
|
||||
logger.info("Seafile .ini file not found, running `seaf-cli init`")
|
||||
#self.ini.parent.parent.mkdir(parents=True, exist_ok=True)
|
||||
subprocess.run(self.binary + ["init", "-d", str(self.seafile)])
|
||||
while not self.ini.exists():
|
||||
logging.debug("Waiting for the .ini file to be created...")
|
||||
time.sleep(1)
|
||||
|
||||
# Start the Seafile client.
|
||||
logger.info("Starting `seaf-cli`.")
|
||||
subprocess.run(self.binary + ["start"])
|
||||
while not self.socket.exists():
|
||||
logger.debug("Waiting for the Seafile client socket to be created.")
|
||||
time.sleep(1)
|
||||
|
||||
def configure(self):
|
||||
command = self.binary + ["config"]
|
||||
if self.skip_ssl_cert:
|
||||
subprocess.run(command +["-k", "disable_verify_certificate", "-v", self.skip_ssl_cert])
|
||||
if self.download_limit:
|
||||
subprocess.run(command +["-k", "download_limit", "-v", self.download_limit])
|
||||
if self.upload_limit:
|
||||
subprocess.run(command +["-k", "upload_limit", "-v", self.upload_limit])
|
||||
|
||||
def synchronize(self):
|
||||
core = self.binary + ["sync", "-u", self.username, "-p", self.password, "-s", self.url]
|
||||
for name, configuration in self.libraries.items():
|
||||
uuid = configuration["uuid"]
|
||||
|
||||
# Check if repository is already synced.
|
||||
repository = self.rpc.get_repo(uuid)
|
||||
if repository is not None:
|
||||
logger.info(f"Library {name} is already synced.")
|
||||
continue
|
||||
|
||||
command = core + ["-l", uuid]
|
||||
|
||||
if "password" in configuration:
|
||||
password = configuration["password"]
|
||||
command += ["-e", password]
|
||||
|
||||
target = self.target if name == "_" else self.target.joinpath(name)
|
||||
target.mkdir(parents=True, exist_ok=True)
|
||||
command += ["-d", str(target)]
|
||||
|
||||
if self.mfa_secret:
|
||||
totp = subprocess.run(
|
||||
f"oathtool --base32 --totp {self.mfa_secret}",
|
||||
text=True,
|
||||
capture_stdout=True).stdout
|
||||
command += ["-a", totp]
|
||||
|
||||
logging.debug(f"Running {' '.join(command)}")
|
||||
subprocess.run(command)
|
||||
|
||||
def follow(self):
|
||||
logging.debug(f"Running `tail -v -f {self.log}`")
|
||||
subprocess.run(["tail", "-v", "-f", self.log])
|
||||
|
||||
def healthcheck(self):
|
||||
|
||||
tasks = self.rpc.get_clone_tasks()
|
||||
healthy = True
|
||||
for task in tasks:
|
||||
name = task.repo_name
|
||||
state = task.state
|
||||
|
||||
if task.state == 'done':
|
||||
continue
|
||||
elif state == "fetch":
|
||||
tx_task = self.rpc.find_transfer_task(task.repo_id)
|
||||
percentage = 0 if tx_task.block_done == 0 else tx_task.block_done / tx_task.block_total * 100
|
||||
rate = 0 if tx_task.rate == 0 else tx_task.rate / 1024.0
|
||||
print(f"{name:<50s}\t{state:<20s}\t{percentage:<.1f}%, {rate:<.1f}KB/s")
|
||||
elif task.state == "error":
|
||||
healthy = False
|
||||
error = self.rpc.sync_error_id_to_str(task.error)
|
||||
print(f"{name:<50s}\t{state:<20s}\t{error}")
|
||||
else:
|
||||
print(f"{name:<50s}\t{state:<20s}")
|
||||
|
||||
repos = self.rpc.get_repo_list(-1, -1)
|
||||
for repo in repos:
|
||||
name = repo.name
|
||||
|
||||
auto_sync_enabled = self.rpc.is_auto_sync_enabled()
|
||||
if not auto_sync_enabled or not repo.auto_sync:
|
||||
state = "auto sync disabled"
|
||||
print(f"{name:<50s}\t{state:<20s}")
|
||||
continue
|
||||
|
||||
task = self.rpc.get_repo_sync_task(repo.id)
|
||||
if task is None:
|
||||
state = "waiting for sync"
|
||||
print(f"{name:<50s}\t{state:<20s}")
|
||||
continue
|
||||
|
||||
state = task.state
|
||||
if state in ['uploading', 'downloading']:
|
||||
tx_task = self.rpc.find_transfer_task(repo.id)
|
||||
if tx_task.rt_state == "data":
|
||||
state += " files"
|
||||
percentage = 0 if tx_task.block_done == 0 else tx_task.block_done / tx_task.block_total * 100
|
||||
rate = 0 if tx_task.rate == 0 else tx_task.rate / 1024.0
|
||||
print(f"{name:<50s}\t{state:<20s}\t{percentage:<.1f}%, {rate:<.1f}KB/s")
|
||||
elif tx_task.rt_state == "fs":
|
||||
state += " files list"
|
||||
percentage = 0 if tx_task.fs_objects_done == 0 else tx_task.fs_objects_done / tx_task.fs_objects_total * 100
|
||||
print(f"{name:<50s}\t{state:<20s}\t{percentage:<.1f}%")
|
||||
elif state == 'error':
|
||||
healthy = False
|
||||
error = self.rpc.sync_error_id_to_str(task.error)
|
||||
print(f"{name:<50s}\t{state:<20s}\t{error}")
|
||||
else:
|
||||
print(f"{name:<50s}\t{state:<20s}")
|
||||
|
||||
|
||||
def entrypoint():
|
||||
try:
|
||||
logging.debug("Instanciating the client")
|
||||
client = Client()
|
||||
except BadConfiguration as e:
|
||||
logger.error(f"Bad configuration: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
logging.debug("Initializing the client")
|
||||
client.initialize()
|
||||
logging.debug("Configuring the client")
|
||||
client.configure()
|
||||
logging.debug("Synchronizing the client")
|
||||
client.synchronize()
|
||||
logging.debug("Following the client")
|
||||
client.follow()
|
||||
|
||||
|
||||
debug = get_configuration("DEBUG", False)
|
||||
level = logging.INFO
|
||||
format = "%(asctime)s - %(levelname)s - %(message)s"
|
||||
if debug:
|
||||
level = logging.DEBUG
|
||||
format = "%(asctime)s - %(filename)s:%(lineno)d - %(levelname)s - %(message)s"
|
||||
logging.basicConfig(format=format, level=level)
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="",
|
||||
description="",
|
||||
epilog=""
|
||||
)
|
||||
parser.add_argument("--healthcheck", action="store_true")
|
||||
args = parser.parse_args()
|
||||
healthcheck = args.healthcheck
|
||||
|
||||
if healthcheck:
|
||||
logger.disabled = True
|
||||
|
||||
try:
|
||||
logging.debug("Instanciating the client")
|
||||
client = Client()
|
||||
except BadConfiguration as e:
|
||||
logger.error(f"Bad configuration: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
if healthcheck:
|
||||
logging.debug("Running healthchecks")
|
||||
sys.exit(client.healthcheck())
|
||||
|
||||
logging.debug("Initializing the client")
|
||||
client.initialize()
|
||||
logging.debug("Configuring the client")
|
||||
client.configure()
|
||||
logging.debug("Synchronizing the client")
|
||||
client.synchronize()
|
||||
logging.debug("Following the client")
|
||||
client.follow()
|
||||
|
||||
4
seafile-client/issue
Normal file
4
seafile-client/issue
Normal file
@@ -0,0 +1,4 @@
|
||||
┌───────────────────────┐
|
||||
│ Seafile Docker client │
|
||||
└───────────────────────┘
|
||||
Run `./entrypoint.sh bash` to login as the seafile user.
|
||||
@@ -1,55 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Docker Seafile client, help you mount a Seafile library as a volume.
|
||||
# Copyright (C) 2019-2020, flow.gunso@gmail.com
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# Initialise the Seafile client, if not already initialised.
|
||||
seafile_ini="$HOME/.ccnet/seafile.ini"
|
||||
if [ ! -f "$seafile_ini" ]; then
|
||||
echo "Initializing Seafile client..."
|
||||
seaf-cli init -d ~/.seafile
|
||||
while [ ! -f "$seafile_ini" ]; do sleep 1; done
|
||||
fi
|
||||
|
||||
# Start the Seafile daemon.
|
||||
echo "Starting Seafile client..."
|
||||
seaf-cli start
|
||||
while [ ! -S "$HOME/.seafile/seafile-data/seafile.sock" ]; do sleep 1; done
|
||||
|
||||
# Synchronize the library, if not already synchronized.
|
||||
if [ -z "$(seaf-cli status | grep -v ^\#)" ]; then
|
||||
echo "Synchronizing Seafile library..."
|
||||
# Set the disable_verify_certificate key to true only if the environment variable exists.
|
||||
[[ "$SEAF_SKIP_SSL_CERT" ]] && seaf-cli config -k disable_verify_certificate -v true
|
||||
|
||||
# Set the upload/download limits
|
||||
[[ "$SEAF_UPLOAD_LIMIT" ]] && seaf-cli config -k upload_limit -v $SEAF_UPLOAD_LIMIT
|
||||
[[ "$SEAF_DOWNLOAD_LIMIT" ]] && seaf-cli config -k download_limit -v $SEAF_DOWNLOAD_LIMIT
|
||||
|
||||
# Build the seaf-cli sync command.
|
||||
cmd="seaf-cli sync -u $SEAF_USERNAME -p $SEAF_PASSWORD -s $SEAF_SERVER_URL -l $SEAF_LIBRARY_UUID -d /library"
|
||||
[[ "$SEAF_2FA_SECRET" ]] && cmd+=" -a $(oathtool --base32 --totp $SEAF_2FA_SECRET)"
|
||||
[[ "$SEAF_LIBRARY_PASSWORD" ]] && cmd+=" -e $SEAF_LIBRARY_PASSWORD"
|
||||
|
||||
# Run it.
|
||||
if ! eval $cmd; then echo "Failed to synchronize."; exit 1; fi
|
||||
fi
|
||||
|
||||
# Continously print the log, infinitely.
|
||||
while true; do
|
||||
tail -v -f ~/.ccnet/logs/seafile.log
|
||||
echo $?
|
||||
done
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
# Docker Seafile client, help you mount a Seafile library as a volume.
|
||||
# Copyright (C) 2019-2020, flow.gunso@gmail.com
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# Given a path to a valid Seafile confdir and a repository, check the
|
||||
# synchronization status and otherwise the transfer status of that
|
||||
# repository.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
import seafile
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Parse Seafile's confdir and repository ID to check.
|
||||
parser = argparse.ArgumentParser(description="Check the status of a synced repository.")
|
||||
parser.add_argument('repository_id', type=str, help="Repository ID to check the status of.")
|
||||
parser.add_argument('-c', '--confdir', type=str, required=True, help="Seafile configuration directory to load the Socket from.")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Instanciate Seafile RPC.
|
||||
seafile_socket = os.path.join(args.confdir, "seafile.sock")
|
||||
if not os.path.exists(seafile_socket):
|
||||
raise Exception("Could not find a Seafile socket at {}".format(args.confdir))
|
||||
seafile_rpc = seafile.RpcClient(seafile_socket)
|
||||
|
||||
# Fetch the sync task of the repository.
|
||||
repository_sync_task = seafile_rpc.get_repo_sync_task(args.repository_id)
|
||||
if repository_sync_task is not None:
|
||||
sync_state = repository_sync_task.state
|
||||
msg = "Repository synchronization state: {}".format(sync_state)
|
||||
if sync_state == "error":
|
||||
raise Exception(msg)
|
||||
else:
|
||||
print(msg)
|
||||
sys.exit(0)
|
||||
|
||||
# Fetch the transfer task of the repository.
|
||||
repository_transfer_task = seafile_rpc.find_transfer_task(args.repository_id)
|
||||
if repository_transfer_task is not None:
|
||||
transfer_state = repository_transfer_task.state
|
||||
msg = "Repository transfer state: {}".format(transfer_state)
|
||||
if transfer_state == "error":
|
||||
raise Exception(msg)
|
||||
else:
|
||||
print(msg)
|
||||
sys.exit(0)
|
||||
|
||||
raise Exception("Could not find any information about any repository synchronization or transfer tasks.")
|
||||
Reference in New Issue
Block a user