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:
flow.gunso
2024-03-16 21:58:04 +00:00
parent 4c347b9156
commit f25b0182d2
42 changed files with 1196 additions and 788 deletions

8
.gitignore vendored
View File

@@ -1,5 +1,5 @@
.idea/
*.pyc
docker-compose.test.yml
venv/
*.description
.env/
tarballs/
VERSIONS.txt
documentations/*.md

View File

@@ -3,67 +3,101 @@ image: docker:latest
services:
- docker:dind
.parallel:
parallel:
matrix:
- TARGET: [oldstable, stable, unstable]
stages:
- report
- build
- test
- publish
- release
before_script:
- apk add bash git
- apk add bash git curl jq make
build:
stage: build
script:
- /bin/bash .utilities/check.sh
- /bin/bash -e .utilities/build.sh
- make build
- make save
extends: .parallel
only:
- merge_requests
- tags
artifacts:
paths:
- "$CI_PROJECT_NAME.tar"
build:description_template:
image: python:3.8-alpine
stage: build
script: sh -e .utilities/templates/templater.sh
only:
- tags
artifacts:
paths:
- "*.description"
- "tarballs/"
test:
stage: test
script: /bin/bash -e .utilities/test.sh
script:
- make load
- make build-test
- make test
extends: .parallel
needs:
- job: build
parallel:
matrix:
- TARGET: oldstable
- TARGET: stable
- TARGET: unstable
only:
- merge_requests
- tags
artifacts:
paths:
- tarballs/
publish-images:
stage: release
script:
- make load
- make publish-images
needs:
- job: build
parallel:
matrix:
- TARGET: oldstable
- TARGET: stable
- TARGET: unstable
- job: test
extends: .parallel
only:
- tags
artifacts:
paths:
- "$CI_PROJECT_NAME.tar"
- tarballs/
- versions/*
publish:
stage: publish
script: /bin/bash -e .utilities/publish.sh
make-documents:
stage: release
script:
- apk add py3-jinja2
- make documents
needs:
- job: publish-images
parallel:
matrix:
- TARGET: oldstable
- TARGET: stable
- TARGET: unstable
only:
- tags
artifacts:
paths:
- "$CI_PROJECT_NAME.tar"
- versions/*
- documentations/*.md
#update_docker_hub_full_description:
# stage: publish
# script: /bin/bash -e .utilities/update-docker-hub-full-description.sh
# only:
# - master
bot:package_update_notification:
stage: report
script: bash -e .utilities/package_update_notifier.sh
publish-documents:
stage: release
script:
- make publish-documents
needs:
- job: make-documents
only:
- schedules
# see https://docs.gitlab.com/ce/ci/yaml/README.html#onlyexcept-advanced for feature updates
# refs:
# - schedules
# variables:
# - $SCHEDULE_ID == $PACKAGE_UPDATE_NOTIFICATION_SCHEDULE_ID
- tags
artifacts:
paths:
- documentations/*.md

View File

@@ -1,34 +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/>.
# Check the CI pipeline sources.
if ! [[ "$CI_PIPELINE_SOURCE" == "push" ]]; then
echo "CI pipelines are only allowed from push."
exit 1
fi
# Check the tag is properly defined on job other than update_docker_hub_full_description job,
# on pushed CI pipelines.
if [[ "$CI_PIPELINE_SOURCE" == "push" ]]; then
if ! [[ "$CI_JOB_NAME" == "update_docker_hub_full_description" ]]; then
if [[ -z "$CI_COMMIT_TAG" && "$CI_COMMIT_TAG" =~ ^[0-9]+[.][0-9]+[.][0-9]+$ ]]; then
echo "The \$CI_COMMIT_TAG $CI_COMMIT_TAG does not match the MAJOR.Minor.revision layout."
exit 1
fi
fi
fi

View File

@@ -1,71 +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/>.
apk add curl jq
# Load utilities functions.
SCRIPT_DIRECTORY=$(dirname ${BASH_SOURCE[0]})
source $SCRIPT_DIRECTORY/utilities.sh
# Restrict the job to the right schedule.
if [[ "$SCHEDULE_ID" != "$PACKAGE_UPDATE_NOTIFICATION_SCHEDULE_ID" ]]; then
exit_with_message_and_code "Schedule ID did not match." 0
fi
# Fetch the issue state if the ISSUE_ID variable is set,
# if that state is closed remove the ISSUE_ID variable and continue the job, otherwise exit the job.
if [[ -n "$ISSUE_ID" ]]; then
issue_state="$(curl -H \"PRIVATE-TOKEN: $REPORTER_BOT_ACCESS_TOKEN\" \
https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/issue/$ISSUE_ID | jq .state)"
if [[ "$issue_state" == "closed" ]]; then
echo "An issue exist, but is closed. Removing ISSUE_ID schedule variable..."
curl -X DELETE \
-H "PRIVATE-TOKEN: $REPORTER_BOT_ACCESS_TOKEN" \
https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/pipeline_schedules/$SCHEDULE_ID/variables/$ISSUE_ID
else
exit_with_message_and_code "An issue already exists, it is not closed yet." 0
fi
fi
# Get the installed and candidate versions of the seafile-cli package from the latest Docker image.
docker pull $CI_REGISTRY_IMAGE:latest
candidate_version=$(docker run --rm --entrypoint="" $CI_REGISTRY_IMAGE:latest \
bash -c "\
apt-get -qq update;\
apt-cache policy seafile-cli | grep 'Candidate:' | awk '{print \$2}'")
installed_version=$(docker run --rm --entrypoint="" $CI_REGISTRY_IMAGE:latest \
bash -c "\
apt-get -qq update;\
apt-cache policy seafile-cli | grep 'Installed:' | awk '{print \$2}'")
# Create an issue if a new version was released.
if [[ "$installed_version" == "$candidate_version" ]]; then
exit_with_message_and_code "No new version of the seafile-cli package have been released." 0
else
echo "A new version of the seafile-cli package have been released. Creating a new issue..."
data=$(jq -n \
--arg title "seafile-cli v${candidate_version} was released" \
--arg description "Check for new feature, breaking changes or anything worth updating to update the Docker image." \
--arg labels "enhancement" \
'{title: $title, description: $description, labels: [$labels]}')
curl -X POST \
-H "PRIVATE-TOKEN: $REPORTER_BOT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "$data"
https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/issues
fi

View File

@@ -1,38 +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/>.
apk add curl
SCRIPT_DIRECTORY=$(dirname ${BASH_SOURCE[0]})
source $SCRIPT_DIRECTORY/utilities.sh
load_images_artifacts
# Generate version tags.
tags=("latest")
for version_component in $(echo $CI_COMMIT_TAG | tr "." "\n"); do
tag+="$version_component"
tags+=("$tag")
tag+="."
done
# Tag then push the Docker Hub registry.
echo $CI_REGISTRY_BOT_PASSWORD | docker login --password-stdin --username $CI_REGISTRY_BOT_USERNAME
for tag in "${tags[@]}"; do
docker tag $CI_PROJECT_NAME:build $CI_REGISTRY_IMAGE:$tag
docker push $CI_REGISTRY_IMAGE:$tag
done

View File

@@ -1,3 +0,0 @@
click==7.1.1
Jinja2==2.11.1
markupsafe==2.0.1

View File

@@ -1,79 +0,0 @@
#!/usr/bin/env python3
# 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/>.
import re
from jinja2 import Template
import click
README_FILENAME = "README.md"
CHANGELOG_FILENAME = "CHANGELOG.md"
SEAFILE_TOPIC_POST_TEMPLATE_FILENAME = ".utilities/templates/seafile_topic_post.template"
DOCKER_HUB_DESCRIPTION_FILENAME = "docker_hub.description"
SEAFILE_FORUM_TOPIC_POST_DESCRIPTION_FILENAME = "seafile_forum_topic_post.description"
def translate_issues_references_into_urls(string):
return re.sub(
r' #([0-9]+)',
r' [issue#\1](https://gitlab.com/flwgns-docker/seafile-client/-/issues/\1)',
string)
def translate_markdown_links_of_repository_files_into_urls(string, ref):
return re.sub(
r'(\[.+\])\((?!.+:\/\/)(?!mailto:.+)(.+)\)',
r'\1(https://gitlab.com/flwgns-docker/seafile-client/-/blob/{}/\2)'
.format(ref),
string)
@click.command()
@click.argument('ref', type=click.STRING)
def templater(ref):
"""CLI entrypoint the templater."""
if len(ref) != 40:
raise Exception("Commit reference must be 40 characters long (i.e. not the short ref)")
# Extract text from the README.md, CHANGELOG.md and the Seafile forum topic post template files.
with open(README_FILENAME, mode="rt") as fo:
readme_text = fo.read()
with open(CHANGELOG_FILENAME, mode="rt") as fo:
changelog_text = fo.read()
with open(SEAFILE_TOPIC_POST_TEMPLATE_FILENAME, mode="rt") as fo:
seafile_topic_post_template_text = fo.read()
# Generate the Docker Hub description by:
# - translating Markdown links of repository files to reachable URLs
docker_hub_description = translate_markdown_links_of_repository_files_into_urls(readme_text, ref)
with open(DOCKER_HUB_DESCRIPTION_FILENAME, mode="wt") as fo:
fo.write(docker_hub_description)
# Generate the Seafile forum topic post description by:
# - translating issues reference into reachable URLs
# - templating the previous into the existing post
seafile_topic_post_template = Template(seafile_topic_post_template_text)
changlog_reachable_issue_urls = translate_issues_references_into_urls(changelog_text)
seafile_topic_post_description = seafile_topic_post_template.render(changelog=changlog_reachable_issue_urls)
with open(SEAFILE_FORUM_TOPIC_POST_DESCRIPTION_FILENAME, mode="wt") as fo:
fo.write(seafile_topic_post_description)
if __name__ == "__main__":
templater()

View File

@@ -1,26 +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/>.
SCRIPT_DIRECTORY=$(dirname ${BASH_SOURCE[0]})
source $SCRIPT_DIRECTORY/utilities.sh
load_images_artifacts
docker run \
--interactive \
--attach stderr \
$CI_PROJECT_NAME:build /tests/test_binaries.sh

View File

@@ -1,46 +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/>.
# Based upon https://gist.github.com/jlhawn/8f218e7c0b14c941c41f
# and https://github.com/moikot/golang-dep/blob/master/.travis/push.sh
# This action can only be done with the actual owner of the repository,
# unless you can extend the collaborator's permissions but as far as I know, you can't.
# Install required system packages.
apk add curl jq
# Get a token from hub.docker.com with the owner credentials.
token=$(curl -s \
-X POST \
-H "Content-Type: application/json" \
-d '{"username": "'"$CI_REGISTRY_OWNER_USERNAME"'", "password": "'"$CI_REGISTRY_OWNER_PASSWORD"'"}' \
https://hub.docker.com/v2/users/login/ | jq -r .token)
# Generate a JSON with the README.md as the full_description.
json=$(jq -n \
--arg readme "$(<README.md)" \
'{"full_description": $readme}')
# Update the Docker Hub repository's full_description.
curl -s -L \
-X PATCH \
-d "$json" \
-H "Content-Type: application/json" \
-H "Authorization: JWT $token" \
https://cloud.docker.com/v2/repositories/$CI_REGISTRY_IMAGE/

View File

@@ -1,26 +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/>.
load_images_artifacts() {
docker load --input $CI_PROJECT_NAME.tar
}
exit_with_message_and_code() {
echo $1
exit $2
}

View File

@@ -1,23 +1,57 @@
- Close #16: add a templater for Docker Hub and Seafile's forum topic description
# Changelog
## __[2.2.0](https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.2.0)__ | _2022/08/26_
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
<!-- To log a new version, copy, uncomment, add your changes, then add the tag shortcut at the end of the file
## [Unreleased]
### Added
### Changed
### Deprecated
### Removed
### Fixed
### Security
[tag]: url_to_tag
-->
## [3.0.0] - 2024/03/16
### Added
- Support for multiple libraries synchronization (#44, #43, #41)
- Support for Docker Secrets (#25)
- Support for Seafile client's version through Docker tags (#9)
- Build documentation with Jinja2 templates (#42)
- Manage the project with a Makefile (#38)
- Mock Seafile server for testings (#6)
### Changed
- Revised project layout and workflow (#38, #39)
### Fixed
- Fixed the Docker Hub description publish through their API (#10)
- Add ca-certificates and gnupg to support more HTTP certificates (#24)
[3.0.0]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/3.0.0
<!-- /3.0.0 -->
## [2.2.0] - 2022/08/26
- Update from Debian Buster to Debian Bullseye (!7)
- Improved Seafile apt source installation (!7)
### __[2.1.1](https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.1.1)__ | _2020/03/10_
- Close #14: prevent re-initialization and re-synchronization of the container if it's life cycle change but is not deleted
## __[2.1.0](https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.1.0)__ | _2020/01/30_
- Close #13: replace previous Bash script that parse `seaf-cli status` with a Python script that use __pysearpc__ to run checks
- Ongoing #14: implement a workaround to probable issue, waiting for the issue to appear
## [2.1.1] - 2020/03/10
- Prevent re-initialization and re-synchronization of the container if it's life cycle change but is not deleted (#14)
## [2.1.0] - 2020/01/30
- Replace previous Bash script that parse `seaf-cli status` with a Python script that use pysearpc to run checks (#13)
- Implement a workaround to probable issue, waiting for the issue to appear (#14)
### __[2.0.3](https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.0.2)__ | _2020/01/14_
- Close #5: read [the docs](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg) a bit more.
### __[2.0.2](https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.0.2)__ | _2020/01/14_
- Ongoing #5: propagate the CI_COMMIT_TAG and CI_PROJECT_URL environment variables into the Dockerfile as [the docs states](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg).
### __[2.0.1](https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.0.1)__ | _2020/01/14_
- Fix #11: update chown path to library, comment chown to an obsolete healthcheck.sh.
- Ongoing #5: pass $CI_PROJECT_URL to the Dockerfile as a build argument.
# __[2.0.0](https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.0.0)__ | _2020/01/06_
## [2.0.3] - 2020/01/14
- Read [the docs](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg) a bit more (#5)
## [2.0.2] - 2020/01/14
- Propagate the CI_COMMIT_TAG and CI_PROJECT_URL environment variables into the Dockerfile as [the docs states](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg) (#5)
## [2.0.1] - 2020/01/14
- Update chown path to library, comment chown to an obsolete healthcheck.sh (#11)
- Pass $CI_PROJECT_URL to the Dockerfile as a build argument (#5)
## [2.0.0] - 2020/01/06
- Support 2FA authentication through `oathtool` using the secret key
- Support for upload/download limits
- Support for Seafile library password
@@ -28,42 +62,62 @@
- Revise README
- Change the volume path from /volume to /library for consistency
### __[1.2.1](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.2.1)__ | _2019/12/29_
- Fix #4:
- Switch base image from Debian oldoldstable Jessie to Debian stable Buster to fix unmet dependencies of `seafile-cli` to `python-future` and `python-searpc`
- Replace `;` with `&&` as commands separators in the Dockerfile's `RUN` to properly report failed commands at CI
## __[1.2.0](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.2.0)__ | _2019/05/02_
## [1.2.1] - 2019/12/29
- Switch base image from Debian oldoldstable Jessie to Debian stable Buster to fix unmet dependencies of `seafile-cli` to `python-future` and `python-searpc` (#4)
- Replace `;` with `&&` as commands separators in the Dockerfile's `RUN` to properly report failed commands at CI (#4)
## [1.2.0] - 2019/05/02
- Replace _supervisord_ with _cron_ for running the front job that keeps the container up. It uses less resources.
- Improve the __infinite-seaf-cli-start.sh__ into __seafile-healthcheck.sh__. The Seafile daemon will not be restarted if it's state are either _downloading_ or _committing_, which otherwise is problematic.
- Improve the infinite-seaf-cli-start.sh into seafile-healthcheck.sh. The Seafile daemon will not be restarted if it's state are either _downloading_ or _committing_, which otherwise is problematic.
### __[1.1.2](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.1.2)__ | _2019/04/18_
## [1.1.2] - 2019/04/18
- Slim down the Docker image, from 102MB to 67MB, gaining 35MB, reducing size by 34%.
### __[1.1.1](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.1.1)__ | _2019/04/18_
## [1.1.1] - 2019/04/18
- Because of the infinite-seaf-cli-start loop, within the container was running many seaf-daemons. Now, the infinite loop stop the current seaf-daemon before starting it again. (see #3)
## __[1.1.0](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.1.0)__ | _2019/04/09_
## [1.1.0] - 2019/04/09
- The container now actually use the UID/GID provided to it:
The container entrypoint is run with root, then another entrypoint is run by the container's user, seafuser, to run the Seafile client.
### __[1.0.6](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.6)__ | _2019/03/25_
## [1.0.6] - 2019/03/25
- More minor fixes from v1.0.4
### __[1.0.5](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.5)__ | _2019/03/25_
## [1.0.5] - 2019/03/25
- Minor fixes from v1.0.4
### __[1.0.4](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.4)__ | _2019/03/25_
## [1.0.4] - 2019/03/25
- Fix the build target detection (@a52559ddb38a64d7fceaa8bf9b8afd7356ccc439)
- Login to the Docker Hub from within the script, not the gitlab-ci.yml, using (@72bab017c1167b8ab35cef3cc709ff83686eaca4, @f69483354a4cf8afdbea89ef2bb1d9a9b7b2ac10)
- Require Bash on all Gitlab CI stages (@72bab017c1167b8ab35cef3cc709ff83686eaca4)
- Add a script to push the README.md into the Docker Hub repository's full_description (@8cb49cbc8253368701d718c2e38017790c78ceca, @ca6128fb96602da71f3b7a560e834d1b7587abac)
### __[1.0.3](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.3)__ | _2019/03/19_
## [1.0.3] - 2019/03/19
- Restrict staging pipelines to pushed pipelines
- Restrict production pipelines to pushed and triggered pipelines
- Require a build target on triggered production pipelines
### __[1.0.2](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.2)__ | _2019/03/18_
## [1.0.2] - 2019/03/18
- Fix a minor issue when testing for requested production build.
### __[1.0.1](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.1)__ | _2019/03/18_
## [1.0.1] - 2019/03/18
- Add failsafe when importing Seafile's APT-key
- Restrict production build to latest, majors, minors and revisions version, on-demand.
# __[1.0.0](https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.0)__ | _2019/03/15_
## [1.0.0] - 2019/03/15
- Release to Docker Hub
### __[0.9.2](https://gitlab.com/flwgns-docker/seafile-client/-/tags/0.9.2)__ | _2019/03/15_
## [0.9.2] - 2019/03/15
- Test release on GitLab, before Docker Hub
[2.2.0]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.2.0
[2.1.1]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.1.1
[2.1.0]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.1.0
[2.0.3]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.0.2
[2.0.2]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.0.2
[2.0.1]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.0.1
[2.0.0]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/2.0.0
[1.2.1]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.2.1
[1.2.0]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.2.0
[1.1.2]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.1.2
[1.1.1]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.1.1
[1.1.0]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.1.0
[1.0.6]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.6
[1.0.5]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.5
[1.0.4]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.4
[1.0.3]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.3
[1.0.2]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.2
[1.0.1]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.1
[1.0.0]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/1.0.0
[0.9.2]: https://gitlab.com/flwgns-docker/seafile-client/-/tags/0.9.2

View File

@@ -24,26 +24,92 @@ One great way to help is simply to say thanks. You can do that by [adding a star
# Project workflow
The ins and outs of the project, from setting up a local environment for developments to notifying users of changes.
To provide the different Seafile's client versions, the project rely on the [`seafile` package available throughout the different Debian versions][packages]. Check out [Debian Developer's Package Overview][ddpo] and [Debian Package Tracker][tracker] for in depth details regarding that package.
[packages]: https://packages.debian.org/search?keywords=seafile-cli
[ddpo]: https://qa.debian.org/developer.php?login=team%2Bseafile%40tracker.debian.org
[tracker]: https://tracker.debian.org/pkg/seafile
The following state diagram describe essentially the project workflow for a release.
```mermaid
stateDiagram-v2
feature: Checkout new branch from main
changes: Apply changes
mr: Create a Merge Request
pipelines: CI/CD pipelines must be successful
log: Changes must be documented
merge: Branch is squash merged into main
release: Release is created
[*] --> feature
feature --> changes
changes --> mr
mr --> pipelines
pipelines --> log
log --> merge
merge --> release
release --> [*]
```
## Environment
The following is required to develop:
* Docker engine
* Bash
* Make
## Development
## Management
A few utilities Bash scripts are available to operate the project:
* [build.sh](.utilities/build.sh): build the Docker image and save as a tarball
* [check.sh](.utilities/check.sh): validate CI pipelines
* [package_update_notifier.sh](.utilities/package_update_notifier.sh): notify, through a GitLab issue, if a new `seaf-cli` version is available
* [publish.sh](.utilities/publish.sh): tag and push the image to Docker Hub
* [test.sh](.utilities/test.sh): run the test suite
* [update-docker-hub-full-description.sh](.utilities/update-docker-hub-full-description.sh): push the README.md to the Docker Hub
* [utilities.sh](.utilities/utilities.sh): functions and assets
The project managemenet is mostly run through the Makefile.
Following a trunk-based development strategy, all changes must come from a short lived branch and fast-forward merged into master.
All commits must be squashed into a single commit referencing a specific issue.
The parameter `TARGET` define on which Debian version the instructions are run.
## CI/CD
Tests are run only on merge requests, but they can be run on demand in a local environment.
The [CHANGELOG.md](CHANGELOG.md) and [AUTHORS.md](AUTHORS.md) will be updated on every merge.
Only merge resquests associated with a milestone will end up in a new release. The [README.md](README.md) will be updated then. Description pages for Docker Hub and Seafile's forum will be templated then as well and made available as artifacts for a manual update since #10 and #17 are still opened issues.
The following instructions are available:
### mock
Start the Docker Compose mock for a Seafile server.
### unmock
Start the Docker Compose mock for a Seafile server.
### client
Purge and start the client service on the Docker Compose mock for a Seafile server.
### logs
Continuously display the logs from the client service on the Docker Compose mock for a Seafile server.
### build
Build the Seafile Docker client image depending on the `TARGET`.
### build-test
Build the Seafile Docker client test image depending on the `TARGET`.
### test
Run the Seafile Docker client test container.
### documents
Build the documentation for both Docker Hub and Seafile's forum.
### publish-images
Publish the Docker Seafile client image, properly tagged with the appropriate Seafile cliens versions.
### publish-documents
Publish the generated documentation on Docker Hub only
### save
Export the Seafile Docker client image as a tarball.
### load
Load the Seafile Docker client image from a tarball
## Pipelines
Pipelines are run either on merge requests or on commit tags.
The pipelines are divided into three stages:
* Build
* Test
* Release
Release jobs are obviously not run on merge requests.

View File

@@ -1,71 +0,0 @@
# 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/>.
FROM debian:bullseye-slim
ARG BUILD_DATE
ARG VCS_REF
ARG VERSION
ARG PROJECT_URL
LABEL maintainer="flow.gunso@gmail.com" \
org.label-schema.build-date=$BUILD_DATE \
org.label-schema.name="Seafile Docker client" \
org.label-schema.description="Sync Seafile librairies within Docker containers." \
org.label-schema.url=$PROJECT_URL \
org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.vcs-url=$PROJECT_URL \
org.label-schema.vendor="flow.gunso@gmail.com" \
org.label-schema.version=$VERSION \
org.label-schema.schema-version="1.0"
# Copy over the assets.
COPY seafile-client/docker-entrypoint.sh /entrypoint.sh
COPY seafile-client/docker-healthcheck.sh /healthcheck.sh
COPY tests /tests
# Install seaf-cli and oathtool, prepare the user.
ENV DEBIAN_FRONTEND=noninteractive
ENV UNAME=seafuser UID=1000 GID=1000
RUN apt-get update && apt-get install -y gnupg wget && \
mkdir -p /etc/apt/sources.list.d/ && \
wget https://linux-clients.seafile.com/seafile.asc -O /usr/share/keyrings/seafile-keyring.asc && \
bash -c "echo 'deb [arch=amd64 signed-by=/usr/share/keyrings/seafile-keyring.asc] https://linux-clients.seafile.com/seafile-deb/bullseye/ stable main' > /etc/apt/sources.list.d/seafile.list" && \
apt-get purge --yes gnupg wget && apt-get autoremove --yes && \
apt-get update && apt-get install \
--no-install-recommends \
--yes \
seafile-cli \
oathtool && \
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/* \
mkdir /library/ && \
groupadd -g $GID -o $UNAME && \
useradd -m -u $UID -g $GID -o -s /bin/bash $UNAME && \
mkdir /home/$UNAME/.seafile && \
chown $UNAME:$GID /home/$UNAME/.seafile
COPY seafile-client/seafile-entrypoint.sh /home/seafuser/entrypoint.sh
COPY seafile-client/seafile-healthcheck.py /home/seafuser/healthcheck.py
RUN chmod +x /home/$UNAME/healthcheck.py && \
chown $UNAME:$GID /home/$UNAME/
ENTRYPOINT ["/bin/bash", "--"]
CMD ["/entrypoint.sh"]
HEALTHCHECK --start-period=1m CMD /healthcheck.sh

49
Makefile Normal file
View File

@@ -0,0 +1,49 @@
TARGET?=unstable
mock:
docker compose -f tests/mock/compose.yaml up -d
unmock:
docker compose -f tests/mock/compose.yaml down
client:
docker compose -f tests/mock/compose.yaml rm -fs client
docker compose -f tests/mock/compose.yaml up -d client
shell:
docker compose -f tests/mock/compose.yaml exec client bash
logs:
docker compose -f tests/mock/compose.yaml logs -f client
build:
TARGET=${TARGET} CI_COMMIT_TAG=${CI_COMMIT_TAG} bash scripts/build-images.sh
build-test:
docker build --build-arg TARGET=${TARGET} -t seafile-client:test tests/image
test:
docker run seafile-client:test
documents:
python scripts/make-documents.py docker.md.j2
python scripts/make-documents.py seafile.md.j2
publish-images:
TARGET=${TARGET} \
DOCKER_HUB_BOT_USERNAME=${DOCKER_HUB_BOT_USERNAME} \
DOCKER_HUB_BOT_TOKEN=${DOCKER_HUB_BOT_TOKEN} \
DOCKER_HUB_OWNER_USERNAME=${DOCKER_HUB_OWNER_USERNAME} \
DOCKER_HUB_OWNER_TOKEN=${DOCKER_HUB_OWNER_TOKEN} \
DOCKER_HUB_IMAGE=${DOCKER_HUB_IMAGE} \
bash scripts/publish-images.sh
publish-documents:
bash scripts/publish-documents.sh
save:
mkdir -p tarballs/
docker save --output tarballs/${TARGET}.tar seafile-client:${TARGET}
load:
docker load --input tarballs/${TARGET}.tar

181
README.md
View File

@@ -1,91 +1,153 @@
[![](https://img.shields.io/gitlab/pipeline/flwgns-docker/seafile-client/2.2.0?label=Build)](https://gitlab.com/flwgns-docker/seafile-client/commits/2.2.0)
[![](https://img.shields.io/docker/image-size/flowgunso/seafile-client/latest?label=Docker%20image%20size&color=%230778b8)](https://hub.docker.com/r/flowgunso/seafile-client)
[![](https://img.shields.io/docker/pulls/flowgunso/seafile-client?label=Docker%20pulls&color=%230778b8)](https://hub.docker.com/r/flowgunso/seafile-client)
[![](https://img.shields.io/badge/License-GPLv3-red.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![](https://img.shields.io/badge/Source%20code-GitLab-red.svg)](https://gitlab.com/flwgns-docker/seafile-client/)
[![][badge-pipeline]][url-pipelines]
[![][badge-image-size]][url-docker]
[![][badge-pulls]][url-docker]
[![][badge-release]][url-sources]
![][badge-license]
[url-pipelines]: https://gitlab.com/flwgns-docker/seafile-client/-/pipelines
[url-docker]: https://hub.docker.com/r/flowgunso/seafile-client
[url-sources]: https://gitlab.com/flwgns-docker/seafile-client/
[badge-pipeline]: https://img.shields.io/gitlab/pipeline-status/flwgns-docker%2Fseafile-client
[badge-image-size]: https://img.shields.io/docker/image-size/flowgunso/seafile-client/latest?logo=docker&label=Image%20size&color=%230778b8
[badge-pulls]: https://img.shields.io/docker/pulls/flowgunso/seafile-client?logo=docker&label=Pulls&color=%230778b8
[badge-license]: https://img.shields.io/gitlab/license/11322291?label=License&color=fca326
[badge-release]: https://img.shields.io/gitlab/v/release/11322291?logo=gitlab&label=Source%20code&color=fca326
**Share a Seafile library as a volume to other containers.**
# Supported tags
[`2`, `2.2`, `2.2.0`, `latest`](seafile-client/Dockerfile)
# Informations
* Synchronize a single Seafile library, available at the path `/library/'.
* Password protected librairies are supported.
* Two factor authentication is supported.
* Upload and download speeds are configurable.
* SSL certificates are skippable.
<!-- -->
* Ask questions on [Seafile forum](https://forum.seafile.com/t/docker-client-to-sync-files-with-containers/8573).
* Contribute and report issues on [Gitlab](https://gitlab.com/flwgns-docker/seafile-client/).
# Features
* Synchronize one or more Seafile libraries.
* Support password protected librairies.
* Support two factor authentication.
* Configure upload and download limits.
* Skip SSL certificates.
* Set file ownership with user/group ID
# Usage
## Required configuration
__SEAF_SERVER_URL__, __SEAF_USERNAME__, __SEAF_PASSWORD__, __SEAF_LIBRARY_UUID__
Provide your Seafile _server URL_, _username_, _password_ and _library UUID_ to synchronise your library at `/library`, then share it as a volume.
The `seaf-cli` is ran within the container as the user `seafuser`.
## Start a Seafile client
## Optional configurations
__SEAF_2FA_SECRET__
_Two factor authentication is supported but your secret key must be provided._ That key can be found on your Seafile web interface, only at the 2FA setup, when the QR code is shown. The secret key is embedded in the QR or available as a cookie.
__SEAF_LIBRARY_PASSWORD__
Password protected librairies can be sync provided with the _password_.
__SEAF_UPLOAD_LIMIT__, __SEAF_DOWNLOAD_LIMIT__
Upload and download speeds are configurable as _absolute bytes_.
__SEAF_SKIP_SSL_CERT__
Skip SSL certificates verifications. _Any string is considered true, omit the variable to set to false_. Enable this if you have synchronization failures regarding SSL certificates.
__UID__, __GID__
Override the _UID_ and _GID_ for volume read/write permissions.
# Examples
## As a Docker command
```
### Docker command-line
The following command start the Seafile client with one library:
```bash
docker run \
-e SEAF_SERVER_URL=https://seafile.example/ \
-e SEAF_USERNAME=a_seafile_user \
-e SEAF_PASSWORD=SoMePaSSWoRD \
-e SEAF_LIBRARY_UUID=an-hexadecimal-library-uuid \
-v path/to/shared/volume:/library \
-e SEAF_SERVER_URL="https://seafile.example/" \
-e SEAF_USERNAME="a_seafile_user" \
-e SEAF_PASSWORD="SoMePaSSWoRD" \
-e SEAF_LIBRARY="an-hexadecimal-library-uuid" \
-v path/to/library:/library \
-v path/to/client/data:/seafile \
flowgunso/seafile-client:latest
```
## As a Docker Compose
### Docker Compose
The following Docker Compose start a Seafile client with two libraries, with one password protected:
```yaml
version: "3"
services:
seafile-client:
image: flowgunso/seafile-client:latest
volumes:
- shared_volume:/library
- audio:/library/audio
- documents:/library/documents
- client:/seafile
environment:
SEAF_SERVER_URL: "https://seafile.example/"
SEAF_USERNAME: "a_seafile_user"
SEAF_PASSWORD: "SoMePaSSWoRD"
SEAF_LIBRARY_UUID: "an-hexadecimal-library-uuid"
SEAF_LIBRARY_AUDIO: "audio-library-uuid"
SEAF_LIBRARY_AUDIO_PASSWORD: "auDioLiBRaRyPaSSWoRD"
SEAF_LIBRARY_DOCUMENTS: "documents-library-uuid"
volumes:
shared_volume:
audio:
documents:
client:
```
## With all optional configurations
```yaml
## Librairies
Environment variables allows librairies configuration, as shown in the examples above.
You can configure either a single librairy or multiple librairies.
### Single library
To synchronize a single library, use the environment variables `SEAF_LIBRARY` and `SEAF_LIBRARY_PASSWORD`. The library will be synchronized in _/library_.
### Multiple librairies
To synchronise multiple librairies, use the same environment variable as above but suffixed with a single identifier word. That word will be used for the library password and it's synchronization path as well.
Hence, to synchronise a library identified as **audio**, the environment variables would be `SEAF_LIBRARY_AUDIO` for the library UUID and `SEAF_LIBRARY_AUDIO_PASSWORD` for the library password. The library will be then synchronized in _/library/audio_.
Identifiers allows to add as many libraries as possible. Identifier are single word only.
## Environment variables
Environment variable allows you to configure the Seafile client.
### `SEAF_SERVER_URL`
> This variable is mandatory.
The Seafile server URL.
### `SEAF_USERNAME`
> This variable is mandatory.
The username for the Seafile account.
### `SEAF_PASSWORD`
> This variable is mandatory.
The password for the Seafile account.
### `SEAF_LIBRARY`, `SEAF_LIBRARY_[IDENTIFIER]`
> This variable is mandatory.
The UUID of the library, libraries to synchronize.
Replace `[IDENTIFIER]` with the a unique single word identifier for each library you want to synchronize.
### `SEAF_LIBRARY_PASSWORD`, `SEAF_LIBRARY_[IDENTIFIER]_PASSWORD`
The password of the library, libraries to synchronize.
Replace `[IDENTIFIER]` with the a unique single word identifier for each library you want to synchronize corresponding to the `SEAF_LIBRARY_[IDENTIFIER]`.
### `SEAF_2FA_SECRET`
_Two factor authentication is supported but your secret key must be provided._ That key can be found on your Seafile web interface, only at the 2FA setup, when the QR code is shown. The secret key is embedded in the QR or available as a cookie.
### `SEAF_UPLOAD_LIMIT`, `SEAF_DOWNLOAD_LIMIT`
Set upload and download speeds limits. Limits are in bytes.
### `SEAF_SKIP_SSL_CERT`
Skip SSL certificates verifications.
> Any string is considered true, omit the variable to set to false. Enable this if you have synchronization failures regarding SSL certificates.
### `UID`, `GID`
Override the _UID_ and _GID_ for user running the Seafile client, hence the volume ownership.
## Docker Secrets
All environments variable supports Docker Secrets, as environment variable variant suffixed with `_FILE` as files.
## Full example
```bash
version: "3"
services:
seafile-client:
image: flowgunso/seafile-client:latest
volumes:
- shared_volume:/library
- audio:/library/audio
- documents:/library/documents
- client:/seafile
environment:
SEAF_SERVER_URL: "https://seafile.example/"
SEAF_USERNAME: "a_seafile_user"
SEAF_PASSWORD: "SoMePaSSWoRD"
SEAF_LIBRARY_UUID: "an-hexadecimal-library-uuid"
SEAF_LIBRARY_AUDIO: "audio-library-uuid"
SEAF_LIBRARY_AUDIO_PASSWORD: "auDioLiBRaRyPaSSWoRD"
SEAF_LIBRARY_DOCUMENTS: "documents-library-uuid"
SEAF_2FA_SECRET: "JBSWY3DPEHPK3PXPIXDAUMXEDOXIUCDXWC32CS"
SEAF_LIBRARY_PASSWORD: "LiBRaRyPaSSWoRD"
SEAF_UPLOAD_LIMIT: "1000000"
SEAF_DOWNLOAD_LIMIT: "1000000"
SEAF_SKIP_SSL_CERT: "true"
@@ -93,6 +155,11 @@ services:
GID: "1000"
volumes:
shared_volume:
audio:
documents:
client:
```
Or use the [docker-compose.yml](documentations/docker-compose.yml) template.
# Troubleshooting
* Ask questions on [Seafile forum](https://forum.seafile.com/t/docker-client-to-sync-files-with-containers/8573).
* Contribute and report issues on [Gitlab](https://gitlab.com/flwgns-docker/seafile-client/).

View File

@@ -0,0 +1,8 @@
docker run \
-e SEAF_SERVER_URL="https://seafile.example/" \
-e SEAF_USERNAME="a_seafile_user" \
-e SEAF_PASSWORD="SoMePaSSWoRD" \
-e SEAF_LIBRARY="an-hexadecimal-library-uuid" \
-v path/to/library:/library \
-v path/to/client/data:/seafile \
flowgunso/seafile-client:latest

View File

@@ -0,0 +1,28 @@
version: "3"
services:
seafile-client:
image: flowgunso/seafile-client:latest
volumes:
- audio:/library/audio
- documents:/library/documents
- client:/seafile
environment:
SEAF_SERVER_URL: "https://seafile.example/"
SEAF_USERNAME: "a_seafile_user"
SEAF_PASSWORD: "SoMePaSSWoRD"
SEAF_LIBRARY_AUDIO: "audio-library-uuid"
SEAF_LIBRARY_AUDIO_PASSWORD: "auDioLiBRaRyPaSSWoRD"
SEAF_LIBRARY_DOCUMENTS: "documents-library-uuid"
SEAF_2FA_SECRET: "JBSWY3DPEHPK3PXPIXDAUMXEDOXIUCDXWC32CS"
SEAF_UPLOAD_LIMIT: "1000000"
SEAF_DOWNLOAD_LIMIT: "1000000"
SEAF_SKIP_SSL_CERT: "true"
UID: "1000"
GID: "1000"
volumes:
audio:
documents:
client:

View File

@@ -0,0 +1,22 @@
version: "3"
services:
seafile-client:
image: flowgunso/seafile-client:latest
volumes:
- audio:/library/audio
- documents:/library/documents
- client:/seafile
environment:
SEAF_SERVER_URL: "https://seafile.example/"
SEAF_USERNAME: "a_seafile_user"
SEAF_PASSWORD: "SoMePaSSWoRD"
SEAF_LIBRARY_AUDIO: "audio-library-uuid"
SEAF_LIBRARY_AUDIO_PASSWORD: "auDioLiBRaRyPaSSWoRD"
SEAF_LIBRARY_DOCUMENTS: "documents-library-uuid"
volumes:
audio:
documents:
client:

View File

@@ -1,20 +0,0 @@
version: "3.4"
services:
seafile-client:
image: flowgunso/seafile-client:latest
volumes:
- shared_volume:/library
environment:
SEAF_SERVER_URL: "" # The URL to your Seafile server.
SEAF_USERNAME: "" # Your Seafile username.
SEAF_PASSWORD: "" # Your Seafile password.
SEAF_LIBRARY_UUID: "" # The Seafile library UUID you want to sync with.
# SEAF_LIBRARY_PASSWORD: "" # The Seafile library password, if required.
# SEAF_SKIP_SSL_CERT: "true" # Any string is true, omit to set to false.
# SEAF_2FA_SECRET: "" # The 2FA secret key available at Seafile 2FA setup.
# UID: "" # Default is 1000.
# GID: "" # Default is 1000.
volumes:
shared_volume:

View File

@@ -0,0 +1,11 @@
{% include "parts/badges.md.j2" %}
**Share a Seafile library as a volume to other containers.**
{% include "parts/supported_tags.md.j2" %}
{% include "parts/features.md.j2" %}
{% include "parts/usage.md.j2" %}
{% include "parts/troubleshooting.md.j2" %}

View File

@@ -0,0 +1,9 @@
{% include "parts/badges.md.j2" %}
**Share a Seafile library as a volume to other containers.**
{% include "parts/features.md.j2" %}
{% include "parts/usage.md.j2" %}
{% include "parts/troubleshooting.md.j2" %}

View File

@@ -0,0 +1,15 @@
[![][badge-pipeline]][url-pipelines]
[![][badge-image-size]][url-docker]
[![][badge-pulls]][url-docker]
[![][badge-release]][url-sources]
![][badge-license]
[url-pipelines]: https://gitlab.com/flwgns-docker/seafile-client/-/pipelines
[url-docker]: https://hub.docker.com/r/flowgunso/seafile-client
[url-sources]: https://gitlab.com/flwgns-docker/seafile-client/
[badge-pipeline]: https://img.shields.io/gitlab/pipeline-status/flwgns-docker%2Fseafile-client
[badge-image-size]: https://img.shields.io/docker/image-size/flowgunso/seafile-client/latest?logo=docker&label=Image%20size&color=%230778b8
[badge-pulls]: https://img.shields.io/docker/pulls/flowgunso/seafile-client?logo=docker&label=Pulls&color=%230778b8
[badge-license]: https://img.shields.io/gitlab/license/11322291?label=License&color=fca326
[badge-release]: https://img.shields.io/gitlab/v/release/11322291?logo=gitlab&label=Source%20code&color=fca326

View File

@@ -0,0 +1,7 @@
# Features
* Synchronize one or more Seafile libraries.
* Support password protected librairies.
* Support two factor authentication.
* Configure upload and download limits.
* Skip SSL certificates.
* Set file ownership with user/group ID

View File

@@ -0,0 +1,7 @@
# Supported tags
{% for version in versions %}
[{{ version | join(", ")}}][Dockerfile]
{% endfor %}
[Dockerfile]: https://gitlab.com/flwgns-docker/seafile-client/-/blob/master/Dockerfile

View File

@@ -0,0 +1,3 @@
# Troubleshooting
* Ask questions on [Seafile forum](https://forum.seafile.com/t/docker-client-to-sync-files-with-containers/8573).
* Contribute and report issues on [Gitlab](https://gitlab.com/flwgns-docker/seafile-client/).

View File

@@ -0,0 +1,80 @@
# Usage
## Start a Seafile client
### Docker command-line
The following command start the Seafile client with one library:
```bash
{% include "assets/cli.bash" %}
```
### Docker Compose
The following Docker Compose start a Seafile client with two libraries, with one password protected:
```yaml
{% include "assets/compose.yaml" %}
```
## Librairies
Environment variables allows librairies configuration, as shown in the examples above.
You can configure either a single librairy or multiple librairies.
### Single library
To synchronize a single library, use the environment variables `SEAF_LIBRARY` and `SEAF_LIBRARY_PASSWORD`. The library will be synchronized in _/library_.
### Multiple librairies
To synchronise multiple librairies, use the same environment variable as above but suffixed with a single identifier word. That word will be used for the library password and it's synchronization path as well.
Hence, to synchronise a library identified as **audio**, the environment variables would be `SEAF_LIBRARY_AUDIO` for the library UUID and `SEAF_LIBRARY_AUDIO_PASSWORD` for the library password. The library will be then synchronized in _/library/audio_.
Identifiers allows to add as many libraries as possible. Identifier are single word only.
## Environment variables
Environment variable allows you to configure the Seafile client.
### `SEAF_SERVER_URL`
> This variable is mandatory.
The Seafile server URL.
### `SEAF_USERNAME`
> This variable is mandatory.
The username for the Seafile account.
### `SEAF_PASSWORD`
> This variable is mandatory.
The password for the Seafile account.
### `SEAF_LIBRARY`, `SEAF_LIBRARY_[IDENTIFIER]`
> This variable is mandatory.
The UUID of the library, libraries to synchronize.
Replace `[IDENTIFIER]` with the a unique single word identifier for each library you want to synchronize.
### `SEAF_LIBRARY_PASSWORD`, `SEAF_LIBRARY_[IDENTIFIER]_PASSWORD`
The password of the library, libraries to synchronize.
Replace `[IDENTIFIER]` with the a unique single word identifier for each library you want to synchronize corresponding to the `SEAF_LIBRARY_[IDENTIFIER]`.
### `SEAF_2FA_SECRET`
_Two factor authentication is supported but your secret key must be provided._ That key can be found on your Seafile web interface, only at the 2FA setup, when the QR code is shown. The secret key is embedded in the QR or available as a cookie.
### `SEAF_UPLOAD_LIMIT`, `SEAF_DOWNLOAD_LIMIT`
Set upload and download speeds limits. Limits are in bytes.
### `SEAF_SKIP_SSL_CERT`
Skip SSL certificates verifications.
> Any string is considered true, omit the variable to set to false. Enable this if you have synchronization failures regarding SSL certificates.
### `UID`, `GID`
Override the _UID_ and _GID_ for user running the Seafile client, hence the volume ownership.
## Docker Secrets
All environments variable supports Docker Secrets, as environment variable variant suffixed with `_FILE` as files.
## Full example
```bash
{% include "assets/compose-full.yaml" %}
```

View File

@@ -11,17 +11,18 @@ Example usage with docker-compose and for the docker cli are provided. Essential
Feedback is welcome so I can keep improving it.
# Quick informations
**[flowgunso/seafile-client](https://hub.docker.com/r/flowgunso/seafile-client)** on Docker Hub, latest stable version: **2.1.1**
**[flowgunso/seafile-client](https://hub.docker.com/r/flowgunso/seafile-client)** on Docker Hub, latest stable version: **{{version}}**
Contribute and report issues on [Gitlab](https://gitlab.com/flwgns-docker/seafile-client/).
## Features
* Synchronize a single Seafile library, available at the path `/library/'.
* Password protected librairies are supported.
* Two factor authentication is supported.
* Upload and download speeds are configurable.
* SSL certificates are skippable.
{% include "parts/supported_tags.md.j2" %}
# Change log
{% include "parts/features.md.j2" %}
{% include "parts/usage.md.j2" %}
{% include "parts/troubleshooting.md.j2" %}
# Changelog
[details]
{{ changelog }}
[/details]
{{changelog}}
[/details]

View File

@@ -16,12 +16,19 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# Prepare the build arguments
build_args=(CREATED=$(date -u +"%Y-%m-%dT%H:%M:%SZ"))
[[ "$CI_COMMIT_SHA" ]] && build_args+=(REVISION=$CI_COMMIT_SHA)
[[ "$CI_COMMIT_TAG" ]] && build_args+=(VERSION=$CI_COMMIT_TAG)
[[ "$TARGET" ]] && build_args+=(TARGET=$TARGET)
# Build the build argumets string.
build_arguments=""
for build_arg in "${build_args[@]}"; do
build_arguments+="--build-arg $build_arg "
done
docker build \
--build-arg BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
--build-arg VCS_REF=$(git rev-parse --short HEAD) \
--build-arg VERSION=$CI_COMMIT_TAG \
--build-arg PROJECT_URL=$CI_PROJECT_URL \
--tag $CI_PROJECT_NAME:build .
docker save --output $CI_PROJECT_NAME.tar $CI_PROJECT_NAME:build
$build_arguments \
--tag seafile-client:$TARGET \
seafile-client/

54
scripts/make-documents.py Executable file
View File

@@ -0,0 +1,54 @@
# !/usr/bin/env python
from pathlib import Path
import argparse
from jinja2 import Environment, FileSystemLoader
REPOSITORY_PATH = Path(__file__).parent.parent
# Argument parsing.
parser = argparse.ArgumentParser(prog="Seafile Docker client documentation renderer")
parser.add_argument("template", type=str)
args = parser.parse_args()
# Setup Jinja2 templater
documentations_path = REPOSITORY_PATH.joinpath("documentations")
loader = FileSystemLoader(documentations_path)
environment = Environment(loader=loader)
template = environment.get_template(args.template)
buffer=[]
for path in Path("versions").iterdir():
with open(path, "rt") as fo:
buffer.append(fo.read().strip())
buffer.sort(reverse=True)
# Prepare the render context.
latest = True
versions = []
for line in buffer:
version = line.strip()
parts = version.split(".")
increments = []
blocks = []
for part in parts:
increments.append(part)
section = ".".join(increments)
blocks.append(f"`{section}`")
if latest:
blocks.append("`latest`")
latest = False
versions.append(blocks)
# Render
content = template.render(versions=versions)
#content = template.render() # When version/ is unavailable.
filename = Path(args.template).with_suffix("")
document = documentations_path.joinpath(filename)
# Write to file
with open(document, mode="w") as fo:
fo.write(content)

View File

@@ -0,0 +1,19 @@
# Get a token from hub.docker.com with the owner credentials.
token=$(curl -s \
-X POST \
-H "Content-Type: application/json" \
-d '{"username": "'"$DOCKER_HUB_OWNER_USERNAME"'", "password": "'"$DOCKER_HUB_OWNER_TOKEN"'"}' \
https://hub.docker.com/v2/users/login/ | jq -r .token)
# Generate a JSON with the README.md as the full_description.
json=$(jq -n \
--arg readme "$(<documentations/docker.md)" \
'{"full_description": $readme,"description":"Synchronize a Seafile library. Support password protected librairies and 2FA authentication."}')
# Update the Docker Hub repository's full_description.
curl -siL \
-X PATCH \
-d "$json" \
-H "Content-Type: application/json" \
-H "Authorization: JWT $token" \
"https://hub.docker.com/v2/repositories/$DOCKER_HUB_IMAGE/"

56
scripts/publish-images.sh Normal file
View File

@@ -0,0 +1,56 @@
# !/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/>.
set -ex
raise() {
echo $1
exit 1
}
# Validate the required parameters.
# [[ -z "$DOCKER_HUB_BOT_USERNAME" ]] && raise "Missing DOCKER_HUB_BOT_USERNAME envvar."
# [[ -z "$DOCKER_HUB_BOT_TOKEN" ]] && raise "Missing DOCKER_HUB_BOT_TOKEN envvar."
# [[ -z "$DOCKER_HUB_OWNER_USERNAME" ]] && raise "Missing DOCKER_HUB_OWNER_USERNAME envvar."
# [[ -z "$DOCKER_HUB_OWNER_TOKEN" ]] && raise "Missing DOCKER_HUB_OWNER_TOKEN envvar."
# [[ -z "$DOCKER_HUB_IMAGE" ]] && raise "Missing DOCKER_HUB_IMAGE envvar"
# Grab version with the container
version="$(docker run --rm seafile-client:$TARGET cat -s /SEAFILE_VERSION)"
version="$(echo ${version%-*})"
# Output the version to an artifact for documentation rendering.
mkdir -p versions/
echo $version >> "versions/$TARGET"
# Generate version tags.
tags=()
#[[ "$TARGET" =~ "unstable" ]] && tags+=("latest")
for version_component in $(echo $version | tr '.' '\n'); do
tag+="$version_component"
tags+=("$tag")
tag+="."
done
# Tag then push to the Docker Hub registry.
echo $DOCKER_HUB_BOT_TOKEN | docker login --password-stdin --username $DOCKER_HUB_BOT_USERNAME
for tag in "${tags[@]}"; do
docker tag seafile-client:$TARGET $DOCKER_HUB_IMAGE:$tag
docker push $DOCKER_HUB_IMAGE:$tag
done

55
seafile-client/Dockerfile Normal file
View 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"]

View File

@@ -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

View File

@@ -1,24 +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/>.
# Grab the status of the active repos then return as healthy/unhealthy
# depending the healthy statuses.
su - $UNAME << EO
~/healthcheck.py -c ~/.seafile/seafile-data/ $SEAF_LIBRARY_UUID
EO

View File

@@ -16,6 +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/>.
pip install -r .utilities/templates/requirements.txt
#!/bin/bash
python .utilities/templates/templater.py $CI_COMMIT_SHA
set -e
groupmod -g $GID seafile &> /dev/null
usermod -u $UID -g $GID seafile &> /dev/null
sudo \
-HE \
-u seafile \
-- "$@"

View 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
View File

@@ -0,0 +1,4 @@
┌───────────────────────┐
│ Seafile Docker client │
└───────────────────────┘
Run `./entrypoint.sh bash` to login as the seafile user.

View File

@@ -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

View File

@@ -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.")

6
tests/image/Dockerfile Normal file
View File

@@ -0,0 +1,6 @@
ARG TARGET=unstable
FROM seafile-client:${TARGET}
COPY --chmod=755 test_binaries.sh /test.sh
CMD ["/test.sh"]

52
tests/mock/compose.yaml Normal file
View File

@@ -0,0 +1,52 @@
services:
mariadb:
image: mariadb:10.11
environment:
- MYSQL_ROOT_PASSWORD=password # Requested, set the root's password of MySQL service.
- MYSQL_LOG_CONSOLE=true
- MARIADB_AUTO_UPGRADE=1
volumes:
- database:/var/lib/mysql # Requested, specifies the path to MySQL data persistent store.
memcached:
image: memcached:1.6.18
container_name: seafile-memcached
entrypoint: memcached -m 256
seafile:
image: seafileltd/seafile-mc:latest
ports:
- "80:80"
volumes:
- seafile:/shared # Requested, specifies the path to Seafile data persistent store.
environment:
- DB_HOST=mariadb
- DB_ROOT_PASSWD=password # Requested, the value should be root's password of MySQL service.
- TIME_ZONE=Etc/UTC # Optional, default is UTC. Should be uncomment and set to your local time zone.
- SEAFILE_ADMIN_EMAIL=seafile@localhost # Specifies Seafile admin user, default is 'me@example.com'.
- SEAFILE_ADMIN_PASSWORD=password # Specifies Seafile admin password, default is 'asecret'.
- SEAFILE_SERVER_LETSENCRYPT=false # Whether to use https or not.
depends_on:
- mariadb
- memcached
client:
image: seafile-client:unstable
volumes:
#- library:/library
- data:/seafile
# user: "1000:1000"
environment:
SEAF_SERVER_URL: "http://seafile"
SEAF_USERNAME: "seafile@localhost"
SEAF_PASSWORD: "password"
SEAF_LIBRARY_UUID: "1b7d4e92-6753-4c4a-85b0-42566eab42c8"
DEBUG: 1
depends_on:
- seafile
volumes:
database:
seafile:
library:
data: