Compare commits

..

1 Commits

Author SHA1 Message Date
Daira Hopwood 1f2574b9a2 Oops, check_requirement doesn't support ==.
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
2015-07-29 01:04:55 +01:00
641 changed files with 63213 additions and 98998 deletions

View File

@ -1,28 +0,0 @@
ARG TAG
FROM debian:${TAG}
ARG PYTHON_VERSION
ENV DEBIAN_FRONTEND noninteractive
ENV WHEELHOUSE_PATH /tmp/wheelhouse
ENV VIRTUALENV_PATH /tmp/venv
# This will get updated by the CircleCI checkout step.
ENV BUILD_SRC_ROOT /tmp/project
RUN apt-get --quiet update && \
apt-get --quiet --yes install \
git \
lsb-release \
sudo \
build-essential \
python${PYTHON_VERSION} \
python${PYTHON_VERSION}-dev \
libffi-dev \
libssl-dev \
libyaml-dev \
virtualenv \
tor
# Get the project source. This is better than it seems. CircleCI will
# *update* this checkout on each job run, saving us more time per-job.
COPY . ${BUILD_SRC_ROOT}
RUN "${BUILD_SRC_ROOT}"/.circleci/prepare-image.sh "${WHEELHOUSE_PATH}" "${VIRTUALENV_PATH}" "${BUILD_SRC_ROOT}" "python${PYTHON_VERSION}"

View File

@ -1,27 +0,0 @@
ARG TAG
FROM fedora:${TAG}
ARG PYTHON_VERSION
ENV WHEELHOUSE_PATH /tmp/wheelhouse
ENV VIRTUALENV_PATH /tmp/venv
# This will get updated by the CircleCI checkout step.
ENV BUILD_SRC_ROOT /tmp/project
# XXX net-tools is actually a Tahoe-LAFS runtime dependency!
RUN yum install --assumeyes \
git \
sudo \
make automake gcc gcc-c++ \
python${PYTHON_VERSION} \
python${PYTHON_VERSION}-devel \
libffi-devel \
openssl-devel \
libyaml-devel \
/usr/bin/virtualenv \
net-tools
# Get the project source. This is better than it seems. CircleCI will
# *update* this checkout on each job run, saving us more time per-job.
COPY . ${BUILD_SRC_ROOT}
RUN "${BUILD_SRC_ROOT}"/.circleci/prepare-image.sh "${WHEELHOUSE_PATH}" "${VIRTUALENV_PATH}" "${BUILD_SRC_ROOT}" "python${PYTHON_VERSION}"

View File

@ -1,26 +0,0 @@
ARG TAG
FROM oraclelinux:${TAG}
ARG PYTHON_VERSION
ENV WHEELHOUSE_PATH /tmp/wheelhouse
ENV VIRTUALENV_PATH /tmp/venv
# This will get updated by the CircleCI checkout step.
ENV BUILD_SRC_ROOT /tmp/project
# XXX net-tools is actually a Tahoe-LAFS runtime dependency!
RUN yum install --assumeyes \
git \
sudo \
make automake gcc gcc-c++ \
python${PYTHON_VERSION} \
libffi-devel \
openssl-devel \
libyaml \
/usr/bin/virtualenv \
net-tools
# Get the project source. This is better than it seems. CircleCI will
# *update* this checkout on each job run, saving us more time per-job.
COPY . ${BUILD_SRC_ROOT}
RUN "${BUILD_SRC_ROOT}"/.circleci/prepare-image.sh "${WHEELHOUSE_PATH}" "${VIRTUALENV_PATH}" "${BUILD_SRC_ROOT}" "python${PYTHON_VERSION}"

View File

@ -1,23 +0,0 @@
FROM pypy:2.7-buster
ENV WHEELHOUSE_PATH /tmp/wheelhouse
ENV VIRTUALENV_PATH /tmp/venv
# This will get updated by the CircleCI checkout step.
ENV BUILD_SRC_ROOT /tmp/project
RUN apt-get --quiet update && \
apt-get --quiet --yes install \
git \
lsb-release \
sudo \
build-essential \
libffi-dev \
libssl-dev \
libyaml-dev \
virtualenv
# Get the project source. This is better than it seems. CircleCI will
# *update* this checkout on each job run, saving us more time per-job.
COPY . ${BUILD_SRC_ROOT}
RUN "${BUILD_SRC_ROOT}"/.circleci/prepare-image.sh "${WHEELHOUSE_PATH}" "${VIRTUALENV_PATH}" "${BUILD_SRC_ROOT}" "pypy"

View File

@ -1,30 +0,0 @@
ARG TAG
FROM ubuntu:${TAG}
ARG PYTHON_VERSION
ENV DEBIAN_FRONTEND noninteractive
ENV WHEELHOUSE_PATH /tmp/wheelhouse
ENV VIRTUALENV_PATH /tmp/venv
# This will get updated by the CircleCI checkout step.
ENV BUILD_SRC_ROOT /tmp/project
# language-pack-en included to support the en_US LANG setting.
# iproute2 necessary for automatic address detection/assignment.
RUN apt-get --quiet update && \
apt-get --quiet --yes install git && \
apt-get --quiet --yes install \
sudo \
build-essential \
python${PYTHON_VERSION} \
python${PYTHON_VERSION}-dev \
libffi-dev \
libssl-dev \
libyaml-dev \
virtualenv \
language-pack-en \
iproute2
# Get the project source. This is better than it seems. CircleCI will
# *update* this checkout on each job run, saving us more time per-job.
COPY . ${BUILD_SRC_ROOT}
RUN "${BUILD_SRC_ROOT}"/.circleci/prepare-image.sh "${WHEELHOUSE_PATH}" "${VIRTUALENV_PATH}" "${BUILD_SRC_ROOT}" "python${PYTHON_VERSION}"

View File

@ -1,78 +0,0 @@
# A master build looks like this:
# BASH_ENV=/tmp/.bash_env-63d018969ca480003a031e62-0-build
# CI=true
# CIRCLECI=true
# CIRCLE_BRANCH=master
# CIRCLE_BUILD_NUM=76545
# CIRCLE_BUILD_URL=https://circleci.com/gh/tahoe-lafs/tahoe-lafs/76545
# CIRCLE_JOB=NixOS 21.11
# CIRCLE_NODE_INDEX=0
# CIRCLE_NODE_TOTAL=1
# CIRCLE_PROJECT_REPONAME=tahoe-lafs
# CIRCLE_PROJECT_USERNAME=tahoe-lafs
# CIRCLE_REPOSITORY_URL=git@github.com:tahoe-lafs/tahoe-lafs.git
# CIRCLE_SHA1=ed0bda2d7456f4a2cd60870072e1fe79864a49a1
# CIRCLE_SHELL_ENV=/tmp/.bash_env-63d018969ca480003a031e62-0-build
# CIRCLE_USERNAME=alice
# CIRCLE_WORKFLOW_ID=6d9bb71c-be3a-4659-bf27-60954180619b
# CIRCLE_WORKFLOW_JOB_ID=0793c975-7b9f-489f-909b-8349b72d2785
# CIRCLE_WORKFLOW_WORKSPACE_ID=6d9bb71c-be3a-4659-bf27-60954180619b
# CIRCLE_WORKING_DIRECTORY=~/project
# A build of an in-repo PR looks like this:
# BASH_ENV=/tmp/.bash_env-63d1971a0298086d8841287e-0-build
# CI=true
# CIRCLECI=true
# CIRCLE_BRANCH=3946-less-chatty-downloads
# CIRCLE_BUILD_NUM=76612
# CIRCLE_BUILD_URL=https://circleci.com/gh/tahoe-lafs/tahoe-lafs/76612
# CIRCLE_JOB=NixOS 21.11
# CIRCLE_NODE_INDEX=0
# CIRCLE_NODE_TOTAL=1
# CIRCLE_PROJECT_REPONAME=tahoe-lafs
# CIRCLE_PROJECT_USERNAME=tahoe-lafs
# CIRCLE_PULL_REQUEST=https://github.com/tahoe-lafs/tahoe-lafs/pull/1251
# CIRCLE_PULL_REQUESTS=https://github.com/tahoe-lafs/tahoe-lafs/pull/1251
# CIRCLE_REPOSITORY_URL=git@github.com:tahoe-lafs/tahoe-lafs.git
# CIRCLE_SHA1=921a2083dcefdb5f431cdac195fc9ac510605349
# CIRCLE_SHELL_ENV=/tmp/.bash_env-63d1971a0298086d8841287e-0-build
# CIRCLE_USERNAME=bob
# CIRCLE_WORKFLOW_ID=5e32c12e-be37-4868-9fa8-6a6929fec2f1
# CIRCLE_WORKFLOW_JOB_ID=316ca408-81b4-4c96-bbdd-644e4c3e01e5
# CIRCLE_WORKFLOW_WORKSPACE_ID=5e32c12e-be37-4868-9fa8-6a6929fec2f1
# CIRCLE_WORKING_DIRECTORY=~/project
# CI_PULL_REQUEST=https://github.com/tahoe-lafs/tahoe-lafs/pull/1251
# A build of a PR from a fork looks like this:
# BASH_ENV=/tmp/.bash_env-63d40f7b2e89cd3de10e0db9-0-build
# CI=true
# CIRCLECI=true
# CIRCLE_BRANCH=pull/1252
# CIRCLE_BUILD_NUM=76678
# CIRCLE_BUILD_URL=https://circleci.com/gh/tahoe-lafs/tahoe-lafs/76678
# CIRCLE_JOB=NixOS 21.05
# CIRCLE_NODE_INDEX=0
# CIRCLE_NODE_TOTAL=1
# CIRCLE_PROJECT_REPONAME=tahoe-lafs
# CIRCLE_PROJECT_USERNAME=tahoe-lafs
# CIRCLE_PR_NUMBER=1252
# CIRCLE_PR_REPONAME=tahoe-lafs
# CIRCLE_PR_USERNAME=carol
# CIRCLE_PULL_REQUEST=https://github.com/tahoe-lafs/tahoe-lafs/pull/1252
# CIRCLE_PULL_REQUESTS=https://github.com/tahoe-lafs/tahoe-lafs/pull/1252
# CIRCLE_REPOSITORY_URL=git@github.com:tahoe-lafs/tahoe-lafs.git
# CIRCLE_SHA1=15c7916e0812e6baa2a931cd54b18f3382a8456e
# CIRCLE_SHELL_ENV=/tmp/.bash_env-63d40f7b2e89cd3de10e0db9-0-build
# CIRCLE_USERNAME=
# CIRCLE_WORKFLOW_ID=19c917c8-3a38-4b20-ac10-3265259fa03e
# CIRCLE_WORKFLOW_JOB_ID=58e95215-eccf-4664-a231-1dba7fd2d323
# CIRCLE_WORKFLOW_WORKSPACE_ID=19c917c8-3a38-4b20-ac10-3265259fa03e
# CIRCLE_WORKING_DIRECTORY=~/project
# CI_PULL_REQUEST=https://github.com/tahoe-lafs/tahoe-lafs/pull/1252
# A build of a PR from a fork where the owner has enabled CircleCI looks
# the same as a build of an in-repo PR, except it runs on th owner's
# CircleCI namespace.

View File

@ -1,807 +0,0 @@
# https://circleci.com/docs/2.0/
# We use version 2.1 of CircleCI's configuration format (the docs are still at
# the 2.0 link) in order to have access to Windows executors. This means we
# can't use dots in job names anymore. They have a new "parameters" feature
# that is supposed to remove the need to have version numbers in job names (the
# source of our dots), but switching to that is going to be a bigger refactor:
#
# https://discuss.circleci.com/t/v2-1-job-name-validation/31123
# https://circleci.com/docs/2.0/reusing-config/
#
version: 2.1
# Every job that pushes a Docker image from Docker Hub must authenticate to
# it. Define a couple yaml anchors that can be used to supply the necessary
# credentials.
# First is a CircleCI job context which makes Docker Hub credentials available
# in the environment.
#
# Contexts are managed in the CircleCI web interface:
#
# https://app.circleci.com/settings/organization/github/tahoe-lafs/contexts
dockerhub-context-template: &DOCKERHUB_CONTEXT
context: "dockerhub-auth"
# Required environment for using the coveralls tool to upload partial coverage
# reports and then finish the process.
coveralls-environment: &COVERALLS_ENVIRONMENT
COVERALLS_REPO_TOKEN: "JPf16rLB7T2yjgATIxFzTsEgMdN1UNq6o"
# Next is a Docker executor template that gets the credentials from the
# environment and supplies them to the executor.
dockerhub-auth-template: &DOCKERHUB_AUTH
- auth:
username: $DOCKERHUB_USERNAME
password: $DOCKERHUB_PASSWORD
# A template that can be shared between the two different image-building
# workflows.
.images: &IMAGES
jobs:
- "build-image-debian-11":
<<: *DOCKERHUB_CONTEXT
- "build-image-ubuntu-20-04":
<<: *DOCKERHUB_CONTEXT
- "build-image-ubuntu-22-04":
<<: *DOCKERHUB_CONTEXT
- "build-image-fedora-35":
<<: *DOCKERHUB_CONTEXT
- "build-image-oraclelinux-8":
<<: *DOCKERHUB_CONTEXT
# Restore later as PyPy38
#- "build-image-pypy27-buster":
# <<: *DOCKERHUB_CONTEXT
parameters:
# Control whether the image-building workflow runs as part of this pipeline.
# Generally we do not want this to run because we don't need our
# dependencies to move around all the time and because building the image
# takes a couple minutes.
#
# An easy way to trigger a pipeline with this set to true is with the
# rebuild-images.sh tool in this directory. You can also do so via the
# CircleCI web UI.
build-images:
default: false
type: "boolean"
# Control whether the test-running workflow runs as part of this pipeline.
# Generally we do want this to run because running the tests is the primary
# purpose of this pipeline.
run-tests:
default: true
type: "boolean"
workflows:
ci:
when: "<< pipeline.parameters.run-tests >>"
jobs:
# Start with jobs testing various platforms.
- "debian-11":
{}
- "ubuntu-20-04":
{}
- "ubuntu-22-04":
{}
# Equivalent to RHEL 8; CentOS 8 is dead.
- "oraclelinux-8":
{}
- "nixos":
name: "<<matrix.pythonVersion>>"
nixpkgs: "nixpkgs-unstable"
matrix:
parameters:
pythonVersion:
- "python39"
- "python310"
- "python311"
# Eventually, test against PyPy 3.8
#- "pypy27-buster":
# {}
# Other assorted tasks and configurations
- "codechecks":
{}
- "pyinstaller":
{}
- "c-locale":
{}
# Any locale other than C or UTF-8.
- "another-locale":
{}
- "windows-server-2022":
name: "Windows Server 2022, CPython <<matrix.pythonVersion>>"
matrix:
parameters:
# Run the job for a number of CPython versions. These are the
# two versions installed on the version of the Windows VM image
# we specify (in the executor). This is handy since it means we
# don't have to do any Python installation work. We pin the
# Windows VM image so these shouldn't shuffle around beneath us
# but if we want to update that image or get different versions
# of Python, we probably have to do something here.
pythonVersion:
- "3.9"
- "3.11"
- "integration":
# Run even the slow integration tests here. We need the `--` to
# sneak past tox and get to pytest.
tox-args: "-- --runslow integration"
requires:
# If the unit test suite doesn't pass, don't bother running the
# integration tests.
- "debian-11"
- "typechecks":
{}
- "docs":
{}
- "finish-coverage-report":
requires:
# Referencing the job by "alias" (as CircleCI calls the mapping
# key) instead of the value of its "name" property causes us to
# require every instance of the job from its matrix expansion. So
# this requirement is enough to require every Windows Server 2022
# job.
- "windows-server-2022"
images:
<<: *IMAGES
# Build as part of the workflow but only if requested.
when: "<< pipeline.parameters.build-images >>"
jobs:
finish-coverage-report:
docker:
- <<: *DOCKERHUB_AUTH
image: "python:3-slim"
steps:
- run:
name: "Indicate completion to coveralls.io"
environment:
<<: *COVERALLS_ENVIRONMENT
command: |
pip install coveralls==3.3.1
python -m coveralls --finish
codechecks:
docker:
- <<: *DOCKERHUB_AUTH
image: "cimg/python:3.9"
steps:
- "checkout"
- run: &INSTALL_TOX
name: "Install tox"
command: |
pip install --user 'tox~=3.0'
- run:
name: "Static-ish code checks"
command: |
~/.local/bin/tox -e codechecks
windows-server-2022:
parameters:
pythonVersion:
description: >-
An argument to pass to the `py` launcher to choose a Python version.
type: "string"
default: ""
executor: "windows"
environment:
# Tweak Hypothesis to make its behavior more suitable for the CI
# environment. This should improve reproducibility and lessen the
# effects of variable compute resources.
TAHOE_LAFS_HYPOTHESIS_PROFILE: "ci"
# Tell pip where its download cache lives. This must agree with the
# "save_cache" step below or caching won't really work right.
PIP_CACHE_DIR: "pip-cache"
# And tell pip where it can find out cached wheelhouse for fast wheel
# installation, even for projects that don't distribute wheels. This
# must also agree with the "save_cache" step below.
PIP_FIND_LINKS: "wheelhouse"
steps:
- "checkout"
# If possible, restore a pip download cache to save us from having to
# download all our Python dependencies from PyPI.
- "restore_cache":
keys:
# The download cache and/or the wheelhouse may contain Python
# version-specific binary packages so include the Python version
# in this key, as well as the canonical source of our
# dependencies.
- &CACHE_KEY "pip-packages-v1-<< parameters.pythonVersion >>-{{ checksum \"setup.py\" }}"
- "run":
name: "Fix $env:PATH"
command: |
# The Python this job is parameterized is not necessarily the one
# at the front of $env:PATH. Modify $env:PATH so that it is so we
# can just say "python" in the rest of the steps. Also get the
# related Scripts directory so tools from packages we install are
# also available.
$p = py -<<parameters.pythonVersion>> -c "import sys; print(sys.prefix)"
$q = py -<<parameters.pythonVersion>> -c "import sysconfig; print(sysconfig.get_path('scripts'))"
New-Item $Profile.CurrentUserAllHosts -Force
# $p gets "python" on PATH and $q gets tools from packages we
# install. Note we carefully construct the string so that
# $env:PATH is not substituted now but $p and $q are. ` is the
# PowerShell string escape character.
Add-Content -Path $Profile.CurrentUserAllHosts -Value "`$env:PATH = `"$p;$q;`$env:PATH`""
- "run":
name: "Display tool versions"
command: |
python misc/build_helpers/show-tool-versions.py
- "run":
# It's faster to install a wheel than a source package. If we don't
# have a cached wheelhouse then build all of the wheels and dump
# them into a directory where they can become a cached wheelhouse.
# We would have built these wheels during installation anyway so it
# doesn't cost us anything extra and saves us effort next time.
name: "(Maybe) Build Wheels"
command: |
if ((Test-Path .\wheelhouse) -and (Test-Path .\wheelhouse\*)) {
echo "Found populated wheelhouse, skipping wheel building."
} else {
python -m pip install wheel
python -m pip wheel --wheel-dir $env:PIP_FIND_LINKS .[testenv] .[test]
}
- "save_cache":
paths:
# Make sure this agrees with PIP_CACHE_DIR in the environment.
- "pip-cache"
- "wheelhouse"
key: *CACHE_KEY
- "run":
name: "Install Dependencies"
environment:
# By this point we should no longer need an index.
PIP_NO_INDEX: "1"
command: |
python -m pip install .[testenv] .[test]
- "run":
name: "Run Unit Tests"
environment:
# Configure the results location for the subunitv2-file reporter
# from subunitreporter
SUBUNITREPORTER_OUTPUT_PATH: "test-results.subunit2"
# Try to get prompt output from the reporter to avoid no-output
# timeouts.
PYTHONUNBUFFERED: "1"
command: |
# Run the test suite under coverage measurement using the
# parameterized version of Python, writing subunitv2-format
# results to the file given in the environment.
python -b -m coverage run -m twisted.trial --reporter=subunitv2-file --rterrors allmydata
- "run":
name: "Upload Coverage"
environment:
<<: *COVERALLS_ENVIRONMENT
# Mark the data as just one piece of many because we have more
# than one instance of this job (two on Windows now, some on other
# platforms later) which collects and reports coverage. This is
# necessary to cause Coveralls to merge multiple coverage results
# into a single report. Note the merge only happens when we
# "finish" a particular build, as identified by its "build_num"
# (aka "service_number").
COVERALLS_PARALLEL: "true"
command: |
python -m pip install coveralls==3.3.1
# .coveragerc sets parallel = True so we don't have a `.coverage`
# file but a `.coverage.<unique stuff>` file (or maybe more than
# one, but probably not). coveralls can't work with these so
# merge them before invoking it.
python -m coverage combine
# Now coveralls will be able to find the data, so have it do the
# upload. Also, have it strip the system config-specific prefix
# from all of the source paths.
$prefix = python -c "import sysconfig; print(sysconfig.get_path('purelib'))"
python -m coveralls --basedir $prefix
- "run":
name: "Convert Result Log"
command: |
# subunit2junitxml exits with error if the result stream it is
# converting has test failures in it! So this step might fail.
# Since the step in which we actually _ran_ the tests won't fail
# even if there are test failures, this is a good thing for now.
subunit2junitxml.exe --output-to=test-results.xml test-results.subunit2
- "store_test_results":
path: "test-results.xml"
- "store_artifacts":
path: "_trial_temp/test.log"
- "store_artifacts":
path: "eliot.log"
- "store_artifacts":
path: ".coverage"
pyinstaller:
docker:
- <<: *DOCKERHUB_AUTH
image: "cimg/python:3.9"
steps:
- "checkout"
- run:
<<: *INSTALL_TOX
- run:
name: "Make PyInstaller executable"
command: |
~/.local/bin/tox -e pyinstaller
- run:
# To verify that the resultant PyInstaller-generated binary executes
# cleanly (i.e., that it terminates with an exit code of 0 and isn't
# failing due to import/packaging-related errors, etc.).
name: "Test PyInstaller executable"
command: |
dist/Tahoe-LAFS/tahoe --version
debian-11: &DEBIAN
environment: &UTF_8_ENVIRONMENT
# In general, the test suite is not allowed to fail while the job
# succeeds. But you can set this to "yes" if you want it to be
# otherwise.
ALLOWED_FAILURE: "no"
# Tell Hypothesis which configuration we want it to use.
TAHOE_LAFS_HYPOTHESIS_PROFILE: "ci"
# Tell the C runtime things about character encoding (mainly to do with
# filenames and argv).
LANG: "en_US.UTF-8"
# Select a tox environment to run for this job.
TAHOE_LAFS_TOX_ENVIRONMENT: "py39"
# Additional arguments to pass to tox.
TAHOE_LAFS_TOX_ARGS: ""
# The path in which test artifacts will be placed.
ARTIFACTS_OUTPUT_PATH: "/tmp/artifacts"
# Convince all of our pip invocations to look at the cached wheelhouse
# we maintain.
WHEELHOUSE_PATH: &WHEELHOUSE_PATH "/tmp/wheelhouse"
PIP_FIND_LINKS: "file:///tmp/wheelhouse"
# Upload the coverage report.
UPLOAD_COVERAGE: ""
# pip cannot install packages if the working directory is not readable.
# We want to run a lot of steps as nobody instead of as root.
working_directory: "/tmp/project"
steps:
- "checkout"
- run: &SETUP_VIRTUALENV
name: "Setup virtualenv"
command: |
/tmp/project/.circleci/setup-virtualenv.sh \
"/tmp/venv" \
"/tmp/project" \
"${WHEELHOUSE_PATH}" \
"${TAHOE_LAFS_TOX_ENVIRONMENT}" \
"${TAHOE_LAFS_TOX_ARGS}"
- run: &RUN_TESTS
name: "Run test suite"
command: |
/tmp/project/.circleci/run-tests.sh \
"/tmp/venv" \
"/tmp/project" \
"${ALLOWED_FAILURE}" \
"${ARTIFACTS_OUTPUT_PATH}" \
"${TAHOE_LAFS_TOX_ENVIRONMENT}" \
"${TAHOE_LAFS_TOX_ARGS}"
# trial output gets directed straight to a log. avoid the circleci
# timeout while the test suite runs.
no_output_timeout: "20m"
- store_test_results: &STORE_TEST_RESULTS
path: "/tmp/artifacts/junit"
- store_artifacts: &STORE_TEST_LOG
# Despite passing --workdir /tmp to tox above, it still runs trial
# in the project source checkout.
path: "/tmp/project/_trial_temp/test.log"
- store_artifacts: &STORE_ELIOT_LOG
# Despite passing --workdir /tmp to tox above, it still runs trial
# in the project source checkout.
path: "/tmp/project/eliot.log"
- store_artifacts: &STORE_OTHER_ARTIFACTS
# Store any other artifacts, too. This is handy to allow other jobs
# sharing most of the definition of this one to be able to
# contribute artifacts easily.
path: "/tmp/artifacts"
- run: &SUBMIT_COVERAGE
name: "Submit coverage results"
command: |
if [ -n "${UPLOAD_COVERAGE}" ]; then
echo "TODO: Need a new coverage solution, see https://tahoe-lafs.org/trac/tahoe-lafs/ticket/4011"
fi
docker:
- <<: *DOCKERHUB_AUTH
image: "tahoelafsci/debian:11-py3.9"
user: "nobody"
# Restore later using PyPy3.8
# pypy27-buster:
# <<: *DEBIAN
# docker:
# - <<: *DOCKERHUB_AUTH
# image: "tahoelafsci/pypy:buster-py2"
# user: "nobody"
# environment:
# <<: *UTF_8_ENVIRONMENT
# # We don't do coverage since it makes PyPy far too slow:
# TAHOE_LAFS_TOX_ENVIRONMENT: "pypy27"
# # Since we didn't collect it, don't upload it.
# UPLOAD_COVERAGE: ""
c-locale:
<<: *DEBIAN
environment:
<<: *UTF_8_ENVIRONMENT
LANG: "C"
another-locale:
<<: *DEBIAN
environment:
<<: *UTF_8_ENVIRONMENT
# aka "Latin 1"
LANG: "en_US.ISO-8859-1"
integration:
<<: *DEBIAN
parameters:
tox-args:
description: >-
Additional arguments to pass to the tox command.
type: "string"
default: ""
docker:
- <<: *DOCKERHUB_AUTH
image: "tahoelafsci/debian:11-py3.9"
user: "nobody"
environment:
<<: *UTF_8_ENVIRONMENT
# Select the integration tests tox environments.
TAHOE_LAFS_TOX_ENVIRONMENT: "integration"
# Disable artifact collection because py.test can't produce any.
ARTIFACTS_OUTPUT_PATH: ""
# Pass on anything we got in our parameters.
TAHOE_LAFS_TOX_ARGS: "<< parameters.tox-args >>"
steps:
- "checkout"
# DRY, YAML-style. See the debian-9 steps.
- run: *SETUP_VIRTUALENV
- run: *RUN_TESTS
ubuntu-20-04:
<<: *DEBIAN
docker:
- <<: *DOCKERHUB_AUTH
image: "tahoelafsci/ubuntu:20.04-py3.9"
user: "nobody"
environment:
<<: *UTF_8_ENVIRONMENT
TAHOE_LAFS_TOX_ENVIRONMENT: "py39"
ubuntu-22-04:
<<: *DEBIAN
docker:
- <<: *DOCKERHUB_AUTH
image: "tahoelafsci/ubuntu:22.04-py3.10"
user: "nobody"
environment:
<<: *UTF_8_ENVIRONMENT
TAHOE_LAFS_TOX_ENVIRONMENT: "py310"
oraclelinux-8: &RHEL_DERIV
docker:
- <<: *DOCKERHUB_AUTH
image: "tahoelafsci/oraclelinux:8-py3.8"
user: "nobody"
environment:
<<: *UTF_8_ENVIRONMENT
TAHOE_LAFS_TOX_ENVIRONMENT: "py38"
# pip cannot install packages if the working directory is not readable.
# We want to run a lot of steps as nobody instead of as root.
working_directory: "/tmp/project"
steps:
- "checkout"
- run: *SETUP_VIRTUALENV
- run: *RUN_TESTS
- store_test_results: *STORE_TEST_RESULTS
- store_artifacts: *STORE_TEST_LOG
- store_artifacts: *STORE_ELIOT_LOG
- store_artifacts: *STORE_OTHER_ARTIFACTS
- run: *SUBMIT_COVERAGE
fedora-35:
<<: *RHEL_DERIV
docker:
- <<: *DOCKERHUB_AUTH
image: "tahoelafsci/fedora:35-py3"
user: "nobody"
nixos:
parameters:
nixpkgs:
description: >-
Reference the name of a flake-managed nixpkgs input (see `nix flake
metadata` and flake.nix)
type: "string"
pythonVersion:
description: >-
Reference the name of a Python package in nixpkgs to use.
type: "string"
executor: "nix"
steps:
- "nix-build":
nixpkgs: "<<parameters.nixpkgs>>"
pythonVersion: "<<parameters.pythonVersion>>"
buildSteps:
- "run":
name: "Unit Test"
command: |
source .circleci/lib.sh
# Translate the nixpkgs selection into a flake reference we
# can use to override the default nixpkgs input.
NIXPKGS=$(nixpkgs_flake_reference <<parameters.nixpkgs>>)
cache_if_able nix run \
--override-input nixpkgs "$NIXPKGS" \
.#<<parameters.pythonVersion>>-unittest -- \
--jobs $UNITTEST_CORES \
allmydata
typechecks:
docker:
- <<: *DOCKERHUB_AUTH
image: "tahoelafsci/ubuntu:20.04-py3.9"
steps:
- "checkout"
- run:
name: "Validate Types"
command: |
/tmp/venv/bin/tox -e typechecks
docs:
docker:
- <<: *DOCKERHUB_AUTH
image: "tahoelafsci/ubuntu:20.04-py3.9"
steps:
- "checkout"
- run:
name: "Build documentation"
command: |
/tmp/venv/bin/tox -e docs
build-image: &BUILD_IMAGE
# This is a template for a job to build a Docker image that has as much of
# the setup as we can manage already done and baked in. This cuts down on
# the per-job setup time the actual testing jobs have to perform - by
# perhaps 10% - 20%.
#
# https://circleci.com/blog/how-to-build-a-docker-image-on-circleci-2-0/
docker:
- <<: *DOCKERHUB_AUTH
# CircleCI build images; https://github.com/CircleCI-Public/cimg-base
# for details.
image: "cimg/base:2022.01"
environment:
DISTRO: "tahoelafsci/<DISTRO>:foo-py3.9"
TAG: "tahoelafsci/distro:<TAG>-py3.9"
PYTHON_VERSION: "tahoelafsci/distro:tag-py<PYTHON_VERSION}"
steps:
- "checkout"
- setup_remote_docker:
version: "20.10.11"
- run:
name: "Log in to Dockerhub"
command: |
docker login -u ${DOCKERHUB_USERNAME} -p ${DOCKERHUB_PASSWORD}
- run:
name: "Build image"
command: |
docker \
build \
--build-arg TAG=${TAG} \
--build-arg PYTHON_VERSION=${PYTHON_VERSION} \
-t tahoelafsci/${DISTRO}:${TAG}-py${PYTHON_VERSION} \
-f ~/project/.circleci/Dockerfile.${DISTRO} \
~/project/
- run:
name: "Push image"
command: |
docker push tahoelafsci/${DISTRO}:${TAG}-py${PYTHON_VERSION}
build-image-debian-11:
<<: *BUILD_IMAGE
environment:
DISTRO: "debian"
TAG: "11"
PYTHON_VERSION: "3.9"
build-image-ubuntu-20-04:
<<: *BUILD_IMAGE
environment:
DISTRO: "ubuntu"
TAG: "20.04"
PYTHON_VERSION: "3.9"
build-image-ubuntu-22-04:
<<: *BUILD_IMAGE
environment:
DISTRO: "ubuntu"
TAG: "22.04"
PYTHON_VERSION: "3.10"
build-image-oraclelinux-8:
<<: *BUILD_IMAGE
environment:
DISTRO: "oraclelinux"
TAG: "8"
PYTHON_VERSION: "3.8"
build-image-fedora-35:
<<: *BUILD_IMAGE
environment:
DISTRO: "fedora"
TAG: "35"
PYTHON_VERSION: "3"
# build-image-pypy27-buster:
# <<: *BUILD_IMAGE
# environment:
# DISTRO: "pypy"
# TAG: "buster"
# # We only have Python 2 for PyPy right now so there's no support for
# # setting up PyPy 3 in the image building toolchain. This value is just
# # for constructing the right Docker image tag.
# PYTHON_VERSION: "2"
executors:
windows:
# Choose a Windows environment that closest matches our testing
# requirements and goals.
# https://circleci.com/developer/orbs/orb/circleci/windows#executors-server-2022
machine:
image: "windows-server-2022-gui:2023.06.1"
shell: "powershell.exe -ExecutionPolicy Bypass"
resource_class: "windows.large"
nix:
docker:
# Run in a highly Nix-capable environment.
- <<: *DOCKERHUB_AUTH
image: "nixos/nix:2.16.1"
environment:
# CACHIX_AUTH_TOKEN is manually set in the CircleCI web UI and allows us
# to push to CACHIX_NAME. CACHIX_NAME tells cachix which cache to push
# to.
CACHIX_NAME: "tahoe-lafs-opensource"
# Let us use features marked "experimental". For example, most/all of
# the `nix <subcommand>` forms.
NIX_CONFIG: "experimental-features = nix-command flakes"
commands:
nix-build:
parameters:
nixpkgs:
description: >-
Reference the name of a flake-managed nixpkgs input (see `nix flake
metadata` and flake.nix)
type: "string"
pythonVersion:
description: >-
Reference the name of a Python package in nixpkgs to use.
type: "string"
buildSteps:
description: >-
The build steps to execute after setting up the build environment.
type: "steps"
steps:
- "run":
# Get cachix for Nix-friendly caching.
name: "Install Basic Dependencies"
command: |
# Get some build environment dependencies and let them float on a
# certain release branch. These aren't involved in the actual
# package build (only in CI environment setup) so the fact that
# they float shouldn't hurt reproducibility.
NIXPKGS="nixpkgs/nixos-23.05"
nix profile install $NIXPKGS#cachix $NIXPKGS#bash $NIXPKGS#jp
# Activate our cachix cache for "binary substitution". This sets
# up configuration tht lets Nix download something from the cache
# instead of building it locally, if possible.
cachix use "${CACHIX_NAME}"
- "checkout"
- "run":
# The Nix package doesn't know how to do this part, unfortunately.
name: "Generate version"
command: |
nix-shell \
-p 'python3.withPackages (ps: [ ps.setuptools ])' \
--run 'python setup.py update_version'
- "run":
name: "Build Package"
command: |
source .circleci/lib.sh
NIXPKGS=$(nixpkgs_flake_reference <<parameters.nixpkgs>>)
cache_if_able nix build \
--verbose \
--print-build-logs \
--cores "$DEPENDENCY_CORES" \
--override-input nixpkgs "$NIXPKGS" \
.#<<parameters.pythonVersion>>-tahoe-lafs
- steps: "<<parameters.buildSteps>>"

View File

@ -1,53 +0,0 @@
#!/bin/bash
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -euxo pipefail
# The filesystem location of the wheelhouse which we'll populate with wheels
# for all of our dependencies.
WHEELHOUSE_PATH="$1"
shift
# The filesystem location of the root of a virtualenv we can use to get/build
# wheels.
BOOTSTRAP_VENV="$1"
shift
# The basename of the Python executable (found on PATH) that will be used with
# this image. This lets us create a virtualenv that uses the correct Python.
PYTHON="$1"
shift
# Set up the virtualenv as a non-root user so we can run the test suite as a
# non-root user. See below.
virtualenv --python "${PYTHON}" "${BOOTSTRAP_VENV}"
# For convenience.
PIP="${BOOTSTRAP_VENV}/bin/pip"
# Tell pip where it can find any existing wheels.
export PIP_FIND_LINKS="file://${WHEELHOUSE_PATH}"
# Get "certifi" to avoid bug #2913. Basically if a `setup_requires=...` causes
# a package to be installed (with setuptools) then it'll fail on certain
# platforms (travis's OX-X 10.12, Slackware 14.2) because PyPI's TLS
# requirements (TLS >= 1.2) are incompatible with the old TLS clients
# available to those systems. Installing it ahead of time (with pip) avoids
# this problem. Make sure this step comes before any other attempts to
# install things using pip!
"${PIP}" install certifi
# Get a new, awesome version of pip and setuptools. For example, the
# distro-packaged virtualenv's pip may not know about wheels. Get the newer
# version of pip *first* in case we have a really old one now which can't even
# install setuptools properly.
"${PIP}" install --upgrade pip
# setuptools 45 requires Python 3.5 or newer. Even though we upgraded pip
# above, it may still not be able to get us a compatible version unless we
# explicitly ask for one.
"${PIP}" install --upgrade setuptools wheel
# Just about every user of this image wants to use tox from the bootstrap
# virtualenv so go ahead and install it now.
"${PIP}" install "tox~=4.0"

View File

@ -1,34 +0,0 @@
#!/bin/bash
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -euxo pipefail
# The filesystem location of the wheelhouse which we'll populate with wheels
# for all of our dependencies.
WHEELHOUSE_PATH="$1"
shift
# The filesystem location of the root of a virtualenv we can use to get/build
# wheels.
BOOTSTRAP_VENV="$1"
shift
# The filesystem location of the root of the project source. We need this to
# know what wheels to get/build, of course.
PROJECT_ROOT="$1"
shift
# Most stuff is going to run as nobody. Here's a helper to make sure nobody
# can access necessary files.
CHOWN_NOBODY="chown --recursive nobody:$(id --group nobody)"
# Avoid the /nonexistent home directory in nobody's /etc/passwd entry.
usermod --home /tmp/nobody nobody
# Grant read access to nobody, the user which will eventually try to test this
# checkout.
${CHOWN_NOBODY} "${PROJECT_ROOT}"
# Create a place for some wheels to live.
mkdir -p "${WHEELHOUSE_PATH}"
${CHOWN_NOBODY} "${WHEELHOUSE_PATH}"

View File

@ -1,148 +0,0 @@
# CircleCI build environment looks like it has a zillion and a half cores.
# Don't let Nix autodetect this high core count because it blows up memory
# usage and fails the test run. Pick a number of cores that suits the build
# environment we're paying for (the free one!).
DEPENDENCY_CORES=3
# Once dependencies are built, we can allow some more concurrency for our own
# test suite.
UNITTEST_CORES=8
# Run a command, enabling cache writes to cachix if possible. The command is
# accepted as a variable number of positional arguments (like argv).
function cache_if_able() {
# Dump some info about our build environment.
describe_build
if is_cache_writeable; then
# If the cache is available we'll use it. This lets fork owners set
# up their own caching if they want.
echo "Cachix credentials present; will attempt to write to cache."
# The `cachix watch-exec ...` does our cache population. When it sees
# something added to the store (I guess) it pushes it to the named
# cache.
cachix watch-exec "${CACHIX_NAME}" -- "$@"
else
if is_cache_required; then
echo "Required credentials (CACHIX_AUTH_TOKEN) are missing."
return 1
else
echo "Cachix credentials missing; will not attempt cache writes."
"$@"
fi
fi
}
function is_cache_writeable() {
# We can only *push* to the cache if we have a CACHIX_AUTH_TOKEN. in-repo
# jobs will get this from CircleCI configuration but jobs from forks may
# not.
[ -v CACHIX_AUTH_TOKEN ]
}
function is_cache_required() {
# If we're building in tahoe-lafs/tahoe-lafs then we must use the cache.
# If we're building anything from a fork then we're allowed to not have
# the credentials.
is_upstream
}
# Return success if the origin of this build is the tahoe-lafs/tahoe-lafs
# repository itself (and so we expect to have cache credentials available),
# failure otherwise.
#
# See circleci.txt for notes about how this determination is made.
function is_upstream() {
# CIRCLE_PROJECT_USERNAME is set to the org the build is happening for.
# If a PR targets a fork of the repo then this is set to something other
# than "tahoe-lafs".
[ "$CIRCLE_PROJECT_USERNAME" == "tahoe-lafs" ] &&
# CIRCLE_BRANCH is set to the real branch name for in-repo PRs and
# "pull/NNNN" for pull requests from forks.
#
# CIRCLE_PULL_REQUESTS is set to a comma-separated list of the full
# URLs of the PR pages which share an underlying branch, with one of
# them ended with that same "pull/NNNN" for PRs from forks.
! any_element_endswith "/$CIRCLE_BRANCH" "," "$CIRCLE_PULL_REQUESTS"
}
# Return success if splitting $3 on $2 results in an array with any element
# that ends with $1, failure otherwise.
function any_element_endswith() {
suffix=$1
shift
sep=$1
shift
haystack=$1
shift
IFS="${sep}" read -r -a elements <<< "$haystack"
for elem in "${elements[@]}"; do
if endswith "$suffix" "$elem"; then
return 0
fi
done
return 1
}
# Return success if $2 ends with $1, failure otherwise.
function endswith() {
suffix=$1
shift
haystack=$1
shift
case "$haystack" in
*${suffix})
return 0
;;
*)
return 1
;;
esac
}
function describe_build() {
echo "Building PR for user/org: ${CIRCLE_PROJECT_USERNAME}"
echo "Building branch: ${CIRCLE_BRANCH}"
if is_upstream; then
echo "Upstream build."
else
echo "Non-upstream build."
fi
if is_cache_required; then
echo "Cache is required."
else
echo "Cache not required."
fi
if is_cache_writeable; then
echo "Cache is writeable."
else
echo "Cache not writeable."
fi
}
# Inspect the flake input metadata for an input of a given name and return the
# revision at which that input is pinned. If the input does not exist then
# return garbage (probably "null").
read_input_revision() {
input_name=$1
shift
nix flake metadata --json | jp --unquoted 'locks.nodes."'"$input_name"'".locked.rev'
}
# Return a flake reference that refers to a certain revision of nixpkgs. The
# certain revision is the revision to which the specified input is pinned.
nixpkgs_flake_reference() {
input_name=$1
shift
echo "github:NixOS/nixpkgs?rev=$(read_input_revision $input_name)"
}

View File

@ -1,33 +0,0 @@
#!/bin/bash
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -euxo pipefail
# The filesystem location of the wheelhouse which we'll populate with wheels
# for all of our dependencies.
WHEELHOUSE_PATH="$1"
shift
# The filesystem location of the root of a virtualenv we can use to get/build
# wheels.
BOOTSTRAP_VENV="$1"
shift
# The filesystem location of the root of the project source. We need this to
# know what wheels to get/build, of course.
PROJECT_ROOT="$1"
shift
# For convenience.
PIP="${BOOTSTRAP_VENV}/bin/pip"
# Tell pip where it can find any existing wheels.
export PIP_FIND_LINKS="file://${WHEELHOUSE_PATH}"
# Populate the wheelhouse, if necessary. zfec 1.5.3 can only be built with a
# UTF-8 environment so make sure we have one, at least for this invocation.
LANG="en_US.UTF-8" "${PIP}" \
wheel \
--wheel-dir "${WHEELHOUSE_PATH}" \
"${PROJECT_ROOT}"[testenv] \
"${PROJECT_ROOT}"[test]

View File

@ -1,28 +0,0 @@
#!/bin/bash
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -euxo pipefail
# The filesystem location of the wheelhouse which we'll populate with wheels
# for all of our dependencies.
WHEELHOUSE_PATH="$1"
shift
# The filesystem location of the root of a virtualenv we can use to get/build
# wheels.
BOOTSTRAP_VENV="$1"
shift
# The filesystem location of the root of the project source. We need this to
# know what wheels to get/build, of course.
PROJECT_ROOT="$1"
shift
# The basename of the Python executable (found on PATH) that will be used with
# this image. This lets us create a virtualenv that uses the correct Python.
PYTHON="$1"
shift
"${PROJECT_ROOT}"/.circleci/fix-permissions.sh "${WHEELHOUSE_PATH}" "${BOOTSTRAP_VENV}" "${PROJECT_ROOT}"
sudo --set-home -u nobody "${PROJECT_ROOT}"/.circleci/create-virtualenv.sh "${WHEELHOUSE_PATH}" "${BOOTSTRAP_VENV}" "${PYTHON}"
sudo --set-home -u nobody "${PROJECT_ROOT}"/.circleci/populate-wheelhouse.sh "${WHEELHOUSE_PATH}" "${BOOTSTRAP_VENV}" "${PROJECT_ROOT}"

View File

@ -1,20 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# Get your API token here:
# https://app.circleci.com/settings/user/tokens
API_TOKEN=$1
shift
# Name the branch you want to trigger the build for
BRANCH=$1
shift
curl \
--verbose \
--request POST \
--url https://circleci.com/api/v2/project/gh/tahoe-lafs/tahoe-lafs/pipeline \
--header "Circle-Token: $API_TOKEN" \
--header "content-type: application/json" \
--data '{"branch":"'"$BRANCH"'","parameters":{"build-images":true,"run-tests":false}}'

View File

@ -1,10 +0,0 @@
#!/usr/bin/env bash
CIRCLE_TOKEN=efb53124be82dd4b3153bc0e3f60de71da629d59
curl --user ${CIRCLE_TOKEN}: \
--request POST \
--form revision=$(git rev-parse HEAD) \
--form config=@config.yml \
--form notify=false \
https://circleci.com/api/v1.1/project/github/exarkun/tahoe-lafs/tree/2929.circleci

View File

@ -1,99 +0,0 @@
#!/bin/bash
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -euxo pipefail
# The filesystem location of the root of a virtualenv we can use to get/build
# wheels.
BOOTSTRAP_VENV="$1"
shift
# The filesystem location of the root of the project source. We need this to
# know what wheels to get/build, of course.
PROJECT_ROOT="$1"
shift
ALLOWED_FAILURE="$1"
shift
ARTIFACTS=$1
shift
TAHOE_LAFS_TOX_ENVIRONMENT=$1
shift
TAHOE_LAFS_TOX_ARGS=$1
shift || :
if [ -n "${ARTIFACTS}" ]; then
# If given an artifacts path, prepare to have some artifacts created
# there. The integration tests don't produce any artifacts; that is the
# case where we expect not to end up here.
# Make sure we can actually write things to this directory.
mkdir -p "${ARTIFACTS}"
SUBUNIT2="${ARTIFACTS}"/results.subunit2
# Use an intermediate directory here because CircleCI extracts some label
# information from its name.
JUNITXML="${ARTIFACTS}"/junit/unittests/results.xml
else
SUBUNIT2=""
JUNITXML=""
fi
# A prefix for the test command that ensure it will exit after no more than a
# certain amount of time. Ideally, we would only enforce a "silent" period
# timeout but there isn't obviously a ready-made tool for that. The unit test
# suite only takes about 5 - 6 minutes on CircleCI right now. The integration
# tests are a bit longer than that. 45 minutes seems like a moderately safe
# window.
#
# This is primarily aimed at catching hangs on the PyPy job which runs for
# about 21 minutes and then gets killed by CircleCI in a way that fails the
# job and bypasses our "allowed failure" logic.
TIMEOUT="timeout --kill-after 1m 45m"
# Run the test suite as a non-root user. This is the expected usage some
# small areas of the test suite assume non-root privileges (such as unreadable
# files being unreadable).
#
# Also run with /tmp as a workdir because the non-root user won't be able to
# create the tox working filesystem state in the source checkout because it is
# owned by root.
#
# Send the output directly to a file because transporting the binary subunit2
# via tox and then scraping it out is hideous and failure prone.
export SUBUNITREPORTER_OUTPUT_PATH="${SUBUNIT2}"
export TAHOE_LAFS_TRIAL_ARGS="${TAHOE_LAFS_TRIAL_ARGS:---reporter=subunitv2-file --rterrors}"
export PIP_NO_INDEX="1"
# Make output unbuffered, so progress reports from subunitv2-file get streamed
# and notify CircleCI we're still alive.
export PYTHONUNBUFFERED=1
if [ "${ALLOWED_FAILURE}" = "yes" ]; then
alternative="true"
else
alternative="false"
fi
WORKDIR=/tmp/tahoe-lafs.tox
${TIMEOUT} ${BOOTSTRAP_VENV}/bin/tox \
-c ${PROJECT_ROOT}/tox.ini \
--workdir "${WORKDIR}" \
-e "${TAHOE_LAFS_TOX_ENVIRONMENT}" \
${TAHOE_LAFS_TOX_ARGS} || "${alternative}"
if [ -n "${ARTIFACTS}" ]; then
if [ ! -e "${SUBUNIT2}" ]; then
echo "subunitv2 output file does not exist: ${SUBUNIT2}"
exit 1
fi
# Create a junitxml results area.
mkdir -p "$(dirname "${JUNITXML}")"
"${WORKDIR}/${TAHOE_LAFS_TOX_ENVIRONMENT}/bin/subunit2junitxml" < "${SUBUNIT2}" > "${JUNITXML}" || "${alternative}"
fi

View File

@ -1,37 +0,0 @@
#!/bin/bash
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -euxo pipefail
# The filesystem location of the root of a virtualenv we can use to get/build
# wheels.
BOOTSTRAP_VENV="$1"
shift
# The filesystem location of the root of the project source. We need this to
# know what wheels to get/build, of course.
PROJECT_ROOT="$1"
shift
# The filesystem location of the wheelhouse which we'll populate with wheels
# for all of our dependencies.
WHEELHOUSE_PATH="$1"
shift
TAHOE_LAFS_TOX_ENVIRONMENT=$1
shift
TAHOE_LAFS_TOX_ARGS=$1
shift || :
# Tell pip where it can find any existing wheels.
export PIP_FIND_LINKS="file://${WHEELHOUSE_PATH}"
export PIP_NO_INDEX="1"
# Get everything else installed in it, too.
"${BOOTSTRAP_VENV}"/bin/tox \
-c "${PROJECT_ROOT}"/tox.ini \
--workdir /tmp/tahoe-lafs.tox \
--notest \
-e "${TAHOE_LAFS_TOX_ENVIRONMENT}" \
${TAHOE_LAFS_TOX_ARGS}

View File

@ -1,27 +0,0 @@
# -*- mode: conf -*-
[run]
# only record trace data for allmydata.*
source =
allmydata
# and don't trace the test files themselves, or generated files
omit =
*/allmydata/test/*
*/allmydata/_version.py
parallel = True
branch = True
[report]
show_missing = True
skip_covered = True
[paths]
source =
# It looks like this in the checkout
src/
# It looks like this in the GitHub Actions Windows build environment
D:/a/tahoe-lafs/tahoe-lafs/.tox/py*-coverage/Lib/site-packages/
# Although sometimes it looks like this instead. Also it looks like this on macOS.
.tox/py*-coverage/lib/python*/site-packages/
# On some Linux CI jobs it looks like this
/tmp/tahoe-lafs.tox/py*-coverage/lib/python*/site-packages/

View File

@ -1,26 +0,0 @@
.. -*- coding: utf-8 -*-
.. This document is rendered on the GitHub PR creation page to guide
contributors. It is also rendered into the overall documentation.
Contributing to Tahoe-LAFS
==========================
As an open source project,
Tahoe-LAFS welcomes contributions of many forms.
Examples of contributions include:
* `Code patches <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/Patches>`_
* `Documentation improvements <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/Doc>`_
* `Bug reports <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/HowToReportABug>`_
* `Patch reviews <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/PatchReviewProcess>`_
Before authoring or reviewing a patch,
please familiarize yourself with the `Coding Standards <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/CodingStandards>`_ and the `Contributor Code of Conduct <../docs/CODE_OF_CONDUCT.md>`_.
🥳 First Contribution?
======================
If you are committing to Tahoe for the very first time, consider adding your name to our contributor list in `CREDITS <../CREDITS>`__

View File

@ -1,285 +0,0 @@
name: CI
on:
push:
branches:
- "master"
pull_request:
# At the start of each workflow run, GitHub creates a unique
# GITHUB_TOKEN secret to use in the workflow. It is a good idea for
# this GITHUB_TOKEN to have the minimum of permissions. See:
#
# - https://docs.github.com/en/actions/security-guides/automatic-token-authentication
# - https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
#
permissions:
contents: read
# Control to what degree jobs in this workflow will run concurrently with
# other instances of themselves.
#
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#concurrency
concurrency:
# We want every revision on master to run the workflow completely.
# "head_ref" is not set for the "push" event but it is set for the
# "pull_request" event. If it is set then it is the name of the branch and
# we can use it to make sure each branch has only one active workflow at a
# time. If it is not set then we can compute a unique string that gives
# every master/push workflow its own group.
group: "${{ github.head_ref || format('{0}-{1}', github.run_number, github.run_attempt) }}"
# Then, we say that if a new workflow wants to start in the same group as a
# running workflow, the running workflow should be cancelled.
cancel-in-progress: true
env:
# Tell Hypothesis which configuration we want it to use.
TAHOE_LAFS_HYPOTHESIS_PROFILE: "ci"
jobs:
coverage:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: macos-12
python-version: "3.12"
# We only support PyPy on Linux at the moment.
- os: ubuntu-latest
python-version: "pypy-3.8"
- os: ubuntu-latest
python-version: "pypy-3.9"
- os: ubuntu-latest
python-version: "3.12"
- os: windows-latest
python-version: "3.12"
steps:
# See https://github.com/actions/checkout. A fetch-depth of 0
# fetches all tags and branches.
- name: Check out Tahoe-LAFS sources
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: 'pip' # caching pip dependencies
- name: Install Python packages
run: |
pip install --upgrade tox tox-gh-actions setuptools
pip list
- name: Display tool versions
run: python misc/build_helpers/show-tool-versions.py
- name: Run tox for corresponding Python version
if: ${{ !contains(matrix.os, 'windows') }}
run: python -m tox
# On Windows, a non-blocking pipe might respond (when emulating Unix-y
# API) with ENOSPC to indicate buffer full. Trial doesn't handle this
# well, so it breaks test runs. To attempt to solve this, we pipe the
# output through passthrough.py that will hopefully be able to do the right
# thing by using Windows APIs.
- name: Run tox for corresponding Python version
if: ${{ contains(matrix.os, 'windows') }}
run: |
pip install twisted pywin32
python -m tox | python misc/windows-enospc/passthrough.py
- name: Upload eliot.log
uses: actions/upload-artifact@v3
with:
name: eliot.log
path: eliot.log
- name: Upload trial log
uses: actions/upload-artifact@v3
with:
name: test.log
path: _trial_temp/test.log
# Upload this job's coverage data to Coveralls. While there is a GitHub
# Action for this, as of Jan 2021 it does not support Python coverage
# files - only lcov files. Therefore, we use coveralls-python, the
# coveralls.io-supplied Python reporter, for this.
- name: "Report Coverage to Coveralls"
run: |
pip3 install --upgrade coveralls==3.0.1
python3 -m coveralls
env:
# Some magic value required for some magic reason.
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
# Help coveralls identify our project.
COVERALLS_REPO_TOKEN: "JPf16rLB7T2yjgATIxFzTsEgMdN1UNq6o"
# Every source of coverage reports needs a unique "flag name".
# Construct one by smashing a few variables from the matrix together
# here.
COVERALLS_FLAG_NAME: "run-${{ matrix.os }}-${{ matrix.python-version }}"
# Mark the data as just one piece of many because we have more than
# one instance of this job (Windows, macOS) which collects and
# reports coverage. This is necessary to cause Coveralls to merge
# multiple coverage results into a single report. Note the merge
# only happens when we "finish" a particular build, as identified by
# its "build_num" (aka "service_number").
COVERALLS_PARALLEL: true
# Tell Coveralls that we're done reporting coverage data. Since we're using
# the "parallel" mode where more than one coverage data file is merged into
# a single report, we have to tell Coveralls when we've uploaded all of the
# data files. This does it. We make sure it runs last by making it depend
# on *all* of the coverage-collecting jobs.
#
# See notes about parallel builds on GitHub Actions at
# https://coveralls-python.readthedocs.io/en/latest/usage/configuration.html
finish-coverage-report:
needs:
- "coverage"
runs-on: "ubuntu-latest"
container: "python:3-slim"
steps:
- name: "Indicate completion to coveralls.io"
run: |
pip3 install --upgrade coveralls==3.0.1
python3 -m coveralls --finish
env:
# Some magic value required for some magic reason.
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
integration:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
# 22.04 has some issue with Tor at the moment:
# https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3943
- ubuntu-20.04
- macos-12
- windows-latest
python-version:
- "3.11"
force-foolscap:
- false
include:
- os: ubuntu-20.04
python-version: "3.12"
force-foolscap: true
steps:
- name: Install Tor [Ubuntu]
if: ${{ contains(matrix.os, 'ubuntu') }}
run: sudo apt install tor
# TODO: See https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3744.
# We have to use an older version of Tor for running integration
# tests on macOS.
- name: Install Tor [macOS, ${{ matrix.python-version }} ]
if: ${{ contains(matrix.os, 'macos') }}
run: |
brew install tor
- name: Install Tor [Windows]
if: matrix.os == 'windows-latest'
uses: crazy-max/ghaction-chocolatey@v2
with:
args: install tor
- name: Check out Tahoe-LAFS sources
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: 'pip' # caching pip dependencies
- name: Install Python packages
run: |
pip install --upgrade tox
pip list
- name: Display tool versions
run: python misc/build_helpers/show-tool-versions.py
- name: Run "Python 3 integration tests"
if: "${{ !matrix.force-foolscap }}"
env:
# On macOS this is necessary to ensure unix socket paths for tor
# aren't too long. On Windows tox won't pass it through so it has no
# effect. On Linux it doesn't make a difference one way or another.
TMPDIR: "/tmp"
run: |
tox -e integration
- name: Run "Python 3 integration tests (force Foolscap)"
if: "${{ matrix.force-foolscap }}"
env:
# On macOS this is necessary to ensure unix socket paths for tor
# aren't too long. On Windows tox won't pass it through so it has no
# effect. On Linux it doesn't make a difference one way or another.
TMPDIR: "/tmp"
run: |
tox -e integration -- --force-foolscap integration/
- name: Upload eliot.log in case of failure
uses: actions/upload-artifact@v3
if: failure()
with:
name: integration.eliot.json
path: integration.eliot.json
packaging:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- macos-12
- windows-latest
- ubuntu-latest
python-version:
- 3.9
steps:
- name: Check out Tahoe-LAFS sources
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: 'pip' # caching pip dependencies
- name: Install Python packages
run: |
pip install --upgrade tox
pip list
- name: Display tool versions
run: python misc/build_helpers/show-tool-versions.py
- name: Run "tox -e pyinstaller"
run: tox -e pyinstaller
# This step is to ensure there are no packaging/import errors.
- name: Test PyInstaller executable
run: dist/Tahoe-LAFS/tahoe --version
- name: Upload PyInstaller package
uses: actions/upload-artifact@v3
with:
name: Tahoe-LAFS-${{ matrix.os }}-Python-${{ matrix.python-version }}
path: dist/Tahoe-LAFS-*-*.*

29
.gitignore vendored
View File

@ -1,21 +1,15 @@
venv*
# vim swap files
*.swp
*.swo
*.pyc
*.pyo
*~
*.DS_Store
.*.kate-swp
*.bak
/build/
/support/
# these are generated at build time, and never checked in
/src/allmydata/_version.py
/src/allmydata/_appname.py
# these are generated too
/bin/tahoe
@ -23,35 +17,20 @@ venv*
/bin/tahoe-script.py
/.built
/src/tahoe_lafs.egg-info/
/src/allmydata_tahoe.egg-info/
Twisted-*.egg
zope.interface-*.egg
.pc
/src/allmydata/test/plugins/dropin.cache
**/_trial_temp*
/_trial_temp*
/tmp*
/*.patch
/dist/
/twisted/plugins/dropin.cache
/tahoe-deps/
/tahoe-deps.tar.gz
/.coverage
/.coverage.*
/.coverage.el
/coverage-html/
/miscaptures.txt
/violations.txt
/.tox/
/docs/_build/
/coverage.xml
/.pre-commit-config.local.yaml
/.hypothesis/
/eliot.log
/misc/python3/results.xml
/misc/python3/results.subunit2
# This is the plaintext of the private environment needed for some CircleCI
# operations. It's never supposed to be checked in.
secret-env-plain
.ruff_cache

View File

@ -1,10 +0,0 @@
repos:
- repo: "local"
hooks:
- id: "codechecks"
name: "codechecks"
stages: ["push"]
language: "system"
files: ".py$"
entry: "tox -e codechecks"
pass_filenames: true

View File

@ -1,10 +0,0 @@
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.10"
python:
install:
- requirements: docs/requirements.txt

View File

@ -1,18 +0,0 @@
select = [
# Pyflakes checks
"F",
# Prohibit tabs:
"W191",
# No trailing whitespace:
"W291",
"W293",
# Make sure we bind closure variables in a loop (equivalent to pylint
# cell-var-from-loop):
"B023",
# Don't silence exceptions in finally by accident:
"B012",
# Don't use mutable default arguments:
"B006",
# Errors from PyLint:
"PLE",
]

25
.travis.yml Normal file
View File

@ -0,0 +1,25 @@
language: python
python:
- "2.7"
- "2.6"
before_install:
- sh -c set
- git config --global user.email "travis-tahoe@tahoe-lafs.org"
- git config --global user.name "Travis Tahoe"
- git pull --depth=1000
- python misc/build_helpers/show-tool-versions.py
install:
- pip install 'coveralls==0.4.2'
before_script: python setup.py build
script: bin/tahoe @coverage run --branch --source=src/allmydata @tahoe --version-and-path debug trial --rterrors --reporter=timing
after_success:
coveralls
notifications:
email: false
irc:
channels: "chat.freenode.net#tahoe-lafs"
on_success: always # for testing
on_failure: always
template:
- "%{repository}#%{build_number} [%{branch}: %{commit} by %{author}] %{message}"
- "Changes: %{compare_url} | Details: %{build_url}"

View File

@ -1,42 +0,0 @@
Contributor Checklist
=====================
* Create a ``Trac`` ticket, fill it out and assign it to yourself (contact exarkun if you don't have an account):
``https://tahoe-lafs.org/trac/tahoe-lafs/newticket``
* Use the ticket number to name your branch (example):
``3003.contributor-guide``
* Good idea to add tests at the same time you write your code.
* Add a file to the ``/newsfragments`` folder, named with the ticket number and the type of patch (example):
``newsfragments/3651.minor``
* ``towncrier`` recognizes the following types:
``incompat``, ``feature``, ``bugfix``, ``installation``, ``configuration``, ``documentation``, ``removed``, ``other``, ``minor``
* Add one sentence to ``newsfragments/<ticket-number>.<towncrier-type>`` describing the change (example):
``The integration test suite has been updated to use pytest-twisted instead of deprecated pytest APIs.``
* Run the test suite with ``tox``, ``tox -e codechecks`` and ``tox -e typechecks``
* Push your branch to Github with your ticket number in the merge commit message (example):
``Fixes ticket:3003``
This makes the ``Trac`` ticket close when your PR gets approved.
* Request appropriate review - we suggest asking `Tahoe Committers <https://github.com/orgs/tahoe-lafs/teams/tahoe-committers>`__
References
----------
This checklist is a summary of `this page on contributing Patches <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/Patches>`__
Before authoring or reviewing a patch, please familiarize yourself with the `Coding Standard <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/CodingStandards>`__
and the `Contributor Code of Conduct <docs/CODE_OF_CONDUCT.md>`__.

74
CREDITS
View File

@ -113,8 +113,6 @@ E: jacob@appelbaum.com
W: http://www.appelbaum.net/
P: 12E4 04FF D3C9 31F9 3405 2D06 B884 1A91 9D0F ACE4
D: Debian packaging including init scripts
D: Note that contributions from Jacob Appelbaum (ioerror) are no longer welcome
D: due to behavior unacceptable to community standards in Tor and other projects
N: Jeremy Visser
D: Ubuntu packaging, usability testing
@ -185,7 +183,7 @@ D: documentation
N: Ramakrishnan Muthukrishnan
E: ram@rkrishnan.org
D: Mac OS X packaging, Debian package maintainer
D: Mac OS X packaging
N: Loose Cannon
E: lcstyle@gmail.com
@ -194,73 +192,3 @@ D: fix the Download! button on the Welcome page
N: Jean-Paul Calderone
E: exarkun@twistedmatrix.com
D: support SFTP public key authentication.
N: David Stainton
E: dstainton415@gmail.com
D: various bug-fixes and features
N: meejah
E: meejah@meejah.ca
P: 0xC2602803128069A7, 9D5A 2BD5 688E CB88 9DEB CD3F C260 2803 1280 69A7
D: various bug-fixes and features
N: Chad Whitacre
E: chad@zetaweb.com
D: Python3 porting
N: Itamar Turner-Trauring
E: itamar@pythonspeed.com
D: Python3 porting
N: Jason R. Coombs
E: jaraco@jaraco.com
D: Python3 porting
N: Maciej Fijalkowski
E: fijall@gmail.com
D: Python3 porting
N: Ross Patterson
E: me@rpatterson.net
D: Python3 porting
N: Sajith Sasidharan
E: sajith@hcoop.net
D: Python3 porting
N: Pete Fein
E: pete@snake.dev
D: Python3 porting
N: Viktoriia Savchuk
W: https://twitter.com/viktoriiasvchk
D: Developer community focused improvements on the README file.
N: Lukas Pirl
E: tahoe@lukas-pirl.de
W: http://lukas-pirl.de
D: Buildslaves (Debian, Fedora, CentOS; 2016-2021)
N: Anxhelo Lushka
E: anxhelo1995@gmail.com
D: Web site design and updates
N: Fon E. Noel
E: fenn25.fn@gmail.com
D: bug-fixes and refactoring
N: Jehad Baeth
E: jehad@leastauthority.com
D: Documentation improvement
N: May-Lee Sia
E: mayleesia@gmail.com
D: Community-manager and documentation improvements
N: Yash Nayani
E: yashaswi.nram@gmail.com
D: Installation Guide improvements
N: Florian Sesser
E: florian@private.storage
D: OpenMetrics support

View File

Before

Width:  |  Height:  |  Size: 362 B

After

Width:  |  Height:  |  Size: 362 B

10
Dockerfile Normal file
View File

@ -0,0 +1,10 @@
FROM python:2.7
ADD . /tahoe-lafs
RUN \
cd /tahoe-lafs && \
git pull --depth=100 && \
make && \
ln -vs /tahoe-lafs/bin/tahoe /usr/local/bin/tahoe
WORKDIR /root

View File

@ -1,13 +1,13 @@
include README.rst
include COPYING.GPL COPYING.TGPPL.rst CREDITS Makefile NEWS.rst Tahoe.home
include relnotes.txt
include bin/tahoe-script.template
include Dockerfile
include tox.ini .appveyor.yml .travis.yml
include .coveragerc
recursive-include src *.xhtml *.js *.png *.css *.svg *.txt *.yaml
recursive-include src *.xhtml *.js *.png *.css *.svg *.txt
graft docs
graft misc
graft static
graft integration
graft Contents
graft setuptools-0.6c16dev6.egg
global-exclude *~ *.pyc

329
Makefile
View File

@ -1,57 +1,17 @@
# Tahoe LFS Development and maintenance tasks
#
# NOTE: this Makefile requires GNU make
### Defensive settings for make:
# https://tech.davis-hansson.com/p/make/
SHELL := bash
.ONESHELL:
.SHELLFLAGS := -xeu -o pipefail -c
.SILENT:
.DELETE_ON_ERROR:
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules
default: build
# Local target variables
PYTHON=python
export PYTHON
PYFLAKES=flake8
export PYFLAKES
VIRTUAL_ENV=./.tox/py37
SOURCES=src/allmydata static misc setup.py
APPNAME=tahoe-lafs
TEST_SUITE=allmydata
# setup.py will extend sys.path to include our support/lib/... directory
# itself. It will also create it in the beginning of the 'develop' command.
# Top-level, phony targets
.PHONY: default
default:
@echo "no default target"
.PHONY: test
## Run all tests and code reports
test: .tox/create-venvs.log
# Run codechecks first since it takes the least time to report issues early.
tox --develop -e codechecks
# Run all the test environments in parallel to reduce run-time
tox --develop -p auto -e 'py37'
.PHONY: test-venv-coverage
## Run all tests with coverage collection and reporting.
test-venv-coverage:
# Special handling for reporting coverage even when the test run fails
rm -f ./.coverage.*
test_exit=
$(VIRTUAL_ENV)/bin/coverage run -m twisted.trial --rterrors --reporter=timing \
$(TEST_SUITE) || test_exit="$$?"
$(VIRTUAL_ENV)/bin/coverage combine
$(VIRTUAL_ENV)/bin/coverage xml || true
$(VIRTUAL_ENV)/bin/coverage report
if [ ! -z "$$test_exit" ]; then exit "$$test_exit"; fi
.PHONY: test-py3-all
## Run all tests under Python 3
test-py3-all: .tox/create-venvs.log
tox --develop -e py37 allmydata
TAHOE=$(PYTHON) bin/tahoe
SOURCES=src/allmydata src/buildtest static misc bin/tahoe-script.template setup.py
APPNAME=allmydata-tahoe
# This is necessary only if you want to automatically produce a new
# _version.py file from the current git history (without doing a build).
@ -59,38 +19,110 @@ test-py3-all: .tox/create-venvs.log
make-version:
$(PYTHON) ./setup.py update_version
.built:
$(MAKE) build
src/allmydata/_version.py:
$(MAKE) make-version
# It is unnecessary to have this depend on build or src/allmydata/_version.py,
# since 'setup.py build' always updates the version.
.PHONY: build
build:
$(PYTHON) setup.py build
touch .built
# Build OS X pkg packages.
.PHONY: build-osx-pkg
build-osx-pkg:
.PHONY: build-osx-pkg test-osx-pkg upload-osx-pkg
build-osx-pkg: build
misc/build_helpers/build-osx-pkg.sh $(APPNAME)
.PHONY: test-osx-pkg
test-osx-pkg:
$(PYTHON) misc/build_helpers/test-osx-pkg.py
.PHONY: upload-osx-pkg
upload-osx-pkg:
# [Failure instance: Traceback: <class 'OpenSSL.SSL.Error'>: [('SSL routines', 'ssl3_read_bytes', 'tlsv1 alert unknown ca'), ('SSL routines', 'ssl3_write_bytes', 'ssl handshake failure')]
#
# @echo "uploading to ~tahoe-tarballs/OS-X-packages/ via flappserver"
# @if [ "X${BB_BRANCH}" = "Xmaster" ] || [ "X${BB_BRANCH}" = "X" ]; then \
# flappclient --furlfile ~/.tahoe-osx-pkg-upload.furl upload-file tahoe-lafs-*-osx.pkg; \
# else \
# echo not uploading tahoe-lafs-osx-pkg because this is not trunk but is branch \"${BB_BRANCH}\" ; \
# fi
@echo "uploading to ~tahoe-tarballs/OS-X-packages/ via flappserver"
@if [ "X${BB_BRANCH}" = "Xmaster" ] || [ "X${BB_BRANCH}" = "X" ]; then \
flappclient --furlfile ~/.tahoe-osx-pkg-upload.furl upload-file tahoe-lafs-*-osx.pkg; \
else \
echo not uploading tahoe-lafs-osx-pkg because this is not trunk but is branch \"${BB_BRANCH}\" ; \
fi
# TESTING
# you can use 'make test TEST=allmydata.test.test_introducer' to run just
# test_introducer. TEST=allmydata.test.test_client.Basic.test_permute works
# too.
TEST=allmydata
# It is unnecessary to have this depend on build or src/allmydata/_version.py,
# since 'setup.py test' always updates the version and builds before testing.
.PHONY: test
test:
$(PYTHON) setup.py test $(TRIALARGS) -s $(TEST)
touch .built
.PHONY: check
check: test
.PHONY: quicktest
quicktest: make-version
$(TAHOE) debug trial $(TRIALARGS) $(TEST)
# "make tmpfstest" may be a faster way of running tests on Linux. It works best when you have
# at least 330 MiB of free physical memory (to run the whole test suite). Since it uses sudo
# to mount/unmount the tmpfs filesystem, it might prompt for your password.
.PHONY: tmpfstest
tmpfstest:
time make _tmpfstest 'TMPDIR=$(shell mktemp -d --tmpdir=.)'
.PHONY: _tmpfstest
_tmpfstest: make-version
sudo mount -t tmpfs -o size=400m tmpfs '$(TMPDIR)'
-$(TAHOE) debug trial --rterrors '--temp-directory=$(TMPDIR)/_trial_temp' $(TRIALARGS) $(TEST)
sudo umount '$(TMPDIR)'
rmdir '$(TMPDIR)'
# code coverage: install the "coverage" package from PyPI, do "make test-coverage" to
# do a unit test run with coverage-gathering enabled, then use "make coverage-output" to
# generate an HTML report. Also see "make .coverage.el" and misc/coding_tools/coverage.el
# for Emacs integration.
# This might need to be python-coverage on Debian-based distros.
COVERAGE=coverage
COVERAGEARGS=--branch --source=src/allmydata
# --include appeared in coverage-3.4
COVERAGE_OMIT=--include '$(CURDIR)/src/allmydata/*' --omit '$(CURDIR)/src/allmydata/test/*'
.PHONY: test-coverage
test-coverage: build
rm -f .coverage
$(TAHOE) '@$(COVERAGE)' run $(COVERAGEARGS) @tahoe debug trial $(TRIALARGS) $(TEST)
.PHONY: coverage-output
coverage-output:
rm -rf coverage-html
coverage html -i -d coverage-html $(COVERAGE_OMIT)
cp .coverage coverage-html/coverage.data
@echo "now point your browser at coverage-html/index.html"
.coverage.el: .coverage
$(PYTHON) misc/coding_tools/coverage2el.py
.PHONY: code-checks
#code-checks: build version-and-path check-interfaces check-miscaptures -find-trailing-spaces -check-umids pyflakes
code-checks: check-interfaces check-debugging check-miscaptures -find-trailing-spaces -check-umids pyflakes
code-checks: build version-and-path check-interfaces check-miscaptures -find-trailing-spaces -check-umids pyflakes
.PHONY: version-and-path
version-and-path:
$(TAHOE) --version-and-path
.PHONY: check-interfaces
check-interfaces:
$(PYTHON) misc/coding_tools/check-interfaces.py 2>&1 |tee violations.txt
@echo
.PHONY: check-debugging
check-debugging:
$(PYTHON) misc/coding_tools/check-debugging.py
$(TAHOE) @misc/coding_tools/check-interfaces.py 2>&1 |tee violations.txt
@echo
.PHONY: check-miscaptures
@ -100,7 +132,7 @@ check-miscaptures:
.PHONY: pyflakes
pyflakes:
$(PYFLAKES) $(SOURCES) |sort |uniq
@$(PYTHON) -OOu `which pyflakes` $(SOURCES) |sort |uniq
@echo
.PHONY: check-umids
@ -132,23 +164,65 @@ count-lines:
@echo -n "XXX: "
@grep XXX `find src -name '*.py' |grep -v /build/` | wc -l
.PHONY: check-memory
check-memory: .built
rm -rf _test_memory
$(TAHOE) @src/allmydata/test/check_memory.py upload
$(TAHOE) @src/allmydata/test/check_memory.py upload-self
$(TAHOE) @src/allmydata/test/check_memory.py upload-POST
$(TAHOE) @src/allmydata/test/check_memory.py download
$(TAHOE) @src/allmydata/test/check_memory.py download-GET
$(TAHOE) @src/allmydata/test/check_memory.py download-GET-slow
$(TAHOE) @src/allmydata/test/check_memory.py receive
# Here is a list of testing tools that can be run with 'python' from a
# virtualenv in which Tahoe has been installed. There used to be Makefile
# targets for each, but the exact path to a suitable python is now up to the
# developer. But as a hint, after running 'tox', ./.tox/py37/bin/python will
# probably work.
.PHONY: check-memory-once
check-memory-once: .built
rm -rf _test_memory
$(TAHOE) @src/allmydata/test/check_memory.py $(MODE)
# src/allmydata/test/bench_dirnode.py
# The check-speed target uses a pre-established client node to run a canned
# set of performance tests against a test network that is also
# pre-established (probably on a remote machine). Provide it with the path to
# a local directory where this client node has been created (and populated
# with the necessary FURLs of the test network). This target will start that
# client with the current code and then run the tests. Afterwards it will
# stop the client.
#
# The 'sleep 5' is in there to give the new client a chance to connect to its
# storageservers, since check_speed.py has no good way of doing that itself.
.PHONY: check-speed
check-speed: .built
if [ -z '$(TESTCLIENTDIR)' ]; then exit 1; fi
@echo "stopping any leftover client code"
-$(TAHOE) stop $(TESTCLIENTDIR)
$(TAHOE) start $(TESTCLIENTDIR)
sleep 5
$(TAHOE) @src/allmydata/test/check_speed.py $(TESTCLIENTDIR)
$(TAHOE) stop $(TESTCLIENTDIR)
# The check-grid target also uses a pre-established client node, along with a
# long-term directory that contains some well-known files. See the docstring
# in src/allmydata/test/check_grid.py to see how to set this up.
##.PHONY: check-grid
##check-grid: .built
## if [ -z '$(TESTCLIENTDIR)' ]; then exit 1; fi
## $(TAHOE) @src/allmydata/test/check_grid.py $(TESTCLIENTDIR) bin/tahoe
.PHONY: check-grid
check-grid: .built
if [ -z '$(TESTCLIENTDIR)' ]; then exit 1; fi
$(TAHOE) @src/allmydata/test/check_grid.py $(TESTCLIENTDIR) bin/tahoe
.PHONY: bench-dirnode
bench-dirnode: .built
$(TAHOE) @src/allmydata/test/bench_dirnode.py
# the provisioning tool runs as a stand-alone webapp server
.PHONY: run-provisioning-tool
run-provisioning-tool: .built
$(TAHOE) @misc/operations_helpers/provisioning/run.py
# 'make repl' is a simple-to-type command to get a Python interpreter loop
# from which you can type 'import allmydata'
.PHONY: repl
repl:
$(TAHOE) debug repl
.PHONY: test-get-ignore
test-git-ignore:
@ -170,19 +244,21 @@ test-clean:
# Use 'make distclean' instead to delete all generated files.
.PHONY: clean
clean:
rm -rf build _trial_temp .built
rm -rf build _trial_temp _test_memory .built
rm -f `find src *.egg -name '*.so' -or -name '*.pyc'`
rm -rf support dist
rm -rf `ls -d *.egg | grep -vEe"setuptools-|setuptools_darcs-|darcsver-"`
rm -rf *.pyc
rm -rf misc/dependencies/build misc/dependencies/temp
rm -rf misc/dependencies/tahoe_deps.egg-info
rm -f bin/tahoe bin/tahoe.pyscript
rm -f *.pkg
.PHONY: distclean
distclean: clean
rm -rf src/*.egg-info
rm -rf src/allmydata_tahoe.egg-info
rm -f src/allmydata/_version.py
rm -f src/allmydata/_appname.py
rm -rf ./.tox/
.PHONY: find-trailing-spaces
@ -195,91 +271,34 @@ find-trailing-spaces:
-$(PYTHON) misc/coding_tools/find-trailing-spaces.py -r $(SOURCES)
@echo
# The test-desert-island target grabs the tahoe-deps tarball, unpacks it,
# does a build, then asserts that the build did not try to download anything
# as it ran. Invoke this on a new tree, or after a 'clean', to make sure the
# support/lib/ directory is gone.
.PHONY: fetch-and-unpack-deps
fetch-and-unpack-deps:
@echo "test-and-unpack-deps is obsolete"
test -f tahoe-deps.tar.gz || wget https://tahoe-lafs.org/source/tahoe-lafs/deps/tahoe-lafs-deps.tar.gz
rm -rf tahoe-deps
tar xzf tahoe-lafs-deps.tar.gz
.PHONY: test-desert-island
test-desert-island:
@echo "test-desert-island is obsolete"
$(MAKE) fetch-and-unpack-deps
$(MAKE) 2>&1 | tee make.out
$(PYTHON) misc/build_helpers/check-build.py make.out no-downloads
.PHONY: test-pip-install
test-pip-install:
@echo "test-pip-install is obsolete"
$(PYTHON) misc/build_helpers/test-pip-install.py
# TARBALL GENERATION
.PHONY: tarballs
tarballs: # delegated to tox, so setup.py can update setuptools if needed
tox -e tarballs
tarballs:
$(MAKE) make-version
$(PYTHON) setup.py sdist --formats=bztar,gztar,zip
$(PYTHON) setup.py sdist --sumo --formats=bztar,gztar,zip
.PHONY: upload-tarballs
upload-tarballs:
@if [ "X${BB_BRANCH}" = "Xmaster" ] || [ "X${BB_BRANCH}" = "X" ]; then for f in dist/*; do flappclient --furlfile ~/.tahoe-tarball-upload.furl upload-file $$f; done ; else echo not uploading tarballs because this is not trunk but is branch \"${BB_BRANCH}\" ; fi
# Real targets
src/allmydata/_version.py:
$(MAKE) make-version
.tox/create-venvs.log: tox.ini setup.py
tox --notest -p all | tee -a "$(@)"
# to make a new release:
# - create a ticket for the release in Trac
# - ensure local copy is up-to-date
# - create a branch like "XXXX.release" from up-to-date master
# - in the branch, run "make release"
# - run "make release-test"
# - perform any other sanity-checks on the release
# - run "make release-upload"
# Note that several commands below hard-code "meejah"; if you are
# someone else please adjust them.
release:
@echo "Is checkout clean?"
git diff-files --quiet
git diff-index --quiet --cached HEAD --
@echo "Clean docs build area"
rm -rf docs/_build/
@echo "Install required build software"
python3 -m pip install --editable .[build]
@echo "Test README"
python3 setup.py check -r -s
@echo "Update NEWS"
python3 -m towncrier build --yes --version `python3 misc/build_helpers/update-version.py --no-tag`
git add -u
git commit -m "update NEWS for release"
# note that this always bumps the "middle" number, e.g. from 1.17.1 -> 1.18.0
# and produces a tag into the Git repository
@echo "Bump version and create tag"
python3 misc/build_helpers/update-version.py
@echo "Build and sign wheel"
python3 setup.py bdist_wheel
gpg --pinentry=loopback -u meejah@meejah.ca --armor --detach-sign dist/tahoe_lafs-`git describe | cut -b 12-`-py3-none-any.whl
ls dist/*`git describe | cut -b 12-`*
@echo "Build and sign source-dist"
python3 setup.py sdist
gpg --pinentry=loopback -u meejah@meejah.ca --armor --detach-sign dist/tahoe-lafs-`git describe | cut -b 12-`.tar.gz
ls dist/*`git describe | cut -b 12-`*
# basically just a bare-minimum smoke-test that it installs and runs
release-test:
gpg --verify dist/tahoe-lafs-`git describe | cut -b 12-`.tar.gz.asc
gpg --verify dist/tahoe_lafs-`git describe | cut -b 12-`-py3-none-any.whl.asc
virtualenv testmf_venv
testmf_venv/bin/pip install dist/tahoe_lafs-`git describe | cut -b 12-`-py3-none-any.whl
testmf_venv/bin/tahoe --version
rm -rf testmf_venv
release-upload:
scp dist/*`git describe | cut -b 12-`* meejah@tahoe-lafs.org:/home/source/downloads
git push origin_push tahoe-lafs-`git describe | cut -b 12-`
twine upload dist/tahoe_lafs-`git describe | cut -b 12-`-py3-none-any.whl dist/tahoe_lafs-`git describe | cut -b 12-`-py3-none-any.whl.asc dist/tahoe-lafs-`git describe | cut -b 12-`.tar.gz dist/tahoe-lafs-`git describe | cut -b 12-`.tar.gz.asc
@if [ "X${BB_BRANCH}" = "Xmaster" ] || [ "X${BB_BRANCH}" = "X" ]; then for f in dist/$(APPNAME)-*; do flappclient --furlfile ~/.tahoe-tarball-upload.furl upload-file $$f; done ; else echo not uploading tarballs because this is not trunk but is branch \"${BB_BRANCH}\" ; fi

1167
NEWS.rst

File diff suppressed because one or more lines are too long

View File

@ -1,149 +1,38 @@
======================================
Free and Open Decentralized Data Store
======================================
==========
Tahoe-LAFS
==========
|image0|
Tahoe-LAFS is a Free and Open decentralized cloud storage system. It distributes
your data across multiple servers. Even if some of the servers fail or are taken
over by an attacker, the entire file store continues to function correctly,
preserving your privacy and security.
`Tahoe-LAFS <https://www.tahoe-lafs.org>`__ (Tahoe Least-Authority File Store) is the first free software / open-source storage technology that distributes your data across multiple servers. Even if some servers fail or are taken over by an attacker, the entire file store continues to function correctly, preserving your privacy and security.
To get started please see `quickstart.rst`_ in the docs directory.
|Contributor Covenant| |readthedocs| |circleci| |githubactions| |coveralls|
LICENCE
=======
Copyright 2006-2015 The Tahoe-LAFS Software Foundation
Table of contents
You may use this package under the GNU General Public License, version 2 or, at
your option, any later version. You may use this package under the Transitive
Grace Period Public Licence, version 1.0, or at your option, any later
version. (You may choose to use this package under the terms of either licence,
at your option.) See the file `COPYING.GPL`_ for the terms of the GNU General
Public License, version 2. See the file `COPYING.TGPPL.rst`_ for the terms of
the Transitive Grace Period Public Licence, version 1.0.
- `About Tahoe-LAFS <#about-tahoe-lafs>`__
See `TGPPL.PDF`_ for why the TGPPL exists, graphically illustrated on three slides.
- `Installation <#installation>`__
.. _quickstart.rst: https://github.com/tahoe-lafs/tahoe-lafs/blob/master/docs/quickstart.rst
.. _COPYING.GPL: https://github.com/tahoe-lafs/tahoe-lafs/blob/master/COPYING.GPL
.. _COPYING.TGPPL.rst: https://github.com/tahoe-lafs/tahoe-lafs/blob/master/COPYING.TGPPL.rst
.. _TGPPL.PDF: https://tahoe-lafs.org/~zooko/tgppl.pdf
- `Issues <#issues>`__
----
- `Documentation <#documentation>`__
.. image:: https://travis-ci.org/tahoe-lafs/tahoe-lafs.png?branch=master
:target: https://travis-ci.org/tahoe-lafs/tahoe-lafs
- `Community <#community>`__
- `Contributing <#contributing>`__
- `FAQ <#faq>`__
- `License <#license>`__
💡 About Tahoe-LAFS
-------------------
Tahoe-LAFS helps you to store files while granting confidentiality, integrity, and availability of your data.
How does it work? You run a client program on your computer, which talks to one or more storage servers on other computers. When you tell your client to store a file, it will encrypt that file, encode it into multiple pieces, then spread those pieces out among various servers. The pieces are all encrypted and protected against modifications. Later, when you ask your client to retrieve the file, it will find the necessary pieces, make sure they havent been corrupted, reassemble them, and decrypt the result.
| |image2|
| *The image is taken from meejah's* \ `blog <https://blog.torproject.org/tor-heart-tahoe-lafs>`__ \ *post at Torproject.org.*
|
The client creates pieces (“shares”) that have a configurable amount of redundancy, so even if some servers fail, you can still get your data back. Corrupt shares are detected and ignored so that the system can tolerate server-side hard-drive errors. All files are encrypted (with a unique key) before uploading, so even a malicious server operator cannot read your data. The only thing you ask of the servers is that they can (usually) provide the shares when you ask for them: you arent relying upon them for confidentiality, integrity, or absolute availability.
Tahoe-LAFS was first designed in 2007, following the "principle of least authority", a security best practice requiring system components to only have the privilege necessary to complete their intended function and not more.
Please read more about Tahoe-LAFS architecture `here <docs/architecture.rst>`__.
✅ Installation
---------------
For more detailed instructions, read `Installing Tahoe-LAFS <docs/Installation/install-tahoe.rst>`__.
Once ``tahoe --version`` works, see `How to Run Tahoe-LAFS <docs/running.rst>`__ to learn how to set up your first Tahoe-LAFS node.
🐍 Python 2
-----------
Python 3.8 or later is required.
If you are still using Python 2.7, use Tahoe-LAFS version 1.17.1.
🤖 Issues
---------
Tahoe-LAFS uses the Trac instance to track `issues <https://www.tahoe-lafs.org/trac/tahoe-lafs/wiki/ViewTickets>`__. Please email jean-paul plus tahoe-lafs at leastauthority dot com for an account.
📑 Documentation
----------------
You can find the full Tahoe-LAFS documentation at our `documentation site <http://tahoe-lafs.readthedocs.io/en/latest/>`__.
💬 Community
------------
Get involved with the Tahoe-LAFS community:
- Chat with Tahoe-LAFS developers at ``#tahoe-lafs`` channel on `libera.chat <https://libera.chat/>`__ IRC network or `Slack <https://join.slack.com/t/tahoe-lafs/shared_invite/zt-jqfj12r5-ZZ5z3RvHnubKVADpP~JINQ>`__.
- Join our `weekly conference calls <https://www.tahoe-lafs.org/trac/tahoe-lafs/wiki/WeeklyMeeting>`__ with core developers and interested community members.
- Subscribe to `the tahoe-dev mailing list <https://lists.tahoe-lafs.org/mailman/listinfo/tahoe-dev>`__, the community forum for discussion of Tahoe-LAFS design, implementation, and usage.
🤗 Contributing
---------------
As a community-driven open source project, Tahoe-LAFS welcomes contributions of any form:
- `Code patches <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/Patches>`__
- `Documentation improvements <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/Doc>`__
- `Bug reports <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/HowToReportABug>`__
- `Patch reviews <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/PatchReviewProcess>`__
Before authoring or reviewing a patch, please familiarize yourself with the `Coding Standard <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/CodingStandards>`__ and the `Contributor Code of Conduct <docs/CODE_OF_CONDUCT.md>`__.
🥳 First Contribution?
----------------------
If you are committing to Tahoe for the very first time, it's required that you add your name to our contributor list in `CREDITS <CREDITS>`__. Please ensure that this addition has it's own commit within your first contribution.
🤝 Supporters
--------------
We would like to thank `Fosshost <https://fosshost.org>`__ for supporting us with hosting services. If your open source project needs help, you can apply for their support.
We are grateful to `Oregon State University Open Source Lab <https://osuosl.org/>`__ for hosting tahoe-dev mailing list.
❓ FAQ
------
Need more information? Please check our `FAQ page <https://www.tahoe-lafs.org/trac/tahoe-lafs/wiki/FAQ>`__.
📄 License
----------
Copyright 2006-2020 The Tahoe-LAFS Software Foundation
You may use this package under the GNU General Public License, version 2 or, at your option, any later version. You may use this package under the Transitive Grace Period Public Licence, version 1.0, or at your choice, any later version. (You may choose to use this package under the terms of either license, at your option.) See the file `COPYING.GPL <COPYING.GPL>`__ for the terms of the GNU General Public License, version 2. See the file `COPYING.TGPPL <COPYING.TGPPL.rst>`__ for the terms of the Transitive Grace Period Public Licence, version 1.0.
See `TGPPL.PDF <https://tahoe-lafs.org/~zooko/tgppl.pdf>`__ for why the TGPPL exists, graphically illustrated on three slides.
.. |image0| image:: docs/_static/media/image2.png
:width: 3in
:height: 0.91667in
.. |image2| image:: docs/_static/media/image1.png
:width: 6.9252in
:height: 2.73611in
.. |readthedocs| image:: http://readthedocs.org/projects/tahoe-lafs/badge/?version=latest
:alt: documentation status
:target: http://tahoe-lafs.readthedocs.io/en/latest/?badge=latest
.. |circleci| image:: https://circleci.com/gh/tahoe-lafs/tahoe-lafs.svg?style=svg
:target: https://circleci.com/gh/tahoe-lafs/tahoe-lafs
.. |githubactions| image:: https://github.com/tahoe-lafs/tahoe-lafs/actions/workflows/ci.yml/badge.svg
:target: https://github.com/tahoe-lafs/tahoe-lafs/actions
.. |coveralls| image:: https://coveralls.io/repos/github/tahoe-lafs/tahoe-lafs/badge.svg
:alt: code coverage
:target: https://coveralls.io/github/tahoe-lafs/tahoe-lafs
.. |Contributor Covenant| image:: https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg
:alt: code of conduct
:target: docs/CODE_OF_CONDUCT.md
.. image:: https://coveralls.io/repos/tahoe-lafs/tahoe-lafs/badge.png?branch=master
:target: https://coveralls.io/r/tahoe-lafs/tahoe-lafs?branch=master

View File

@ -1,12 +0,0 @@
"""
pytest-based end-to-end benchmarks of Tahoe-LAFS.
Usage:
$ systemd-run --user --scope pytest benchmark --number-of-nodes=3
It's possible to pass --number-of-nodes multiple times.
The systemd-run makes sure the tests run in their own cgroup so we get CPU
accounting correct.
"""

View File

@ -1,150 +0,0 @@
"""
pytest infrastructure for benchmarks.
The number of nodes is parameterized via a --number-of-nodes CLI option added
to pytest.
"""
import os
from shutil import which, rmtree
from tempfile import mkdtemp
from contextlib import contextmanager
from time import time
import pytest
import pytest_twisted
from twisted.internet import reactor
from twisted.internet.defer import DeferredList, succeed
from allmydata.util.iputil import allocate_tcp_port
from integration.grid import Client, create_grid, create_flog_gatherer
def pytest_addoption(parser):
parser.addoption(
"--number-of-nodes",
action="append",
default=[],
type=int,
help="list of number_of_nodes to benchmark against",
)
# Required to be compatible with integration.util code that we indirectly
# depend on, but also might be useful.
parser.addoption(
"--force-foolscap",
action="store_true",
default=False,
dest="force_foolscap",
help=(
"If set, force Foolscap only for the storage protocol. "
+ "Otherwise HTTP will be used."
),
)
def pytest_generate_tests(metafunc):
# Make number_of_nodes accessible as a parameterized fixture:
if "number_of_nodes" in metafunc.fixturenames:
metafunc.parametrize(
"number_of_nodes",
metafunc.config.getoption("number_of_nodes"),
scope="session",
)
def port_allocator():
port = allocate_tcp_port()
return succeed(port)
@pytest.fixture(scope="session")
def grid(request):
"""
Provides a new Grid with a single Introducer and flog-gathering process.
Notably does _not_ provide storage servers; use the storage_nodes
fixture if your tests need a Grid that can be used for puts / gets.
"""
tmp_path = mkdtemp(prefix="tahoe-benchmark")
request.addfinalizer(lambda: rmtree(tmp_path))
flog_binary = which("flogtool")
flog_gatherer = pytest_twisted.blockon(
create_flog_gatherer(reactor, request, tmp_path, flog_binary)
)
g = pytest_twisted.blockon(
create_grid(reactor, request, tmp_path, flog_gatherer, port_allocator)
)
return g
@pytest.fixture(scope="session")
def storage_nodes(grid, number_of_nodes):
nodes_d = []
for _ in range(number_of_nodes):
nodes_d.append(grid.add_storage_node())
nodes_status = pytest_twisted.blockon(DeferredList(nodes_d))
for ok, value in nodes_status:
assert ok, "Storage node creation failed: {}".format(value)
return grid.storage_servers
@pytest.fixture(scope="session")
def client_node(request, grid, storage_nodes, number_of_nodes) -> Client:
"""
Create a grid client node with number of shares matching number of nodes.
"""
client_node = pytest_twisted.blockon(
grid.add_client(
"client_node",
needed=number_of_nodes,
happy=number_of_nodes,
total=number_of_nodes,
)
)
print(f"Client node pid: {client_node.process.transport.pid}")
return client_node
def get_cpu_time_for_cgroup():
"""
Get how many CPU seconds have been used in current cgroup so far.
Assumes we're running in a v2 cgroup.
"""
with open("/proc/self/cgroup") as f:
cgroup = f.read().strip().split(":")[-1]
assert cgroup.startswith("/")
cgroup = cgroup[1:]
cpu_stat = os.path.join("/sys/fs/cgroup", cgroup, "cpu.stat")
with open(cpu_stat) as f:
for line in f.read().splitlines():
if line.startswith("usage_usec"):
return int(line.split()[1]) / 1_000_000
raise ValueError("Failed to find usage_usec")
class Benchmarker:
"""Keep track of benchmarking results."""
@contextmanager
def record(self, capsys: pytest.CaptureFixture[str], name, **parameters):
"""Record the timing of running some code, if it succeeds."""
start_cpu = get_cpu_time_for_cgroup()
start = time()
yield
elapsed = time() - start
end_cpu = get_cpu_time_for_cgroup()
elapsed_cpu = end_cpu - start_cpu
# FOR now we just print the outcome:
parameters = " ".join(f"{k}={v}" for (k, v) in parameters.items())
with capsys.disabled():
print(
f"\nBENCHMARK RESULT: {name} {parameters} elapsed={elapsed:.3} (secs) CPU={elapsed_cpu:.3} (secs)\n"
)
@pytest.fixture(scope="session")
def tahoe_benchmarker():
return Benchmarker()

View File

@ -1,66 +0,0 @@
"""Benchmarks for minimal `tahoe` CLI interactions."""
from subprocess import Popen, PIPE
import pytest
from integration.util import cli
@pytest.fixture(scope="module", autouse=True)
def cli_alias(client_node):
cli(client_node.process, "create-alias", "cli")
@pytest.mark.parametrize("file_size", [1000, 100_000, 1_000_000, 10_000_000])
def test_get_put_files_sequentially(
file_size,
client_node,
tahoe_benchmarker,
number_of_nodes,
capsys,
):
"""
Upload 5 files with ``tahoe put`` and then download them with ``tahoe
get``, measuring the latency of both operations. We do multiple uploads
and downloads to try to reduce noise.
"""
DATA = b"0123456789" * (file_size // 10)
with tahoe_benchmarker.record(
capsys, "cli-put-5-file-sequentially", file_size=file_size, number_of_nodes=number_of_nodes
):
for i in range(5):
p = Popen(
[
"tahoe",
"--node-directory",
client_node.process.node_dir,
"put",
"-",
f"cli:get_put_files_sequentially{i}",
],
stdin=PIPE,
)
p.stdin.write(DATA)
p.stdin.write(str(i).encode("ascii"))
p.stdin.close()
assert p.wait() == 0
with tahoe_benchmarker.record(
capsys, "cli-get-5-files-sequentially", file_size=file_size, number_of_nodes=number_of_nodes
):
for i in range(5):
p = Popen(
[
"tahoe",
"--node-directory",
client_node.process.node_dir,
"get",
f"cli:get_put_files_sequentially{i}",
"-",
],
stdout=PIPE,
)
assert p.stdout.read() == DATA + str(i).encode("ascii")
assert p.wait() == 0

130
bin/tahoe-script.template Normal file
View File

@ -0,0 +1,130 @@
#!/bin/false # You must specify a python interpreter.
import sys; assert sys.version_info < (3,), ur"Tahoe-LAFS does not run under Python 3. Please use a version of Python between 2.6 and 2.7.x inclusive."
import os, subprocess
where = os.path.realpath(sys.argv[0])
base = os.path.dirname(os.path.dirname(where))
if sys.platform == "win32":
perhaps_installed_tahoe = os.path.join(os.path.dirname(sys.executable), 'Scripts', 'tahoe.pyscript')
else:
perhaps_installed_tahoe = "/usr/bin/tahoe"
whoami = '''\
I am a "bin%stahoe" executable for the convenience of running Tahoe-LAFS
from its source distribution -- I work only when invoked as the "tahoe"
script that lives in the "bin" subdirectory of a Tahoe source code
distribution, and only if you have already run "python setup.py build".
''' % (os.path.sep,)
# look for Tahoe.home .
homemarker = os.path.join(base, "Tahoe.home")
if not os.path.exists(homemarker):
print(whoami)
print('''\
I just tried to run and found that I am not living in such a directory, so I
am stopping now. To run Tahoe after it has been is installed, please execute
my brother, who gets installed into the appropriate place for executables
when you run "make install" (perhaps as "%s").
''' % (perhaps_installed_tahoe,))
sys.exit(1)
# we've found our home. Put the tahoe support/lib etc. in our PYTHONPATH.
if sys.platform == "win32":
supportdir = os.path.join(base, "support", "Lib", "site-packages")
else:
supportdir = os.path.join(base, "support",
"lib",
"python%d.%d" % sys.version_info[:2],
"site-packages")
# update PYTHONPATH so that child processes (like twistd) will use this too
pp = os.environ.get("PYTHONPATH")
if pp:
pp = os.pathsep.join([supportdir] + pp.split(os.pathsep))
else:
pp = supportdir
os.environ["PYTHONPATH"] = pp
# find commandline args and the location of the tahoe executable.
if sys.platform == "win32":
import re
from ctypes import WINFUNCTYPE, POINTER, byref, c_wchar_p, c_int, windll
GetCommandLineW = WINFUNCTYPE(c_wchar_p)(("GetCommandLineW", windll.kernel32))
CommandLineToArgvW = WINFUNCTYPE(POINTER(c_wchar_p), c_wchar_p, POINTER(c_int)) \
(("CommandLineToArgvW", windll.shell32))
argc = c_int(0)
argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc))
# See src/allmydata/scripts/runner.py for the corresponding unmangler.
# Note that this doesn't escape \x7F. If it did, test_unicode_arguments_and_output
# in test_runner.py wouldn't work.
def mangle(s):
return str(re.sub(u'[^\\x20-\\x7F]', lambda m: u'\x7F%x;' % (ord(m.group(0)),), s))
argv = [mangle(argv_unicode[i]) for i in xrange(0, argc.value)]
# Take only the suffix with the same number of arguments as sys.argv.
# This accounts for anything that can cause initial arguments to be stripped,
# for example, the Python interpreter or any options passed to it, or runner
# scripts such as 'coverage run'. It works even if there are no such arguments,
# as in the case of a frozen executable created by bb-freeze or similar.
argv = argv[-len(sys.argv):]
# On Windows, the script is not directly executable and must be run via python.
prefix = [sys.executable]
script = os.path.join(base, "support", "Scripts", "tahoe.pyscript")
args = argv[1:]
else:
# On non-Windows, invoke the script directly, so that 'top' for example shows 'tahoe'.
prefix = []
script = os.path.join(base, "support", "bin", "tahoe")
args = sys.argv[1:]
# Support indirection via another "runner" script (e.g. coverage).
# For example: bin/tahoe @RUNNER RUNNER_ARGS @tahoe TAHOE_ARGS
if len(args) >= 1 and args[0].startswith('@'):
runner = args[0][1:]
if runner.endswith('.py') or runner.endswith('.pyscript'):
prefix = [sys.executable]
else:
prefix = []
if runner == "python":
runner = sys.executable
def _subst(a):
if a == '@tahoe': return script
return a
command = prefix + [runner] + map(_subst, args[1:])
else:
runner = script
command = prefix + [script] + args
if not os.path.exists(script):
print(whoami)
print('''\
I could not find the support script
"%s".
To run an installed version of Tahoe-LAFS, please execute the "tahoe"
script that is installed into the appropriate place for executables
when you run "python setup.py install" (perhaps as "%s").
''' % (script, perhaps_installed_tahoe))
sys.exit(1)
try:
res = subprocess.call(command, env=os.environ)
except Exception as le:
print(whoami)
print('''\
I just tried to invoke "%s"
and got an exception.
''' % (runner,))
raise
else:
sys.exit(res)

View File

@ -1,13 +0,0 @@
# This is the flake-compat glue code. It loads the flake and gives us its
# outputs. This gives us backwards compatibility with pre-flake consumers.
# All of the real action is in flake.nix.
(import
(
let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
)
{ src = ./.; }
).defaultNix.default

View File

@ -1,55 +0,0 @@
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to
fairly and consistently applying these principles to every aspect of managing
this project. Project maintainers who do not follow or enforce the Code of
Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting a project maintainer (see below). All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. Maintainers are
obligated to maintain confidentiality with regard to the reporter of an
incident.
The following community members have made themselves available for conduct issues:
- Jean-Paul Calderone (jean-paul at leastauthority dot com)
- meejah (meejah at meejah dot ca)
- May-Lee Sia(she/her) (tahoe dot lafs dot community at gmail dot com)
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/

View File

@ -1,140 +0,0 @@
***************************************
Building Tahoe-LAFS On A Desert Island
***************************************
(or an airplane, or anywhere else without internet connectivity)
Here's the story: you leave for the airport in an hour, you know you want to
do some Tahoe hacking on the flight. What can you grab right now that will
let you install the necessary dependencies later, when you are offline?
Pip can help, with a technique described in the pip documentation
https://pip.pypa.io/en/stable/user_guide/#installing-from-local-packages .
First, do two setup steps:
* ``mkdir ~/.pip/wheels``
* edit ``~/.pip/pip.conf`` to set ``[global] find-links = ~/.pip/wheels``
(the filename may vary on non-unix platforms: check the pip documentation for
details)
This instructs all ``pip install`` commands to look in your local directory
for compiled wheels, in addition to asking PyPI and the normal wheel cache.
Before you get shipwrecked (or leave the internet for a while), do this from
your tahoe source tree (or any python source tree that you want to hack on):
* ``pip wheel -w ~/.pip/wheels .``
That command will require network and time: it will download and compile
whatever is necessary right away. Schedule your shipwreck for *after* it
completes.
Specifically, it will get wheels for everything that the current project
(".", i.e. tahoe) needs, and write them to the ``~/.pip/wheels`` directory.
It will query PyPI to learn the current version of every dependency, then
acquire wheels from the first source that has one:
* copy from our ``~/.pip/wheels`` directory
* copy from the local wheel cache (see below for where this lives)
* download a wheel from PyPI
* build a wheel from a tarball (cached or downloaded)
Later, on the plane, do this:
* ``virtualenv --no-download ve``
* ``. ve/bin/activate``
* ``pip install --no-index --editable .``
That tells virtualenv/pip to not try to contact PyPI, and your ``pip.conf``
"find-links" tells them to use the wheels in ``~/.pip/wheels/`` instead.
How This Works
==============
The pip wheel cache
-------------------
Modern versions of pip and setuptools will, by default, cache both their HTTP
downloads and their generated wheels. When pip is asked to install a package,
it will first check with PyPI. If the PyPI index says it needs to download a
newer version, but it can find a copy of the tarball/zipball/wheel in the
HTTP cache, it will not actually download anything. Then it tries to build a
wheel: if it already has one in the wheel cache (downloaded or built
earlier), it will not actually build anything.
If it cannot contact PyPI, it will fail. The ``--no-index`` above is to tell
it to skip the PyPI step, but that leaves it with no source of packages. The
``find-links`` setting is what provides an alternate source of packages.
The HTTP and wheel caches are not single flat directories: they use a
hierarchy of subdirectories, named after a hash of the URL or name of the
object being stored (this is to avoid filesystem limitations on the size of a
directory). As a result, the wheel cache is not suitable for use as a
``find-links`` target (but see below).
There is a command named ``pip wheel`` which only creates wheels (and stores
them in ``--wheel-dir=``, which defaults to the current directory). This
command does not populate the wheel cache: it reads from (and writes to) the
HTTP cache, and reads from the wheel cache, but will only save the generated
wheels into the directory you specify with ``--wheel-dir=``.
Where Does The Cache Live?
--------------------------
Pip's cache location depends upon the platform. On linux, it defaults to
~/.cache/pip/ (both http/ and wheels/). On OS-X (homebrew), it uses
~/Library/Caches/pip/ . On Windows, try ~\AppData\Local\pip\cache .
The location can be overridden by ``pip.conf``. Look for the "wheel-dir",
"cache-dir", and "find-links" options.
How Can I Tell If It's Using The Cache?
---------------------------------------
When "pip install" has to download a source tarball (and build a wheel), it
will say things like::
Collecting zfec
Downloading zfec-1.4.24.tar.gz (175kB)
Building wheels for collected packages: zfec
Running setup.py bdist_wheel for zfec ... done
Stored in directory: $CACHEDIR
Successfully built zfec
Installing collected packages: zfec
Successfully installed zfec-1.4.24
When "pip install" can use a cached downloaded tarball, but does not have a
cached wheel, it will say::
Collecting zfec
Using cached zfec-1.4.24.tar.gz
Building wheels for collected packages: zfec
Running setup.py bdist_wheel for zfec ... done
Stored in directory: $CACHEDIR
Successfully built zfec
Installing collected packages: zfec
Successfully installed zfec-1.4.24
When "pip install" can use a cached wheel, it will just say::
Collecting zfec
Installed collected packages: zfec
Successfully installed zfec-1.4.24
Many packages publish pre-built wheels next to their source tarballs. This is
common for non-platform-specific (pure-python) packages. It is also common
for them to provide pre-compiled windows and OS-X wheel, so users do not have
to have a compiler installed (pre-compiled Linux wheels are not common,
because there are too many platform variations). When "pip install" can use a
downloaded wheel like this, it will say::
Collecting six
Downloading six-1.10.0-py2.py3-none-any.whl
Installing collected packages: six
Successfully installed six-1.10.0
Note that older versions of pip do not always use wheels, or the cache. Pip
8.0.0 or newer should be ok. The version of setuptools may also be
significant.

View File

@ -1,75 +0,0 @@
****************************
Building Tahoe-LAFS on Linux
****************************
Tahoe-LAFS has made packages available for installing on many linux and BSD distributions.
Debian and Ubuntu users can use ``apt-get install tahoe-lafs``.
If you are working on a Linux distribution which does not have Tahoe-LAFS or are looking to hack on the source code, you can build Tahoe-LAFS yourself:
Prerequisites
=============
Make sure the following are installed:
* **Python 3's latest version**: Check for the version by running ``python --version``.
* **pip**: Most python installations already include ``pip``. However, if your installation does not, see `pip installation <https://pip.pypa.io/en/stable/installing/>`_.
* **virtualenv**: Use ``pip`` to install virtualenv::
pip install --user virtualenv
* **C compiler and libraries**:
* ``python-dev``: Python development headers.
* ``libffi-dev``: Foreign Functions Interface library.
* ``libssl-dev``: SSL library, Tahoe-LAFS needs OpenSSL version 1.1.1c or greater.
.. note::
If you are working on Debian or Ubuntu, you can install the necessary libraries using ``apt-get``::
apt-get install python-dev libffi-dev libssl-dev
On an RPM-based system such as Fedora, you can install the necessary libraries using ``yum`` or ``rpm``. However, the packages may be named differently.
Install the Latest Tahoe-LAFS Release
=====================================
If you are looking to hack on the source code or run pre-release code, we recommend you install Tahoe-LAFS directly from source by creating a ``virtualenv`` instance:
1. Clone the Tahoe-LAFS repository::
git clone https://github.com/tahoe-lafs/tahoe-lafs.git
2. Move into the tahoe-lafs directory::
cd tahoe-lafs
3. Create a fresh virtualenv for your Tahoe-LAFS install::
virtualenv venv
.. note::
venv is the name of the virtual environment in this example. Use any name for your environment.
4. Upgrade ``pip`` and ``setuptools`` on the newly created virtual environment::
venv/bin/pip install -U pip setuptools
5. If you'd like to modify the Tahoe source code, you need to install Tahoe-LAFS with the ``--editable`` flag with the ``test`` extra::
venv/bin/pip install --editable .[test]
.. note::
Tahoe-LAFS provides extra functionality when requested explicitly at installation using the "extras" feature of setuptools. To learn more about the extras which Tahoe supports, see Tahoe extras.
6. Verify installation by checking for the version::
venv/bin/tahoe --version
If you do not want to use the full path, i.e., ``venv/bin/tahoe`` everytime you want to run tahoe, you can activate the ``virtualenv``::
. venv/bin/activate
This will generate a subshell with a ``$PATH`` that includes the ``venv/bin/`` directory.

View File

@ -1,45 +0,0 @@
******************************
Building Tahoe-LAFS on Windows
******************************
If you are looking to hack on the source code or run pre-release code, we recommend you create a virtualenv instance and install Tahoe-LAFS into that:
1. Make sure you have Powershell installed. See `PowerShell installation <https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-7.1>`_.
2. Install the latest version of Python 3. Download the .exe file at the `python website <https://www.python.org/downloads/>`_.
3. Open the installer by double-clicking it. Select the **Add Python to PATH** check-box, then click **Install Now**.
4. Start PowerShell and enter the following command to verify python installation::
python --version
5. Use ``pip`` to install ``virtualenv``::
pip install --user virtualenv
6. Create a fresh virtualenv for your Tahoe-LAFS install using the following command::
virtualenv venv
.. note::
venv is the name of the virtual environment in this example. Use any name for your environment.
7. Use pip to install Tahoe-LAFS in the virtualenv instance::
venv\Scripts\pip install tahoe-lafs
6. Verify installation by checking for the version::
venv\Scripts\tahoe --version
If you do not want to use the full path, i.e. ``venv\Scripts\tahoe`` everytime you want to run tahoe, you can:
* Activate the virtualenv::
. venv\Scripts\activate
This will generate a subshell with a ``$PATH`` that includes the ``venv\Scripts\`` directory.
* Change your ``$PATH`` to include the ``venv\Scripts`` directory.

View File

@ -1,68 +0,0 @@
.. -*- coding: utf-8-with-signature-unix; fill-column: 77 -*-
..
note: if you aren't reading the rendered form of these docs at
http://tahoe-lafs.readthedocs.io/en/latest/ , then be aware that any
":doc:" links refer to other files in this docs/ directory
*********************
Installing Tahoe-LAFS
*********************
`Tahoe-LAFS`_ is a secure, decentralized, and fault-tolerant storage system.
To see an overview of the architecture and security properties, see :doc:`Welcome to Tahoe LAFS! <../about-tahoe>`
Tahoe-LAFS can be installed and used on any of the following operating systems.
.. _Tahoe-LAFS: https://tahoe-lafs.org
Microsoft Windows
=================
To install Tahoe-LAFS on Windows:
1. Make sure you have Powershell installed. See `PowerShell installation <https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-7.1>`_.
2. Install the latest version of Python 3. Download the .exe file at the `python website <https://www.python.org/downloads/>`_.
3. Open the installer by double-clicking it. Select the **Add Python to PATH** check-box, then click **Install Now**.
4. Start PowerShell and enter the following command to verify python installation::
python --version
5. Enter the following command to install Tahoe-LAFS::
pip install tahoe-lafs
6. Verify installation by checking for the version::
tahoe --version
If you want to hack on Tahoe's source code, you can install Tahoe in a ``virtualenv`` on your Windows Machine. To learn more, see :doc:`install-on-windows`.
Linux, BSD, or MacOS
====================
Tahoe-LAFS can be installed on MacOS, many Linux and BSD distributions. If you are using Ubuntu or Debian, run the following command to install Tahoe-LAFS::
apt-get install tahoe-lafs
If you are working on MacOS or a Linux distribution which does not have Tahoe-LAFS packages, you can build it yourself:
1. Make sure the following are installed:
* **Python 3's latest version**: Check for the version by running ``python --version``.
* **pip**: Most python installations already include `pip`. However, if your installation does not, see `pip installation <https://pip.pypa.io/en/stable/installing/>`_.
2. Install Tahoe-LAFS using pip::
pip install tahoe-lafs
3. Verify installation by checking for the version::
tahoe --version
If you are looking to hack on the source code or run pre-release code, we recommend you install Tahoe-LAFS on a `virtualenv` instance. To learn more, see :doc:`install-on-linux`.
You can always write to the `tahoe-dev mailing list <https://lists.tahoe-lafs.org/mailman/listinfo/tahoe-dev>`_ or chat on the `Libera.chat IRC <irc://irc.libera.chat/%23tahoe-lafs>`_ if you are not able to get Tahoe-LAFS up and running on your deployment.

View File

@ -1,220 +1,21 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
SOURCES = subtree1.svg lease-tradeoffs.svg
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
PNGS = $(patsubst %.svg,%.png,$(SOURCES))
EPSS = $(patsubst %.svg,%.eps,$(SOURCES))
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: images-png images-eps
all: $(PNGS) $(EPSS)
images-png: $(PNGS)
images-eps: $(EPSS)
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
%.png: %.svg
inkscape -b white -d 90 -D --export-png $@ $<
%.eps: %.svg
inkscape --export-eps $@ $<
%.html: %.rst
rst2html.py $< $@
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Tahoe-LAFS.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Tahoe-LAFS.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Tahoe-LAFS"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Tahoe-LAFS"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
.PHONY: livehtml
livehtml:
sphinx-autobuild -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
rm -f *.png *.eps

View File

@ -1,21 +0,0 @@
SOURCES = subtree1.svg lease-tradeoffs.svg
PNGS = $(patsubst %.svg,%.png,$(SOURCES))
EPSS = $(patsubst %.svg,%.eps,$(SOURCES))
.PHONY: images-png images-eps
all: $(PNGS) $(EPSS)
images-png: $(PNGS)
images-eps: $(EPSS)
%.png: %.svg
inkscape -b white -d 90 -D --export-png $@ $<
%.eps: %.svg
inkscape --export-eps $@ $<
%.html: %.rst
rst2html.py $< $@
clean:
rm -f *.png *.eps

View File

@ -1,30 +0,0 @@
If you are reading Tahoe-LAFS documentation
-------------------------------------------
If you are reading Tahoe-LAFS documentation at a code hosting site or
from a checked-out source tree, the preferred place to view the docs
is http://tahoe-lafs.readthedocs.io/en/latest/. Code-hosting sites do
not render cross-document links or images correctly.
If you are writing Tahoe-LAFS documentation
-------------------------------------------
To edit Tahoe-LAFS docs, you will need a checked-out source tree. You
can edit the `.rst` files in this directory using a text editor, and
then generate HTML output using Sphinx, a program that can produce its
output in HTML and other formats.
Files with `.rst` extension use reStructuredText markup format, which
is the format Sphinx natively handles. To learn more about Sphinx, and
for a friendly primer on reStructuredText, please see Sphinx project's
documentation, available at:
https://www.sphinx-doc.org/
If you have `tox` installed, you can run `tox -e docs` and then open
the resulting docs/_build/html/index.html in your web browser.
Note that Sphinx can also process Python docstrings to generate API
documentation. Tahoe-LAFS currently does not use Sphinx for this
purpose.

0
docs/_static/.empty vendored
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

View File

@ -1,33 +1,11 @@
.. -*- coding: utf-8-with-signature -*-
**********************
Welcome to Tahoe-LAFS!
**********************
What is Tahoe-LAFS?
===================
======================
Welcome to Tahoe-LAFS_, the first decentralized storage system with
*provider-independent security*.
Tahoe-LAFS is a system that helps you to store files. You run a client
program on your computer, which talks to one or more storage servers on other
computers. When you tell your client to store a file, it will encrypt that
file, encode it into multiple pieces, then spread those pieces out among
multiple servers. The pieces are all encrypted and protected against
modifications. Later, when you ask your client to retrieve the file, it will
find the necessary pieces, make sure they haven't been corrupted, reassemble
them, and decrypt the result.
The client creates more pieces (or "shares") than it will eventually need, so
even if some of the servers fail, you can still get your data back. Corrupt
shares are detected and ignored, so the system can tolerate server-side
hard-drive errors. All files are encrypted (with a unique key) before
uploading, so even a malicious server operator cannot read your data. The
only thing you ask of the servers is that they can (usually) provide the
shares when you ask for them: you aren't relying upon them for
confidentiality, integrity, or absolute availability.
.. _Tahoe-LAFS: https://tahoe-lafs.org
What is "provider-independent security"?
@ -67,12 +45,12 @@ Here's how it works:
A "storage grid" is made up of a number of storage servers. A storage server
has direct attached storage (typically one or more hard disks). A "gateway"
communicates with storage nodes, and uses them to provide access to the
grid over protocols such as HTTP(S) and SFTP.
filesystem over protocols such as HTTP(S), SFTP or FTP.
Note that you can find "client" used to refer to gateway nodes (which act as
a client to storage servers), and also to processes or programs connecting to
a gateway node and performing operations on the grid -- for example, a CLI
command, Web browser, or SFTP client.
command, Web browser, SFTP client, or FTP client.
Users do not rely on storage servers to provide *confidentiality* nor
*integrity* for their data -- instead all of the data is encrypted and
@ -94,8 +72,8 @@ An alternate deployment mode is that the gateway runs on a remote machine and
the user connects to it over HTTPS or SFTP. This means that the operator of
the gateway can view and modify the user's data (the user *relies on* the
gateway for confidentiality and integrity), but the advantage is that the
user can access the Tahoe-LAFS grid with a client that doesn't have the
gateway software installed, such as an Internet kiosk or cell phone.
user can access the filesystem with a client that doesn't have the gateway
software installed, such as an Internet kiosk or cell phone.
Access Control
==============
@ -127,17 +105,13 @@ For more technical detail, please see the `the doc page`_ on the Wiki.
Get Started
===========
To use Tahoe-LAFS, please see :doc:`Installing Tahoe-LAFS <../Installation/install-tahoe>`.
To use Tahoe-LAFS, please see quickstart.rst_.
.. _quickstart.rst: quickstart.rst
License
=======
Tahoe-LAFS is an open-source project; please see the `top-level README`_ for
details.
..
this is really ../README.rst, but it's not included in the Sphinx build so
we can't link to it normally
.. _top-level README: https://github.com/tahoe-lafs/tahoe-lafs/blob/master/README.rst
Tahoe-LAFS is an open-source project; please see README.rst_ for details.
.. _README.rst: ../README.rst

View File

@ -1,78 +0,0 @@
========================
Storage Server Donations
========================
The following is a configuration convention which allows users to anonymously support the operators of storage servers.
Donations are made using `Zcash shielded transactions`_ to limit the amount of personal information incidentally conveyed.
Sending Donations
=================
To support a storage server following this convention, you need several things:
* a Zcash wallet capable of sending shielded transactions
(at least until Zcash 1.1.1 this requires a Zcash full node)
* a shielded address with sufficient balance
* a running Tahoe-LAFS client node which knows about the recipient storage server
For additional protection, you may also wish to operate your Zcash wallet and full node using Tor.
Find Zcash Shielded Address
---------------------------
To find an address at which a storage server operator wishes to receive donations,
launch the Tahoe-LAFS web UI::
$ tahoe webopen
Inspect the page for the storage server area.
This will have a heading like *Connected to N of M known storage servers*.
Each storage server in this section will have a nickname.
A storage server with a nickname beginning with ``zcash:`` is signaling it accepts Zcash donations.
Copy the full address following the ``zcash:`` prefix and save it for the next step.
This is the donation address.
Donation addresses beginning with ``z`` are shielded.
It is recommended that all donations be sent from and to shielded addresses.
Send the Donation
-----------------
First, select a donation amount.
Next, use a Zcash wallet to send the selected amount to the donation address.
Using the Zcash cli wallet, this can be done with commands like::
$ DONATION_ADDRESS="..."
$ AMOUNT="..."
$ YOUR_ADDRESS="..."
$ zcash-cli z_sendmany $YOUR_ADDRESS "[{\"address\": \"$DONATION_ADDRESS\", \"amount\": $AMOUNT}]"
Remember that you must also have funds to pay the transaction fee
(which defaults to 0.0001 ZEC in mid-2018).
Receiving Donations
===================
To receive donations from users following this convention, you need the following:
* a Zcash shielded address
Configuring Tahoe-LAFS
----------------------
The Zcash shielded address is placed in the storage server's ``nickname`` field.
Edit ``tahoe.cfg`` and edit the ``nickname`` field in the ``node`` section like so::
[node]
nickname = zcash:zcABCDEF....
Then restart the storage server.
Further Reading
===============
To acquaint yourself with the security and privacy properties of Zcash,
refer to the `Zcash documentation`_.
.. _Zcash shielded transactions: https://z.cash/support/security/privacy-security-recommendations.html#transaction
.. _Zcash documentation: http://zcash.readthedocs.io/en/latest/

View File

@ -1,437 +0,0 @@
.. -*- coding: utf-8-with-signature; fill-column: 77 -*-
======================================================
Using Tahoe-LAFS with an anonymizing network: Tor, I2P
======================================================
#. `Overview`_
#. `Use cases`_
#. `Software Dependencies`_
#. `Tor`_
#. `I2P`_
#. `Connection configuration`_
#. `Anonymity configuration`_
#. `Client anonymity`_
#. `Server anonymity, manual configuration`_
#. `Server anonymity, automatic configuration`_
#. `Performance and security issues`_
Overview
========
Tor is an anonymizing network used to help hide the identity of internet
clients and servers. Please see the Tor Project's website for more information:
https://www.torproject.org/
I2P is a decentralized anonymizing network that focuses on end-to-end anonymity
between clients and servers. Please see the I2P website for more information:
https://geti2p.net/
Use cases
=========
There are three potential use-cases for Tahoe-LAFS on the client side:
1. User wishes to always use an anonymizing network (Tor, I2P) to protect
their anonymity when connecting to Tahoe-LAFS storage grids (whether or
not the storage servers are anonymous).
2. User does not care to protect their anonymity but they wish to connect to
Tahoe-LAFS storage servers which are accessible only via Tor Hidden Services or I2P.
* Tor is only used if a server connection hint uses ``tor:``. These hints
generally have a ``.onion`` address.
* I2P is only used if a server connection hint uses ``i2p:``. These hints
generally have a ``.i2p`` address.
3. User does not care to protect their anonymity or to connect to anonymous
storage servers. This document is not useful to you... so stop reading.
For Tahoe-LAFS storage servers there are three use-cases:
1. The operator wishes to protect their anonymity by making their Tahoe
server accessible only over I2P, via Tor Hidden Services, or both.
2. The operator does not *require* anonymity for the storage server, but they
want it to be available over both publicly routed TCP/IP and through an
anonymizing network (I2P, Tor Hidden Services). One possible reason to do
this is because being reachable through an anonymizing network is a
convenient way to bypass NAT or firewall that prevents publicly routed
TCP/IP connections to your server (for clients capable of connecting to
such servers). Another is that making your storage server reachable
through an anonymizing network can provide better protection for your
clients who themselves use that anonymizing network to protect their
anonymity.
3. Storage server operator does not care to protect their own anonymity nor
to help the clients protect theirs. Stop reading this document and run
your Tahoe-LAFS storage server using publicly routed TCP/IP.
See this Tor Project page for more information about Tor Hidden Services:
https://www.torproject.org/docs/hidden-services.html.en
See this I2P Project page for more information about I2P:
https://geti2p.net/en/about/intro
Software Dependencies
=====================
Tor
---
Clients who wish to connect to Tor-based servers must install the following.
* Tor (tor) must be installed. See here:
https://www.torproject.org/docs/installguide.html.en . On Debian/Ubuntu,
use ``apt-get install tor``. You can also install and run the Tor Browser
Bundle.
* Tahoe-LAFS must be installed with the ``[tor]`` "extra" enabled. This will
install ``txtorcon`` ::
pip install tahoe-lafs[tor]
Manually-configured Tor-based servers must install Tor, but do not need
``txtorcon`` or the ``[tor]`` extra. Automatic configuration, when
implemented, will need these, just like clients.
I2P
---
Clients who wish to connect to I2P-based servers must install the following.
As with Tor, manually-configured I2P-based servers need the I2P daemon, but
no special Tahoe-side supporting libraries.
* I2P must be installed. See here:
https://geti2p.net/en/download
* The SAM API must be enabled.
* Start I2P.
* Visit http://127.0.0.1:7657/configclients in your browser.
* Under "Client Configuration", check the "Run at Startup?" box for "SAM
application bridge".
* Click "Save Client Configuration".
* Click the "Start" control for "SAM application bridge", or restart I2P.
* Tahoe-LAFS must be installed with the ``[i2p]`` extra enabled, to get
``txi2p`` ::
pip install tahoe-lafs[i2p]
Both Tor and I2P
----------------
Clients who wish to connect to both Tor- and I2P-based servers must install
all of the above. In particular, Tahoe-LAFS must be installed with both
extras enabled::
pip install tahoe-lafs[tor,i2p]
Connection configuration
========================
See :ref:`Connection Management` for a description of the ``[tor]`` and
``[i2p]`` sections of ``tahoe.cfg``. These control how the Tahoe client will
connect to a Tor/I2P daemon, and thus make connections to Tor/I2P -based
servers.
The ``[tor]`` and ``[i2p]`` sections only need to be modified to use unusual
configurations, or to enable automatic server setup.
The default configuration will attempt to contact a local Tor/I2P daemon
listening on the usual ports (9050/9150 for Tor, 7656 for I2P). As long as
there is a daemon running on the local host, and the necessary support
libraries were installed, clients will be able to use Tor-based servers
without any special configuration.
However note that this default configuration does not improve the client's
anonymity: normal TCP connections will still be made to any server that
offers a regular address (it fulfills the second client use case above, not
the third). To protect their anonymity, users must configure the
``[connections]`` section as follows::
[connections]
tcp = tor
With this in place, the client will use Tor (instead of an
IP-address -revealing direct connection) to reach TCP-based servers.
Anonymity configuration
=======================
Tahoe-LAFS provides a configuration "safety flag" for explicitly stating
whether or not IP-address privacy is required for a node::
[node]
reveal-IP-address = (boolean, optional)
When ``reveal-IP-address = False``, Tahoe-LAFS will refuse to start if any of
the configuration options in ``tahoe.cfg`` would reveal the node's network
location:
* ``[connections] tcp = tor`` is required: otherwise the client would make
direct connections to the Introducer, or any TCP-based servers it learns
from the Introducer, revealing its IP address to those servers and a
network eavesdropper. With this in place, Tahoe-LAFS will only make
outgoing connections through a supported anonymizing network.
* ``tub.location`` must either be disabled, or contain safe values. This
value is advertised to other nodes via the Introducer: it is how a server
advertises it's location so clients can connect to it. In private mode, it
is an error to include a ``tcp:`` hint in ``tub.location``. Private mode
rejects the default value of ``tub.location`` (when the key is missing
entirely), which is ``AUTO``, which uses ``ifconfig`` to guess the node's
external IP address, which would reveal it to the server and other clients.
This option is **critical** to preserving the client's anonymity (client
use-case 3 from `Use cases`_, above). It is also necessary to preserve a
server's anonymity (server use-case 3).
This flag can be set (to False) by providing the ``--hide-ip`` argument to
the ``create-node``, ``create-client``, or ``create-introducer`` commands.
Note that the default value of ``reveal-IP-address`` is True, because
unfortunately hiding the node's IP address requires additional software to be
installed (as described above), and reduces performance.
Client anonymity
----------------
To configure a client node for anonymity, ``tahoe.cfg`` **must** contain the
following configuration flags::
[node]
reveal-IP-address = False
tub.port = disabled
tub.location = disabled
Once the Tahoe-LAFS node has been restarted, it can be used anonymously (client
use-case 3).
Server anonymity, manual configuration
--------------------------------------
To configure a server node to listen on an anonymizing network, we must first
configure Tor to run an "Onion Service", and route inbound connections to the
local Tahoe port. Then we configure Tahoe to advertise the ``.onion`` address
to clients. We also configure Tahoe to not make direct TCP connections.
* Decide on a local listening port number, named PORT. This can be any unused
port from about 1024 up to 65535 (depending upon the host's kernel/network
config). We will tell Tahoe to listen on this port, and we'll tell Tor to
route inbound connections to it.
* Decide on an external port number, named VIRTPORT. This will be used in the
advertised location, and revealed to clients. It can be any number from 1
to 65535. It can be the same as PORT, if you like.
* Decide on a "hidden service directory", usually in ``/var/lib/tor/NAME``.
We'll be asking Tor to save the onion-service state here, and Tor will
write the ``.onion`` address here after it is generated.
Then, do the following:
* Create the Tahoe server node (with ``tahoe create-node``), but do **not**
launch it yet.
* Edit the Tor config file (typically in ``/etc/tor/torrc``). We need to add
a section to define the hidden service. If our PORT is 2000, VIRTPORT is
3000, and we're using ``/var/lib/tor/tahoe`` as the hidden service
directory, the section should look like::
HiddenServiceDir /var/lib/tor/tahoe
HiddenServicePort 3000 127.0.0.1:2000
* Restart Tor, with ``systemctl restart tor``. Wait a few seconds.
* Read the ``hostname`` file in the hidden service directory (e.g.
``/var/lib/tor/tahoe/hostname``). This will be a ``.onion`` address, like
``u33m4y7klhz3b.onion``. Call this ONION.
* Edit ``tahoe.cfg`` to set ``tub.port`` to use
``tcp:PORT:interface=127.0.0.1``, and ``tub.location`` to use
``tor:ONION.onion:VIRTPORT``. Using the examples above, this would be::
[node]
reveal-IP-address = false
tub.port = tcp:2000:interface=127.0.0.1
tub.location = tor:u33m4y7klhz3b.onion:3000
[connections]
tcp = tor
* Launch the Tahoe server with ``tahoe run $NODEDIR``
The ``tub.port`` section will cause the Tahoe server to listen on PORT, but
bind the listening socket to the loopback interface, which is not reachable
from the outside world (but *is* reachable by the local Tor daemon). Then the
``tcp = tor`` section causes Tahoe to use Tor when connecting to the
Introducer, hiding it's IP address. The node will then announce itself to all
clients using ``tub.location``, so clients will know that they must use Tor
to reach this server (and not revealing it's IP address through the
announcement). When clients connect to the onion address, their packets will
flow through the anonymizing network and eventually land on the local Tor
daemon, which will then make a connection to PORT on localhost, which is
where Tahoe is listening for connections.
Follow a similar process to build a Tahoe server that listens on I2P. The
same process can be used to listen on both Tor and I2P (``tub.location =
tor:ONION.onion:VIRTPORT,i2p:ADDR.i2p``). It can also listen on both Tor and
plain TCP (use-case 2), with ``tub.port = tcp:PORT``, ``tub.location =
tcp:HOST:PORT,tor:ONION.onion:VIRTPORT``, and ``anonymous = false`` (and omit
the ``tcp = tor`` setting, as the address is already being broadcast through
the location announcement).
Server anonymity, automatic configuration
-----------------------------------------
To configure a server node to listen on an anonymizing network, create the
node with the ``--listen=tor`` option. This requires a Tor configuration that
either launches a new Tor daemon, or has access to the Tor control port (and
enough authority to create a new onion service). On Debian/Ubuntu systems, do
``apt install tor``, add yourself to the control group with ``adduser
YOURUSERNAME debian-tor``, and then logout and log back in: if the ``groups``
command includes ``debian-tor`` in the output, you should have permission to
use the unix-domain control port at ``/var/run/tor/control``.
This option will set ``reveal-IP-address = False`` and ``[connections] tcp =
tor``. It will allocate the necessary ports, instruct Tor to create the onion
service (saving the private key somewhere inside NODEDIR/private/), obtain
the ``.onion`` address, and populate ``tub.port`` and ``tub.location``
correctly.
Performance and security issues
===============================
If you are running a server which does not itself need to be
anonymous, should you make it reachable via an anonymizing network or
not? Or should you make it reachable *both* via an anonymizing network
and as a publicly traceable TCP/IP server?
There are several trade-offs effected by this decision.
NAT/Firewall penetration
------------------------
Making a server be reachable via Tor or I2P makes it reachable (by
Tor/I2P-capable clients) even if there are NATs or firewalls preventing
direct TCP/IP connections to the server.
Anonymity
---------
Making a Tahoe-LAFS server accessible *only* via Tor or I2P can be used to
guarantee that the Tahoe-LAFS clients use Tor or I2P to connect
(specifically, the server should only advertise Tor/I2P addresses in the
``tub.location`` config key). This prevents misconfigured clients from
accidentally de-anonymizing themselves by connecting to your server through
the traceable Internet.
Clearly, a server which is available as both a Tor/I2P service *and* a
regular TCP address is not itself anonymous: the .onion address and the real
IP address of the server are easily linkable.
Also, interaction, through Tor, with a Tor Hidden Service may be more
protected from network traffic analysis than interaction, through Tor,
with a publicly traceable TCP/IP server.
**XXX is there a document maintained by Tor developers which substantiates or refutes this belief?
If so we need to link to it. If not, then maybe we should explain more here why we think this?**
Linkability
-----------
As of 1.12.0, the node uses a single persistent Tub key for outbound
connections to the Introducer, and inbound connections to the Storage Server
(and Helper). For clients, a new Tub key is created for each storage server
we learn about, and these keys are *not* persisted (so they will change each
time the client reboots).
Clients traversing directories (from rootcap to subdirectory to filecap) are
likely to request the same storage-indices (SIs) in the same order each time.
A client connected to multiple servers will ask them all for the same SI at
about the same time. And two clients which are sharing files or directories
will visit the same SIs (at various times).
As a result, the following things are linkable, even with ``reveal-IP-address
= false``:
* Storage servers can link recognize multiple connections from the same
not-yet-rebooted client. (Note that the upcoming Accounting feature may
cause clients to present a persistent client-side public key when
connecting, which will be a much stronger linkage).
* Storage servers can probably deduce which client is accessing data, by
looking at the SIs being requested. Multiple servers can collude to
determine that the same client is talking to all of them, even though the
TubIDs are different for each connection.
* Storage servers can deduce when two different clients are sharing data.
* The Introducer could deliver different server information to each
subscribed client, to partition clients into distinct sets according to
which server connections they eventually make. For client+server nodes, it
can also correlate the server announcement with the deduced client
identity.
Performance
-----------
A client connecting to a publicly traceable Tahoe-LAFS server through Tor
incurs substantially higher latency and sometimes worse throughput than the
same client connecting to the same server over a normal traceable TCP/IP
connection. When the server is on a Tor Hidden Service, it incurs even more
latency, and possibly even worse throughput.
Connecting to Tahoe-LAFS servers which are I2P servers incurs higher latency
and worse throughput too.
Positive and negative effects on other Tor users
------------------------------------------------
Sending your Tahoe-LAFS traffic over Tor adds cover traffic for other
Tor users who are also transmitting bulk data. So that is good for
them -- increasing their anonymity.
However, it makes the performance of other Tor users' interactive
sessions -- e.g. ssh sessions -- much worse. This is because Tor
doesn't currently have any prioritization or quality-of-service
features, so someone else's ssh keystrokes may have to wait in line
while your bulk file contents get transmitted. The added delay might
make other people's interactive sessions unusable.
Both of these effects are doubled if you upload or download files to a
Tor Hidden Service, as compared to if you upload or download files
over Tor to a publicly traceable TCP/IP server.
Positive and negative effects on other I2P users
------------------------------------------------
Sending your Tahoe-LAFS traffic over I2P adds cover traffic for other I2P users
who are also transmitting data. So that is good for them -- increasing their
anonymity. It will not directly impair the performance of other I2P users'
interactive sessions, because the I2P network has several congestion control and
quality-of-service features, such as prioritizing smaller packets.
However, if many users are sending Tahoe-LAFS traffic over I2P, and do not have
their I2P routers configured to participate in much traffic, then the I2P
network as a whole will suffer degradation. Each Tahoe-LAFS router using I2P has
their own anonymizing tunnels that their data is sent through. On average, one
Tahoe-LAFS node requires 12 other I2P routers to participate in their tunnels.
It is therefore important that your I2P router is sharing bandwidth with other
routers, so that you can give back as you use I2P. This will never impair the
performance of your Tahoe-LAFS node, because your I2P router will always
prioritize your own traffic.

View File

@ -10,7 +10,7 @@ Tahoe-LAFS Architecture
4. `Capabilities`_
5. `Server Selection`_
6. `Swarming Download, Trickling Upload`_
7. `The File Store Layer`_
7. `The Filesystem Layer`_
8. `Leases, Refreshing, Garbage Collection`_
9. `File Repairer`_
10. `Security`_
@ -22,7 +22,7 @@ Overview
(See the `docs/specifications directory`_ for more details.)
There are three layers: the key-value store, the file store, and the
There are three layers: the key-value store, the filesystem, and the
application.
The lowest layer is the key-value store. The keys are "capabilities" -- short
@ -33,21 +33,21 @@ values, but there may be performance issues with extremely large values (just
due to the limitation of network bandwidth). In practice, values as small as
a few bytes and as large as tens of gigabytes are in common use.
The middle layer is the decentralized file store: a directed graph in which
The middle layer is the decentralized filesystem: a directed graph in which
the intermediate nodes are directories and the leaf nodes are files. The leaf
nodes contain only the data -- they contain no metadata other than the length
in bytes. The edges leading to leaf nodes have metadata attached to them
about the file they point to. Therefore, the same file may be associated with
different metadata if it is referred to through different edges.
The top layer consists of the applications using the file store.
The top layer consists of the applications using the filesystem.
Allmydata.com used it for a backup service: the application periodically
copies files from the local disk onto the decentralized file store. We later
copies files from the local disk onto the decentralized filesystem. We later
provide read-only access to those files, allowing users to recover them.
There are several other applications built on top of the Tahoe-LAFS
file store (see the RelatedProjects_ page of the wiki for a list).
filesystem (see the RelatedProjects_ page of the wiki for a list).
.. _docs/specifications directory: https://github.com/tahoe-lafs/tahoe-lafs/tree/master/docs/specifications
.. _docs/specifications directory: specifications
.. _RelatedProjects: https://tahoe-lafs.org/trac/tahoe-lafs/wiki/RelatedProjects
The Key-Value Store
@ -57,18 +57,6 @@ The key-value store is implemented by a grid of Tahoe-LAFS storage servers --
user-space processes. Tahoe-LAFS storage clients communicate with the storage
servers over TCP.
There are two supported protocols:
* Foolscap, the only supported protocol in release before v1.19.
* HTTPS, new in v1.19.
By default HTTPS is enabled. When HTTPS is enabled on the server, the server
transparently listens for both Foolscap and HTTPS on the same port. When it is
disabled, the server only supports Foolscap. Clients can use either; by default
they will use HTTPS when possible, falling back to I2p, but when configured
appropriately they will only use Foolscap. At this time the only limitations of
HTTPS is that I2P is not supported, so any usage of I2P only uses Foolscap.
Storage servers hold data in the form of "shares". Shares are encoded pieces
of files. There are a configurable number of shares for each file, 10 by
default. Normally, each share is stored on a separate server, but in some
@ -110,7 +98,7 @@ subset are needed to reconstruct the segment (3 out of 10, with the default
settings).
It sends one block from each segment to a given server. The set of blocks on
a given server constitutes a "share". Therefore a subset of the shares (3 out
a given server constitutes a "share". Therefore a subset f the shares (3 out
of 10, by default) are needed to reconstruct the file.
A hash of the encryption key is used to form the "storage index", which is
@ -169,7 +157,7 @@ The "key-value store" layer doesn't include human-meaningful names.
Capabilities sit on the "global+secure" edge of `Zooko's Triangle`_. They are
self-authenticating, meaning that nobody can trick you into accepting a file
that doesn't match the capability you used to refer to that file. The
file store layer (described below) adds human-meaningful names atop the
filesystem layer (described below) adds human-meaningful names atop the
key-value layer.
.. _`Zooko's Triangle`: https://en.wikipedia.org/wiki/Zooko%27s_triangle
@ -328,18 +316,20 @@ commercially-run grid for which all of the storage servers are in a colo
facility with high interconnect bandwidth. In this case, the helper is placed
in the same facility, so the helper-to-storage-server bandwidth is huge.
See :doc:`helper` for details about the upload helper.
See helper.rst_ for details about the upload helper.
.. _helper.rst: helper.rst
The File Store Layer
The Filesystem Layer
====================
The "file store" layer is responsible for mapping human-meaningful pathnames
The "filesystem" layer is responsible for mapping human-meaningful pathnames
(directories and filenames) to pieces of data. The actual bytes inside these
files are referenced by capability, but the file store layer is where the
files are referenced by capability, but the filesystem layer is where the
directory names, file names, and metadata are kept.
The file store layer is a graph of directories. Each directory contains a
The filesystem layer is a graph of directories. Each directory contains a
table of named children. These children are either other directories or
files. All children are referenced by their capability.
@ -365,11 +355,11 @@ that are globally visible.
Leases, Refreshing, Garbage Collection
======================================
When a file or directory in the file store is no longer referenced, the space
that its shares occupied on each storage server can be freed, making room for
other shares. Tahoe-LAFS uses a garbage collection ("GC") mechanism to
implement this space-reclamation process. Each share has one or more
"leases", which are managed by clients who want the file/directory to be
When a file or directory in the virtual filesystem is no longer referenced,
the space that its shares occupied on each storage server can be freed,
making room for other shares. Tahoe-LAFS uses a garbage collection ("GC")
mechanism to implement this space-reclamation process. Each share has one or
more "leases", which are managed by clients who want the file/directory to be
retained. The storage server accepts each share for a pre-defined period of
time, and is allowed to delete the share if all of the leases are cancelled
or allowed to expire.
@ -380,8 +370,11 @@ clients are responsible for renewing their leases on a periodic basis at
least frequently enough to prevent any of the leases from expiring before the
next renewal pass.
See :doc:`garbage-collection` for further information, and for how to
configure garbage collection.
See garbage-collection.rst_ for further information, and for how to configure
garbage collection.
.. _garbage-collection.rst: garbage-collection.rst
File Repairer
=============
@ -390,7 +383,7 @@ Shares may go away because the storage server hosting them has suffered a
failure: either temporary downtime (affecting availability of the file), or a
permanent data loss (affecting the preservation of the file). Hard drives
crash, power supplies explode, coffee spills, and asteroids strike. The goal
of a robust distributed file store is to survive these setbacks.
of a robust distributed filesystem is to survive these setbacks.
To work against this slow, continual loss of shares, a File Checker is used
to periodically count the number of shares still available for any given
@ -498,7 +491,12 @@ validate-capability, but not vice versa). These capabilities may be expressly
delegated (irrevocably) by simply transferring the relevant secrets.
The application layer can provide whatever access model is desired, built on
top of this capability access model.
top of this capability access model. The first big user of this system so far
is allmydata.com. The allmydata.com access model currently works like a
normal web site, using username and password to give a user access to her
"virtual drive". In addition, allmydata.com users can share individual files
(using a file sharing interface built on top of the immutable file read
capabilities).
Reliability

View File

@ -1,35 +0,0 @@
In December 2018, the Tahoe-LAFS project engaged Aspiration[1], a US 501(c)3
nonprofit technology organization, as a "fiscal sponsor"[2]. A portion of the
project's Bitcoin will be given to Aspiration, from which they can pay
developers and contractors to work on the Tahoe codebase. Aspiration will
handle the payroll, taxes, accounting, project management, and oversight, and
is compensated by an 8% management fee. This provides the tax-withholding
structure to use our project's BTC for significant development.
We're using 25% of our ~369 BTC for this initial stage of the project,
which will give us about $300K-$350K of development work, spread out
over the 2019 calendar year. While it would have been nice to make this
happen a year ago (given the recent decline of the BTC price), we think
this is a reasonable value, and we're excited to finally get to use this
surprise windfall to improve the codebase.
Our initial set of projects to fund, drafted by Liz Steininger of Least
Authority and approved by Zooko and Brian, looks like this:
* porting Tahoe and dependent libraries to Python 3
* improving grid operation/management tools
* community outreach, UI/UX improvements, documentation
* adding new community-requested features, improving garbage collection
* possibly run another summit
If this goes well (and especially if the BTC price recovers), we'll
probably do more next year.
As usual, the transfer amounts and addresses will be logged in
"donations.rst" and "expenses.rst" in the docs/ directory.
Many thanks to Gunner and Josh Black of Aspiration, and Liz Steininger
of Least Authority, for making this possible.
[1]: https://aspirationtech.org/
[2]: https://aspirationtech.org/services/openprojects

View File

@ -64,9 +64,3 @@ Peter Secor
Shawn Willden
Terrell Russell
Jean-Paul Calderone
meejah
Sajith Sasidharan

View File

@ -4,7 +4,9 @@
Things To Be Careful About As We Venture Boldly Forth
=======================================================
See also :doc:`known_issues`.
See also known_issues.rst_.
.. _known_issues.rst: known_issues.rst
Timing Attacks
==============

View File

@ -1,47 +0,0 @@
import psutil
import filelock
def can_spawn_tahoe(pidfile):
"""
Determine if we can spawn a Tahoe-LAFS for the given pidfile. That
pidfile may be deleted if it is stale.
:param pathlib.Path pidfile: the file to check, that is the Path
to "running.process" in a Tahoe-LAFS configuration directory
:returns bool: True if we can spawn `tahoe run` here
"""
lockpath = pidfile.parent / (pidfile.name + ".lock")
with filelock.FileLock(lockpath):
try:
with pidfile.open("r") as f:
pid, create_time = f.read().strip().split(" ", 1)
except FileNotFoundError:
return True
# somewhat interesting: we have a pidfile
pid = int(pid)
create_time = float(create_time)
try:
proc = psutil.Process(pid)
# most interesting case: there _is_ a process running at the
# recorded PID -- but did it just happen to get that PID, or
# is it the very same one that wrote the file?
if create_time == proc.create_time():
# _not_ stale! another intance is still running against
# this configuration
return False
except psutil.NoSuchProcess:
pass
# the file is stale
pidfile.unlink()
return True
from pathlib import Path
print("can spawn?", can_spawn_tahoe(Path("running.process")))

View File

@ -1,280 +0,0 @@
# -*- coding: utf-8 -*-
#
# Tahoe-LAFS documentation build configuration file, created by
# sphinx-quickstart on Sat Mar 26 11:20:25 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['recommonmark', 'sphinx_rtd_theme']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = ['.rst', '.md']
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Tahoe-LAFS'
copyright = u'2016, The Tahoe-LAFS Developers'
author = u'The Tahoe-LAFS Developers'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'1.x'
# The full version, including alpha/beta/rc tags.
release = u'1.x'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = "en"
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'Tahoe-LAFSdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'Tahoe-LAFS.tex', u'Tahoe-LAFS Documentation',
u'The Tahoe-LAFS Developers', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'tahoe-lafs', u'Tahoe-LAFS Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'Tahoe-LAFS', u'Tahoe-LAFS Documentation',
author, 'Tahoe-LAFS', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

View File

@ -4,19 +4,16 @@
Configuring a Tahoe-LAFS node
=============================
#. `Node Types`_
#. `Overall Node Configuration`_
#. `Connection Management`_
#. `Client Configuration`_
#. `Storage Server Configuration`_
#. `Storage Server Plugin Configuration`_
#. `Frontend Configuration`_
#. `Running A Helper`_
#. `Running An Introducer`_
#. `Other Files in BASEDIR`_
#. `Static Server Definitions`_
#. `Other files`_
#. `Example`_
1. `Node Types`_
2. `Overall Node Configuration`_
3. `Client Configuration`_
4. `Storage Server Configuration`_
5. `Frontend Configuration`_
6. `Running A Helper`_
7. `Running An Introducer`_
8. `Other Files in BASEDIR`_
9. `Other files`_
10. `Example`_
A Tahoe-LAFS node is configured by writing to files in its base directory.
These files are read by the node when it starts, so each time you change
@ -29,9 +26,9 @@ This document contains a complete list of the config files that are examined
by the client node, as well as the state files that you'll observe in its
base directory.
The main file is named "``tahoe.cfg``", and is an "`.INI`_"-style configuration
file (parsed by the Python stdlib `ConfigParser`_ module: "``[name]``" section
markers, lines with "``key.subkey: value``", `RFC822-style`_
The main file is named "``tahoe.cfg``", and is an ".INI"-style configuration
file (parsed by the Python stdlib 'ConfigParser' module: "``[name]``" section
markers, lines with "``key.subkey: value``", rfc822-style
continuations). There are also other files containing information that does
not easily fit into this format. The "``tahoe create-node``" or "``tahoe
create-client``" command will create an initial ``tahoe.cfg`` file for
@ -52,35 +49,26 @@ The item descriptions below use the following types:
not specified, Tahoe-LAFS will attempt to bind the port specified on all
interfaces.
``endpoint specification string``
a Twisted Endpoint specification string, like "``tcp:80``" or
"``tcp:3456:interface=127.0.0.1``". These are replacing strports strings.
For a full description of the format, see `the Twisted Endpoints
documentation`_. Please note, if interface= is not specified, Tahoe-LAFS
will attempt to bind the port specified on all interfaces. Also note that
``tub.port`` only works with TCP endpoints right now.
``FURL string``
a Foolscap endpoint identifier, like
``pb://soklj4y7eok5c3xkmjeqpw@192.168.69.247:44801/eqpwqtzm``
.. _.INI: https://en.wikipedia.org/wiki/INI_file
.. _ConfigParser: https://docs.python.org/2/library/configparser.html
.. _RFC822-style: https://www.ietf.org/rfc/rfc0822
.. _the Twisted strports documentation: https://twistedmatrix.com/documents/current/api/twisted.application.strports.html
.. _the Twisted Endpoints documentation: http://twistedmatrix.com/documents/current/core/howto/endpoints.html#endpoint-types-included-with-twisted
Node Types
==========
A node can be a client/server or an introducer.
A node can be a client/server, an introducer, a statistics gatherer, or a
key generator.
Client/server nodes provide one or more of the following services:
* web-API service
* SFTP service
* FTP service
* drop-upload service
* helper service
* storage service.
@ -116,7 +104,7 @@ set the ``tub.location`` option described below.
This controls where the node's web server should listen, providing node
status and, if the node is a client/server, providing web-API service as
defined in :doc:`frontends/webapi`.
defined in webapi.rst_.
This file contains a Twisted "strports" specification such as "``3456``"
or "``tcp:3456:interface=127.0.0.1``". The "``tahoe create-node``" or
@ -140,126 +128,71 @@ set the ``tub.location`` option described below.
``http://127.0.0.1:3456/static/foo.html`` will serve the contents of
``BASEDIR/public_html/foo.html`` .
``tub.port = (endpoint specification strings or "disabled", optional)``
``tub.port = (integer, optional)``
This controls which port the node uses to accept Foolscap connections
from other nodes. It is parsed as a comma-separated list of Twisted
"server endpoint descriptor" strings, each of which is a value like
``tcp:12345`` and ``tcp:23456:interface=127.0.0.1``.
from other nodes. If not provided, the node will ask the kernel for any
available port. The port will be written to a separate file (named
``client.port`` or ``introducer.port``), so that subsequent runs will
re-use the same port.
To listen on multiple ports at once (e.g. both TCP-on-IPv4 and TCP-on-IPv6),
use something like ``tcp6:interface=2600\:3c01\:f03c\:91ff\:fe93\:d272:3456,tcp:interface=8.8.8.8:3456``.
Lists of endpoint descriptor strings like the following ``tcp:12345,tcp6:12345``
are known to not work because an ``Address already in use.`` error.
``tub.location = (string, optional)``
If any descriptor begins with ``listen:tor``, or ``listen:i2p``, the
corresponding tor/i2p Provider object will construct additional endpoints
for the Tub to listen on. This allows the ``[tor]`` or ``[i2p]`` sections
in ``tahoe.cfg`` to customize the endpoint; e.g. to add I2CP control
options. If you use ``listen:i2p``, you should not also have an
``i2p:..`` endpoint in ``tub.port``, as that would result in multiple
I2P-based listeners.
If ``tub.port`` is the string ``disabled``, the node will not listen at
all, and thus cannot accept connections from other nodes. If ``[storage]
enabled = true``, or ``[helper] enabled = true``, or the node is an
Introducer, then it is an error to have ``tub.port`` be empty. If
``tub.port`` is disabled, then ``tub.location`` must also be disabled,
and vice versa.
For backwards compatibility, if this contains a simple integer, it will
be used as a TCP port number, like ``tcp:%d`` (which will accept
connections on all interfaces). However ``tub.port`` cannot be ``0`` or
``tcp:0`` (older versions accepted this, but the node is no longer
willing to ask Twisted to allocate port numbers in this way). If
``tub.port`` is present, it may not be empty.
If the ``tub.port`` config key is not provided (e.g. ``tub.port`` appears
nowhere in the ``[node]`` section, or is commented out), the node will
look in ``BASEDIR/client.port`` (or ``BASEDIR/introducer.port``, for
introducers) for the descriptor that was used last time.
If neither ``tub.port`` nor the port file is available, the node will ask
the kernel to allocate any available port (the moral equivalent of
``tcp:0``). The allocated port number will be written into a descriptor
string in ``BASEDIR/client.port`` (or ``introducer.port``), so that
subsequent runs will re-use the same port.
``tub.location = (hint string or "disabled", optional)``
In addition to running as a client, each Tahoe-LAFS node can also run as
a server, listening for connections from other Tahoe-LAFS clients. The
node announces its location by publishing a "FURL" (a string with some
In addition to running as a client, each Tahoe-LAFS node also runs as a
server, listening for connections from other Tahoe-LAFS clients. The node
announces its location by publishing a "FURL" (a string with some
connection hints) to the Introducer. The string it publishes can be found
in ``BASEDIR/private/storage.furl`` . The ``tub.location`` configuration
controls what location is published in this announcement.
If your node is meant to run as a server, you should fill this in, using
a hostname or IP address that is reachable from your intended clients.
If ``tub.port`` is set to ``disabled``, then ``tub.location`` must also
be ``disabled``.
If you don't provide ``tub.location``, the node will try to figure out a
useful one by itself, by using tools like "``ifconfig``" to determine the
set of IP addresses on which it can be reached from nodes both near and
far. It will also include the TCP port number on which it is listening
(either the one specified by ``tub.port``, or whichever port was assigned
by the kernel when ``tub.port`` is left unspecified). However this
automatic address-detection is discouraged, and will probably be removed
from a future release. It will include the ``127.0.0.1`` "localhost"
address (which is only useful to clients running on the same computer),
and RFC1918 private-network addresses like ``10.*.*.*`` and
``192.168.*.*`` (which are only useful to clients on the local LAN). In
general, the automatically-detected IP addresses will only be useful if
the node has a public IP address, such as a VPS or colo-hosted server.
by the kernel when ``tub.port`` is left unspecified).
You will certainly need to set ``tub.location`` if your node lives behind
a firewall that is doing inbound port forwarding, or if you are using
other proxies such that the local IP address or port number is not the
same one that remote clients should use to connect. You might also want
to control this when using a Tor proxy to avoid revealing your actual IP
address through the Introducer announcement.
You might want to override this value if your node lives behind a
firewall that is doing inbound port forwarding, or if you are using other
proxies such that the local IP address or port number is not the same one
that remote clients should use to connect. You might also want to control
this when using a Tor proxy to avoid revealing your actual IP address
through the Introducer announcement.
If ``tub.location`` is specified, by default it entirely replaces the
automatically determined set of IP addresses. To include the automatically
determined addresses as well as the specified ones, include the uppercase
string "``AUTO``" in the list.
The value is a comma-separated string of method:host:port location hints,
like this::
The value is a comma-separated string of host:port location hints, like
this::
tcp:123.45.67.89:8098,tcp:tahoe.example.com:8098,tcp:127.0.0.1:8098
123.45.67.89:8098,tahoe.example.com:8098,127.0.0.1:8098
A few examples:
* Don't listen at all (client-only mode)::
* Emulate default behavior, assuming your host has IP address
123.45.67.89 and the kernel-allocated port number was 8098::
tub.port = disabled
tub.location = disabled
tub.port = 8098
tub.location = 123.45.67.89:8098,127.0.0.1:8098
* Use a DNS name so you can change the IP address more easily::
tub.port = tcp:8098
tub.location = tcp:tahoe.example.com:8098
* Run a node behind a firewall (which has an external IP address) that
has been configured to forward external port 7912 to our internal
node's port 8098::
tub.port = tcp:8098
tub.location = tcp:external-firewall.example.com:7912
* Emulate default behavior, assuming your host has public IP address of
123.45.67.89, and the kernel-allocated port number was 8098::
tub.port = tcp:8098
tub.location = tcp:123.45.67.89:8098,tcp:127.0.0.1:8098
tub.port = 8098
tub.location = tahoe.example.com:8098
* Use a DNS name but also include the default set of addresses::
tub.port = tcp:8098
tub.location = tcp:tahoe.example.com:8098,AUTO
tub.port = 8098
tub.location = tahoe.example.com:8098,AUTO
* Run a node behind a firewall (which has an external IP address) that
has been configured to forward port 7912 to our internal node's port
8098::
tub.port = 8098
tub.location = external-firewall.example.com:7912
* Run a node behind a Tor proxy (perhaps via ``torsocks``), in
client-only mode (i.e. we can make outbound connections, but other
@ -268,8 +201,8 @@ set the ``tub.location`` option described below.
reminder to human observers that this node cannot be reached. "Don't
call us.. we'll call you"::
tub.port = tcp:8098
tub.location = tcp:unreachable.example.org:0
tub.port = 8098
tub.location = unreachable.example.org:0
* Run a node behind a Tor proxy, and make the server available as a Tor
"hidden service". (This assumes that other clients are running their
@ -285,8 +218,10 @@ set the ``tub.location`` option described below.
``/var/lib/tor/hidden_services/tahoe/hostname``. Then set up your
``tahoe.cfg`` like::
tub.port = tcp:8098
tub.location = tor:ualhejtq2p7ohfbb.onion:29212
tub.port = 8098
tub.location = ualhejtq2p7ohfbb.onion:29212
Most users will not need to set ``tub.location``.
``log_gatherer.furl = (FURL, optional)``
@ -337,6 +272,19 @@ set the ``tub.location`` option described below.
.. _`#521`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/521
``ssh.port = (strports string, optional)``
``ssh.authorized_keys_file = (filename, optional)``
This enables an SSH-based interactive Python shell, which can be used to
inspect the internal state of the node, for debugging. To cause the node
to accept SSH connections on port 8022 from the same keys as the rest of
your account, use::
[tub]
ssh.port = 8022
ssh.authorized_keys_file = ~/.ssh/authorized_keys
``tempdir = (string, optional)``
This specifies a temporary directory for the web-API server to use, for
@ -349,228 +297,8 @@ set the ``tub.location`` option described below.
used for files that usually (on a Unix system) go into ``/tmp``. The
string will be interpreted relative to the node's base directory.
``reveal-IP-address = (boolean, optional, defaults to True)``
.. _webapi.rst: frontends/webapi.rst
This is a safety flag. When set to False (aka "private mode"), the node
will refuse to start if any of the other configuration options would
reveal the node's IP address to servers or the external network. This
flag does not directly affect the node's behavior: its only power is to
veto node startup when something looks unsafe.
The default is True (non-private mode), because setting it to False
requires the installation of additional libraries (use ``pip install
tahoe-lafs[tor]`` and/or ``pip install tahoe-lafs[i2p]`` to get them) as
well as additional non-python software (Tor/I2P daemons). Performance is
also generally reduced when operating in private mode.
When False, any of the following configuration problems will cause
``tahoe run`` to throw a PrivacyError instead of starting the node:
* ``[node] tub.location`` contains any ``tcp:`` hints
* ``[node] tub.location`` uses ``AUTO``, or is missing/empty (because
that defaults to AUTO)
* ``[connections] tcp =`` is set to ``tcp`` (or left as the default),
rather than being set to ``tor`` or ``disabled``
.. _Connection Management:
Connection Management
=====================
Three sections (``[tor]``, ``[i2p]``, and ``[connections]``) control how the
Tahoe node makes outbound connections. Tor and I2P are configured here. This
also controls when Tor and I2P are used: for all TCP connections (to hide
your IP address), or only when necessary (just for servers which declare that
they need Tor, because they use ``.onion`` addresses).
Note that if you want to protect your node's IP address, you should set
``[node] reveal-IP-address = False``, which will refuse to launch the node if
any of the other configuration settings might violate this privacy property.
``[connections]``
-----------------
This section controls *when* Tor and I2P are used. The ``[tor]`` and
``[i2p]`` sections (described later) control *how* Tor/I2P connections are
managed.
All Tahoe nodes need to make a connection to the Introducer; the
``private/introducers.yaml`` file (described below) configures where one or more
Introducers live. Tahoe client nodes must also make connections to storage
servers: these targets are specified in announcements that come from the
Introducer. Both are expressed as FURLs (a Foolscap URL), which include a
list of "connection hints". Each connection hint describes one (of perhaps
many) network endpoints where the service might live.
Connection hints include a type, and look like:
* ``tcp:tahoe.example.org:12345``
* ``tor:u33m4y7klhz3b.onion:1000``
* ``i2p:c2ng2pbrmxmlwpijn``
``tor`` hints are always handled by the ``tor`` handler (configured in the
``[tor]`` section, described below). Likewise, ``i2p`` hints are always
routed to the ``i2p`` handler. But either will be ignored if Tahoe was not
installed with the necessary Tor/I2P support libraries, or if the Tor/I2P
daemon is unreachable.
The ``[connections]`` section lets you control how ``tcp`` hints are handled.
By default, they use the normal TCP handler, which just makes direct
connections (revealing your node's IP address to both the target server and
the intermediate network). The node behaves this way if the ``[connections]``
section is missing entirely, or if it looks like this::
[connections]
tcp = tcp
To hide the Tahoe node's IP address from the servers that it uses, set the
``[connections]`` section to use Tor for TCP hints::
[connections]
tcp = tor
You can also disable TCP hints entirely, which would be appropriate when
running an I2P-only node::
[connections]
tcp = disabled
(Note that I2P does not support connections to normal TCP ports, so
``[connections] tcp = i2p`` is invalid)
In the future, Tahoe services may be changed to live on HTTP/HTTPS URLs
instead of Foolscap. In that case, connections will be made using whatever
handler is configured for ``tcp`` hints. So the same ``tcp = tor``
configuration will work.
``[tor]``
---------
This controls how Tor connections are made. The defaults (all empty) mean
that, when Tor is needed, the node will try to connect to a Tor daemon's
SOCKS proxy on localhost port 9050 or 9150. Port 9050 is the default Tor
SOCKS port, so it should be available under any system Tor instance (e.g. the
one launched at boot time when the standard Debian ``tor`` package is
installed). Port 9150 is the SOCKS port for the Tor Browser Bundle, so it
will be available any time the TBB is running.
You can set ``launch = True`` to cause the Tahoe node to launch a new Tor
daemon when it starts up (and kill it at shutdown), if you don't have a
system-wide instance available. Note that it takes 30-60 seconds for Tor to
get running, so using a long-running Tor process may enable a faster startup.
If your Tor executable doesn't live on ``$PATH``, use ``tor.executable=`` to
specify it.
``[tor]``
``enabled = (boolean, optional, defaults to True)``
If False, this will disable the use of Tor entirely. The default of True
means the node will use Tor, if necessary, and if possible.
``socks.port = (string, optional, endpoint specification string, defaults to empty)``
This tells the node that Tor connections should be routed to a SOCKS
proxy listening on the given endpoint. The default (of an empty value)
will cause the node to first try localhost port 9050, then if that fails,
try localhost port 9150. These are the default listening ports of the
standard Tor daemon, and the Tor Browser Bundle, respectively.
While this nominally accepts an arbitrary endpoint string, internal
limitations prevent it from accepting anything but ``tcp:HOST:PORT``
(unfortunately, unix-domain sockets are not yet supported). See ticket
#2813 for details. Also note that using a HOST of anything other than
localhost is discouraged, because you would be revealing your IP address
to external (and possibly hostile) machines.
``control.port = (string, optional, endpoint specification string)``
This tells the node to connect to a pre-existing Tor daemon on the given
control port (which is typically ``unix://var/run/tor/control`` or
``tcp:localhost:9051``). The node will then ask Tor what SOCKS port it is
using, and route Tor connections to that.
``launch = (bool, optional, defaults to False)``
If True, the node will spawn a new (private) copy of Tor at startup, and
will kill it at shutdown. The new Tor will be given a persistent state
directory under ``NODEDIR/private/``, where Tor's microdescriptors will
be cached, to speed up subsequent startup.
``tor.executable = (string, optional, defaults to empty)``
This controls which Tor executable is used when ``launch = True``. If
empty, the first executable program named ``tor`` found on ``$PATH`` will
be used.
There are 5 valid combinations of these configuration settings:
* 1: ``(empty)``: use SOCKS on port 9050/9150
* 2: ``launch = true``: launch a new Tor
* 3: ``socks.port = tcp:HOST:PORT``: use an existing Tor on the given SOCKS port
* 4: ``control.port = ENDPOINT``: use an existing Tor at the given control port
* 5: ``enabled = false``: no Tor at all
1 is the default, and should work for any Linux host with the system Tor
package installed. 2 should work on any box with Tor installed into $PATH,
but will take an extra 30-60 seconds at startup. 3 and 4 can be used for
specialized installations, where Tor is already running, but not listening on
the default port. 5 should be used in environments where Tor is installed,
but should not be used (perhaps due to a site-wide policy).
Note that Tor support depends upon some additional Python libraries. To
install Tahoe with Tor support, use ``pip install tahoe-lafs[tor]``.
``[i2p]``
---------
This controls how I2P connections are made. Like with Tor, the all-empty
defaults will cause I2P connections to be routed to a pre-existing I2P daemon
on port 7656. This is the default SAM port for the ``i2p`` daemon.
``[i2p]``
``enabled = (boolean, optional, defaults to True)``
If False, this will disable the use of I2P entirely. The default of True
means the node will use I2P, if necessary, and if possible.
``sam.port = (string, optional, endpoint descriptor, defaults to empty)``
This tells the node that I2P connections should be made via the SAM
protocol on the given port. The default (of an empty value) will cause
the node to try localhost port 7656. This is the default listening port
of the standard I2P daemon.
``launch = (bool, optional, defaults to False)``
If True, the node will spawn a new (private) copy of I2P at startup, and
will kill it at shutdown. The new I2P will be given a persistent state
directory under ``NODEDIR/private/``, where I2P's microdescriptors will
be cached, to speed up subsequent startup. The daemon will allocate its
own SAM port, which will be queried from the config directory.
``i2p.configdir = (string, optional, directory)``
This tells the node to parse an I2P config file in the given directory,
and use the SAM port it finds there. If ``launch = True``, the new I2P
daemon will be told to use the given directory (which can be
pre-populated with a suitable config file). If ``launch = False``, we
assume there is a pre-running I2P daemon running from this directory, and
can again parse the config file for the SAM port.
``i2p.executable = (string, optional, defaults to empty)``
This controls which I2P executable is used when ``launch = True``. If
empty, the first executable program named ``i2p`` found on ``$PATH`` will
be used.
.. _Client Configuration:
Client Configuration
====================
@ -579,8 +307,6 @@ Client Configuration
``introducer.furl = (FURL string, mandatory)``
DEPRECATED. See :ref:`introducer-definitions`.
This FURL tells the client how to connect to the introducer. Each
Tahoe-LAFS grid is defined by an introducer. The introducer's FURL is
created by the introducer node and written into its private base
@ -590,7 +316,18 @@ Client Configuration
``helper.furl = (FURL string, optional)``
If provided, the node will attempt to connect to and use the given helper
for uploads. See :doc:`helper` for details.
for uploads. See helper.rst_ for details.
``key_generator.furl = (FURL string, optional)``
If provided, the node will attempt to connect to and use the given
key-generator service, using RSA keys from the external process rather
than generating its own.
``stats_gatherer.furl = (FURL string, optional)``
If provided, the node will connect to the given stats gatherer and
provide it with operational statistics.
``shares.needed = (int, optional) aka "k", default 3``
@ -615,7 +352,7 @@ Client Configuration
ratios are more reliable, and small ``N``/``k`` ratios use less disk
space. ``N`` cannot be larger than 256, because of the 8-bit
erasure-coding algorithm that Tahoe-LAFS uses. ``k`` can not be greater
than ``N``. See :doc:`performance` for more details.
than ``N``. See performance.rst_ for more details.
``shares.happy`` allows you control over how well to "spread out" the
shares of an immutable file. For a successful upload, shares are
@ -653,49 +390,19 @@ Client Configuration
controlled by this parameter and will always use SDMF. We may revisit
this decision in future versions of Tahoe-LAFS.
See :doc:`specifications/mutable` for details about mutable file formats.
See mutable.rst_ for details about mutable file formats.
``peers.preferred = (string, optional)``
This is an optional comma-separated list of Node IDs of servers that will
be tried first when selecting storage servers for reading or writing.
Servers should be identified here by their Node ID as it appears in the web
ui, underneath the server's nickname. For storage servers running tahoe
versions >=1.10 (if the introducer is also running tahoe >=1.10) this will
be a "Node Key" (which is prefixed with 'v0-'). For older nodes, it will be
a TubID instead. When a preferred server (and/or the introducer) is
upgraded to 1.10 or later, clients must adjust their configs accordingly.
Every node selected for upload, whether preferred or not, will still
receive the same number of shares (one, if there are ``N`` or more servers
accepting uploads). Preferred nodes are simply moved to the front of the
server selection lists computed for each file.
This is useful if a subset of your nodes have different availability or
connectivity characteristics than the rest of the grid. For instance, if
there are more than ``N`` servers on the grid, and ``K`` or more of them
are at a single physical location, it would make sense for clients at that
location to prefer their local servers so that they can maintain access to
all of their uploads without using the internet.
``force_foolscap = (boolean, optional)``
If this is ``True``, the client will only connect to storage servers via
Foolscap, regardless of whether they support HTTPS. If this is ``False``,
the client will prefer HTTPS when it is available on the server. The default
value is ``False``.
In addition,
see :doc:`accepting-donations` for a convention for donating to storage server operators.
.. _helper.rst: helper.rst
.. _performance.rst: performance.rst
.. _mutable.rst: specifications/mutable.rst
Frontend Configuration
======================
The Tahoe-LAFS client process can run a variety of frontend file access
protocols. You will use these to create and retrieve files from the
Tahoe-LAFS file store. Configuration details for each are documented in
the following protocol-specific guides:
The Tahoe client process can run a variety of frontend file-access protocols.
You will use these to create and retrieve files from the virtual filesystem.
Configuration details for each are documented in the following
protocol-specific guides:
HTTP
@ -704,22 +411,33 @@ HTTP
directories and files, as well as a number of pages to check on the
status of your Tahoe node. It also provides a machine-oriented "WAPI",
with a REST-ful HTTP interface that can be used by other programs
(including the CLI tools). Please see :doc:`frontends/webapi` for full
details, and the ``web.port`` and ``web.static`` config variables above.
:doc:`frontends/download-status` also describes a few WUI status pages.
(including the CLI tools). Please see webapi.rst_ for full details, and
the ``web.port`` and ``web.static`` config variables above. The
`download-status.rst`_ document also describes a few WUI status pages.
CLI
The main ``tahoe`` executable includes subcommands for manipulating the
file store, uploading/downloading files, and creating/running Tahoe
nodes. See :doc:`frontends/CLI` for details.
The main "bin/tahoe" executable includes subcommands for manipulating the
filesystem, uploading/downloading files, and creating/running Tahoe
nodes. See CLI.rst_ for details.
SFTP
SFTP, FTP
Tahoe can also run SFTP servers, and map a username/password
pair to a top-level Tahoe directory. See :doc:`frontends/FTP-and-SFTP`
for instructions on configuring this service, and the ``[sftpd]``
section of ``tahoe.cfg``.
Tahoe can also run both SFTP and FTP servers, and map a username/password
pair to a top-level Tahoe directory. See FTP-and-SFTP.rst_ for
instructions on configuring these services, and the ``[sftpd]`` and
``[ftpd]`` sections of ``tahoe.cfg``.
Drop-Upload
As of Tahoe-LAFS v1.9.0, a node running on Linux can be configured to
automatically upload files that are created or changed in a specified
local directory. See drop-upload.rst_ for details.
.. _download-status.rst: frontends/download-status.rst
.. _CLI.rst: frontends/CLI.rst
.. _FTP-and-SFTP.rst: frontends/FTP-and-SFTP.rst
.. _drop-upload.rst: frontends/drop-upload.rst
Storage Server Configuration
@ -735,17 +453,6 @@ Storage Server Configuration
for clients who do not wish to provide storage service. The default value
is ``True``.
``anonymous = (boolean, optional)``
If this is ``True``, the node will expose the storage server via Foolscap
without any additional authentication or authorization. The capability to
use all storage services is conferred by knowledge of the Foolscap fURL
for the storage server which will be included in the storage server's
announcement. If it is ``False``, the node will not expose this and
storage must be exposed using the storage server plugin system (see
`Storage Server Plugin Configuration`_ for details). The default value is
``True``.
``readonly = (boolean, optional)``
If ``True``, the node will run a storage server but will not accept any
@ -790,54 +497,10 @@ Storage Server Configuration
These settings control garbage collection, in which the server will
delete shares that no longer have an up-to-date lease on them. Please see
:doc:`garbage-collection` for full details.
garbage-collection.rst_ for full details.
.. _#390: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/390
``storage_dir = (string, optional)``
This specifies a directory where share files and other state pertaining to
storage servers will be kept.
The default value is the ``storage`` directory in the node's base directory
(i.e. ``BASEDIR/storage``), but it can be placed elsewhere. Relative paths
will be interpreted relative to the node's base directory.
``force_foolscap = (boolean, optional)``
If this is ``True``, the node will expose the storage server via Foolscap
only, with no support for HTTPS. If this is ``False``, the server will
support both Foolscap and HTTPS on the same port. The default value is
``False``.
In addition,
see :doc:`accepting-donations` for a convention encouraging donations to storage server operators.
Storage Server Plugin Configuration
===================================
In addition to the built-in storage server,
it is also possible to load and configure storage server plugins into Tahoe-LAFS.
Plugins to load are specified in the ``[storage]`` section.
``plugins = (string, optional)``
This gives a comma-separated list of plugin names.
Plugins named here will be loaded and offered to clients.
The default is for no such plugins to be loaded.
Each plugin can also be configured in a dedicated section.
The section for each plugin is named after the plugin itself::
[storageserver.plugins.<plugin name>]
For example,
the configuration section for a plugin named ``acme-foo-v1`` is ``[storageserver.plugins.acme-foo-v1]``.
The contents of such sections are defined by the plugins themselves.
Refer to the documentation provided with those plugins.
.. _garbage-collection.rst: garbage-collection.rst
Running A Helper
@ -850,12 +513,12 @@ service.
``enabled = (boolean, optional)``
If ``True``, the node will run a helper (see :doc:`helper` for details).
If ``True``, the node will run a helper (see helper.rst_ for details).
The helper's contact FURL will be placed in ``private/helper.furl``, from
which it can be copied to any clients that wish to use it. Clearly nodes
should not both run a helper and attempt to use one: do not create
``helper.furl`` and also define ``[helper]enabled`` in the same node. The
default is ``False``.
``helper.furl`` and also define ``[helper]enabled`` in the same node.
The default is ``False``.
Running An Introducer
@ -880,8 +543,6 @@ Other Files in BASEDIR
Some configuration is not kept in ``tahoe.cfg``, for the following reasons:
* it doesn't fit into the INI format of ``tahoe.cfg`` (e.g.
``private/servers.yaml``)
* it is generated by the node at startup, e.g. encryption keys. The node
never writes to ``tahoe.cfg``.
* it is generated by user action, e.g. the "``tahoe create-alias``" command.
@ -904,7 +565,7 @@ This section describes these other files.
files on behalf of other clients. There will be a directory underneath it
for each StorageIndex for which this node is holding shares. There is also
an "incoming" directory where partially-completed shares are held while
they are being received. This location may be overridden in ``tahoe.cfg``.
they are being received.
``tahoe-client.tac``
@ -919,6 +580,16 @@ This section describes these other files.
This file is used to construct an introducer, and is created by the
"``tahoe create-introducer``" command.
``tahoe-key-generator.tac``
This file is used to construct a key generator, and is created by the
"``tahoe create-key-gernerator``" command.
``tahoe-stats-gatherer.tac``
This file is used to construct a statistics gatherer, and is created by the
"``tahoe create-stats-gatherer``" command.
``private/control.furl``
This file contains a FURL that provides access to a control port on the
@ -938,7 +609,7 @@ This section describes these other files.
``private/helper.furl``
If the node is running a helper (for use by other clients), its contact
FURL will be placed here. See :doc:`helper` for more details.
FURL will be placed here. See helper.rst_ for more details.
``private/root_dir.cap`` (optional)
@ -970,142 +641,6 @@ This section describes these other files.
with as many people as possible, put the empty string (so that
``private/convergence`` is a zero-length file).
.. _introducer-definitions:
Introducer Definitions
======================
The ``private/introducers.yaml`` file defines Introducers.
Choose a locally-unique "petname" for each one then define their FURLs in ``private/introducers.yaml`` like this::
introducers:
petname2:
furl: "FURL2"
petname3:
furl: "FURL3"
Servers will announce themselves to all configured introducers. Clients will
merge the announcements they receive from all introducers. Nothing will
re-broadcast an announcement (i.e. telling introducer 2 about something you
heard from introducer 1).
If you omit the introducer definitions from ``introducers.yaml``,
the node will not use an Introducer at all.
Such "introducerless" clients must be configured with static servers (described
below), or they will not be able to upload and download files.
.. _server_list:
Static Server Definitions
=========================
The ``private/servers.yaml`` file defines "static servers": those which are
not announced through the Introducer. This can also control how we connect to
those servers.
Most clients do not need this file. It is only necessary if you want to use
servers which are (for some specialized reason) not announced through the
Introducer, or to connect to those servers in different ways. You might do
this to "freeze" the server list: use the Introducer for a while, then copy
all announcements into ``servers.yaml``, then stop using the Introducer
entirely. Or you might have a private server that you don't want other users
to learn about (via the Introducer). Or you might run a local server which is
announced to everyone else as a Tor onion address, but which you can connect
to directly (via TCP).
The file syntax is `YAML`_, with a top-level dictionary named ``storage``.
Other items may be added in the future.
The ``storage`` dictionary takes keys which are server-ids, and values which
are dictionaries with two keys: ``ann`` and ``connections``. The ``ann``
value is a dictionary which will be used in lieu of the introducer
announcement, so it can be populated by copying the ``ann`` dictionary from
``NODEDIR/introducer_cache.yaml``.
The server-id can be any string, but ideally you should use the public key as
published by the server. Each server displays this as "Node ID:" in the
top-right corner of its "WUI" web welcome page. It can also be obtained from
other client nodes, which record it as ``key_s:`` in their
``introducer_cache.yaml`` file. The format is "v0-" followed by 52 base32
characters like so::
v0-c2ng2pbrmxmlwpijn3mr72ckk5fmzk6uxf6nhowyosaubrt6y5mq
The ``ann`` dictionary really only needs one key:
* ``anonymous-storage-FURL``: how we connect to the server
(note that other important keys may be added in the future, as Accounting and
HTTP-based servers are implemented)
Optional keys include:
* ``nickname``: the name of this server, as displayed on the Welcome page
server list
* ``permutation-seed-base32``: this controls how shares are mapped to
servers. This is normally computed from the server-ID, but can be
overridden to maintain the mapping for older servers which used to use
Foolscap TubIDs as server-IDs. If your selected server-ID cannot be parsed
as a public key, it will be hashed to compute the permutation seed. This is
fine as long as all clients use the same thing, but if they don't, then
your client will disagree with the other clients about which servers should
hold each share. This will slow downloads for everybody, and may cause
additional work or consume extra storage when repair operations don't
converge.
* anything else from the ``introducer_cache.yaml`` announcement, like
``my-version``, which is displayed on the Welcome page server list
For example, a private static server could be defined with a
``private/servers.yaml`` file like this::
storage:
v0-4uazse3xb6uu5qpkb7tel2bm6bpea4jhuigdhqcuvvse7hugtsia:
ann:
nickname: my-server-1
anonymous-storage-FURL: pb://u33m4y7klhz3bypswqkozwetvabelhxt@tcp:8.8.8.8:51298/eiu2i7p6d6mm4ihmss7ieou5hac3wn6b
Or, if you're feeling really lazy::
storage:
my-serverid-1:
ann:
anonymous-storage-FURL: pb://u33m4y7klhz3bypswqkozwetvabelhxt@tcp:8.8.8.8:51298/eiu2i7p6d6mm4ihmss7ieou5hac3wn6b
.. _YAML: http://yaml.org/
Overriding Connection-Handlers for Static Servers
-------------------------------------------------
A ``connections`` entry will override the default connection-handler mapping
(as established by ``tahoe.cfg [connections]``). This can be used to build a
"Tor-mostly client": one which is restricted to use Tor for all connections,
except for a few private servers to which normal TCP connections will be
made. To override the published announcement (and thus avoid connecting twice
to the same server), the server ID must exactly match.
``tahoe.cfg``::
[connections]
# this forces the use of Tor for all "tcp" hints
tcp = tor
``private/servers.yaml``::
storage:
v0-c2ng2pbrmxmlwpijn3mr72ckk5fmzk6uxf6nhowyosaubrt6y5mq:
ann:
nickname: my-server-1
anonymous-storage-FURL: pb://u33m4y7klhz3bypswqkozwetvabelhxt@tcp:10.1.2.3:51298/eiu2i7p6d6mm4ihmss7ieou5hac3wn6b
connections:
# this overrides the tcp=tor from tahoe.cfg, for just this server
tcp: tcp
The ``connections`` table is needed to override the ``tcp = tor`` mapping
that comes from ``tahoe.cfg``. Without it, the client would attempt to use
Tor to connect to ``10.1.2.3``, which would fail because it is a
local/non-routeable (RFC1918) address.
Other files
===========
@ -1136,7 +671,7 @@ Other files
files. The web-API has a facility to block access to filecaps by their
storage index, returning a 403 "Forbidden" error instead of the original
file. For more details, see the "Access Blacklist" section of
:doc:`frontends/webapi`.
webapi.rst_.
Example
@ -1151,15 +686,18 @@ a legal one.
[node]
nickname = Bob's Tahoe-LAFS Node
tub.port = tcp:34912
tub.location = tcp:123.45.67.89:8098,tcp:44.55.66.77:8098
web.port = tcp:3456
tub.port = 34912
tub.location = 123.45.67.89:8098,44.55.66.77:8098
web.port = 3456
log_gatherer.furl = pb://soklj4y7eok5c3xkmjeqpw@192.168.69.247:44801/eqpwqtzm
timeout.keepalive = 240
timeout.disconnect = 1800
ssh.port = 8022
ssh.authorized_keys_file = ~/.ssh/authorized_keys
[client]
helper.furl = pb://ggti5ssoklj4y7eok5c3xkmj@tcp:helper.tahoe.example:7054/kk8lhr
introducer.furl = pb://ok45ssoklj4y7eok5c3xkmj@tahoe.example:44801/ii3uumo
helper.furl = pb://ggti5ssoklj4y7eok5c3xkmj@helper.tahoe.example:7054/kk8lhr
[storage]
enabled = True
@ -1169,11 +707,6 @@ a legal one.
[helper]
enabled = True
To be introduced to storage servers, here is a sample ``private/introducers.yaml`` which can be used in conjunction::
introducers:
examplegrid:
furl: "pb://ok45ssoklj4y7eok5c3xkmj@tcp:tahoe.example:44801/ii3uumo"
Old Configuration Files
=======================
@ -1181,4 +714,6 @@ Old Configuration Files
Tahoe-LAFS releases before v1.3.0 had no ``tahoe.cfg`` file, and used
distinct files for each item. This is no longer supported and if you have
configuration in the old format you must manually convert it to the new
format for Tahoe-LAFS to detect it. See :doc:`historical/configuration`.
format for Tahoe-LAFS to detect it. See `historical/configuration.rst`_.
.. _historical/configuration.rst: historical/configuration.rst

View File

@ -1 +0,0 @@
.. include:: ../.github/CONTRIBUTING.rst

View File

@ -1,9 +1,5 @@
.. -*- coding: utf-8-with-signature -*-
**********************
The Convergence Secret
**********************
What Is It?
-----------

View File

@ -11,7 +11,8 @@ Debian and Ubuntu Support
Overview
========
Tahoe-LAFS is provided as a ``.deb`` package in current Debian (>= `stretch <https://packages.debian.org/source/stretch/tahoe-lafs>`_) and Ubuntu (>= lucid) releases. Before official packages were added, the Tahoe
Tahoe-LAFS is provided as a ``.deb`` package in current Debian (>= wheezy)
and Ubuntu (>= lucid) releases. Before official packages were added, the Tahoe
source tree provided support for building unofficial packages for a variety
of popular Debian/Ubuntu versions. The project also ran buildbots to create
``.debs`` of current trunk for ease of testing.
@ -34,21 +35,21 @@ Dependency Packages
Tahoe depends upon a number of additional libraries. When building Tahoe from
source, any dependencies that are not already present in the environment will
be downloaded (via ``pip`` and ``easy_install``) and installed in the
virtualenv.
be downloaded (via ``easy_install``) and stored in the ``support/lib``
directory.
The ``.deb`` packages, of course, rely solely upon other ``.deb`` packages.
For reference, here is a list of the debian package names that provide Tahoe's
dependencies as of the 1.14.0 release:
dependencies as of the 1.9 release:
* python
* python-zfec
* python-pycryptopp
* python-foolscap
* python-openssl (needed by foolscap)
* python-twisted
* python-nevow
* python-mock
* python-cryptography
* python-simplejson
* python-setuptools
* python-support (for Debian-specific install-time tools)

View File

@ -1,42 +0,0 @@
Developer Guide
===============
Pre-commit Checks
-----------------
This project is configured for use with `pre-commit`_ to install `VCS/git hooks`_ which perform some static code analysis checks and other code checks to catch common errors.
These hooks can be configured to run before commits or pushes
For example::
tahoe-lafs $ pre-commit install --hook-type pre-push
pre-commit installed at .git/hooks/pre-push
tahoe-lafs $ echo "undefined" > src/allmydata/undefined_name.py
tahoe-lafs $ git add src/allmydata/undefined_name.py
tahoe-lafs $ git commit -a -m "Add a file that violates flake8"
tahoe-lafs $ git push
codechecks...............................................................Failed
- hook id: codechecks
- exit code: 1
GLOB sdist-make: ./tahoe-lafs/setup.py
codechecks inst-nodeps: ...
codechecks installed: ...
codechecks run-test-pre: PYTHONHASHSEED='...'
codechecks run-test: commands[0] | flake8 src/allmydata/undefined_name.py
src/allmydata/undefined_name.py:1:1: F821 undefined name 'undefined'
ERROR: InvocationError for command ./tahoe-lafs/.tox/codechecks/bin/flake8 src/allmydata/undefined_name.py (exited with code 1)
___________________________________ summary ____________________________________
ERROR: codechecks: commands failed
To uninstall::
tahoe-lafs $ pre-commit uninstall --hook-type pre-push
pre-push uninstalled
.. _`pre-commit`: https://pre-commit.com
.. _`VCS/git hooks`: `pre-commit`_
.. _`pre-commit configuration`: ../.pre-commit-config.yaml

View File

@ -1,42 +0,0 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
January 20, 2021
Any of the following core Tahoe contributers may sign a release. Each
release MUST be signed by at least one developer but MAY have
additional signatures. Each developer independently produces a
signature which is made available beside Tahoe releases after 1.15.0
This statement is signed by the existing Tahoe release key. Any future
such statements may be signed by it OR by any two developers (for
example, to add or remove developers from the list).
meejah
0xC2602803128069A7
9D5A 2BD5 688E CB88 9DEB CD3F C260 2803 1280 69A7
https://meejah.ca/meejah.asc
jean-paul calderone (exarkun)
0xE27B085EDEAA4B1B
96B9 C5DA B2EA 9EB6 7941 9DB7 E27B 085E DEAA 4B1B
https://twistedmatrix.com/~exarkun/E27B085EDEAA4B1B.asc
brian warner (lothar)
0x863333C265497810
5810 F125 7F8C F753 7753 895A 8633 33C2 6549 7810
https://www.lothar.com/warner-gpg.html
-----BEGIN PGP SIGNATURE-----
iQEzBAEBCgAdFiEE405i0G0Oac/KQXn/veDTHWhmanoFAmAHIyIACgkQveDTHWhm
anqhqQf/YSbMXL+gwFhAZsjX39EVlbr/Ik7WPPkJW7v1oHybTnwFpFIc52COU1x/
sqRfk4OyYtz9IBgOPXoWgXu9R4qdK6vYKxEsekcGT9C5l0OyDz8YWXEWgbGK5mvI
aEub9WucD8r2uOQnnW6DtznFuEpvOjtf/+2BU767+bvLsbViW88ocbuLfCqLdOgD
WZT9j3M+Y2Dc56DAJzP/4fkrUSVIofZStYp5u9HBjburgcYIp0g/cyc4xXRoi6Mp
lFTRFv3MIjmoamzSQseoIgP6fi8QRqPrffPrsyqAp+06mJnPhxxFqxtO/ZErmpSa
+BGrLBxdWa8IF9U1A4Fs5nuAzAKMEg==
=E9J+
-----END PGP SIGNATURE-----

View File

@ -1,125 +0,0 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
=========
Donations
=========
Donations to the Tahoe-LAFS project are welcome, and can be made to the
following Bitcoin address:
1PxiFvW1jyLM5T6Q1YhpkCLxUh3Fw8saF3
The funds currently available to the project are visible through the
blockchain explorer:
https://blockchain.info/address/1PxiFvW1jyLM5T6Q1YhpkCLxUh3Fw8saF3
Governance
==========
The Tahoe-LAFS Software Foundation manages these funds. Our intention is
to use them for operational expenses (website hosting, test
infrastructure, EC2 instance rental, and SSL certificates). Future uses
might include developer summit expenses, bug bounties, contract services
(e.g. graphic design for the web site, professional security review of
codebases, development of features outside the core competencies of the
main developers), and student sponsorships.
The Foundation currently consists of secorp (Peter Secor), warner (Brian
Warner), and zooko (Zooko Wilcox).
Transparent Accounting
======================
Our current plan is to leave all funds in the main `1Pxi` key until they
are spent. For each declared budget item, we will allocate a new public
key, and transfer funds to that specific key before distributing them to
the ultimate recipient. All expenditures can thus be tracked on the
blockchain.
Some day, we might choose to move the funds into a more sophisticated
type of key (e.g. a 2-of-3 multisig address). If/when that happens, we
will publish the new donation address, and transfer all funds to it. We
will continue the plan of keeping all funds in the (new) primary
donation address until they are spent.
Expenditure Addresses
=====================
This lists the public key used for each declared budget item. The individual
payments will be recorded in a separate file (see `docs/expenses.rst`), which
is not signed. All transactions from the main `1Pxi` key should be to some
key on this list.
* Initial testing (warner)
1387fFG7Jg1iwCzfmQ34FwUva7RnC6ZHYG
one-time 0.01 BTC deposit+withdrawal
* tahoe-lafs.org DNS registration (paid by warner)
1552pt6wpudVCRcJaU14T7tAk8grpUza4D
~$15/yr for DNS
* tahoe-lafs.org SSL certificates (paid by warner)
$0-$50/yr, ending 2015 (when we switched to LetsEncrypt)
1EkT8yLvQhnjnLpJ6bNFCfAHJrM9yDjsqa
* website/dev-server hosting (on Linode, paid by secorp)
~$20-$25/mo, 2007-present
1MSWNt1R1fohYxgaMV7gJSWbYjkGbXzKWu (<= may-2016)
1NHgVsq1nAU9x1Bb8Rs5K3SNtzEH95C5kU (>= jun-2016)
* 2016 Tahoe Summit expenses: venue rental, team dinners (paid by warner)
~$1020
1DskmM8uCvmvTKjPbeDgfmVsGifZCmxouG
* Aspiration contract
$300k-$350k (first phase, 2019)
$800k (second phase, 2020)
1gDXYQNH4kCJ8Dk7kgiztfjNUaA1KJcHv
* OpenCollective development work (2023)
~$260k
1KZYr8UU2XjuEdSPzn2pF8eRPZZvffByDf
Historical Donation Addresses
=============================
The Tahoe project has had a couple of different donation addresses over
the years, managed by different people. All of these funds have been (or
will be) transferred to the current primary donation address (`1Pxi`).
* 13GrdS9aLXoEbcptBLQi7ffTsVsPR7ubWE (21-Aug-2010 - 23-Aug-2010)
Managed by secorp, total receipts: 17 BTC
* 19jzBxijUeLvcMVpUYXcRr5kGG3ThWgx4P (23-Aug-2010 - 29-Jan-2013)
Managed by secorp, total receipts: 358.520276 BTC
* 14WTbezUqWSD3gLhmXjHD66jVg7CwqkgMc (24-May-2013 - 21-Mar-2016)
Managed by luckyredhot, total receipts: 3.97784278 BTC
stored in 19jXek4HRL54JrEwNPyEzitPnkew8XPkd8
* 1PxiFvW1jyLM5T6Q1YhpkCLxUh3Fw8saF3 (21-Mar-2016 - present)
Managed by warner, backups with others
Validation
==========
This document is signed by the Tahoe-LAFS Release-Signing Key (GPG keyid
2048R/68666A7A, fingerprint E34E 62D0 6D0E 69CF CA41 79FF BDE0 D31D 6866
6A7A). It is also committed to the Tahoe source tree
(https://github.com/tahoe-lafs/tahoe-lafs.git) as `docs/donations.rst`.
Both actions require access to secrets held closely by Tahoe developers.
signed: Brian Warner, 25-Oct-2023
-----BEGIN PGP SIGNATURE-----
iQEzBAEBCAAdFiEE405i0G0Oac/KQXn/veDTHWhmanoFAmU5YZMACgkQveDTHWhm
anqt+ggAo2kulNmjrWA5VhqE8i6ckkxQMRVY4y0LAfiI0ho/505ZBZvpoh/Ze31x
ZJj4DczHmZM+m3L+fZyubT4ldagYEojtwkYmxHAQz2DIV4PrdjsUQWyvkNcTBZWu
y5mR5ATk3EYRa19xGEosWK1OzW2kgRbpAbznuWsdxxw9vNENBrolGRsyJqRQHCiV
/4UkrGiOegaJSFMKy2dCyDF3ExD6wT9+fdqC5xDJZjhD+SUDJnD4oWLYLroj//v1
sy4J+/ElNU9oaC0jDb9fx1ECk+u6B+YiaYlW/MrZNqzKCM/76yZ8sA2+ynsOHGtL
bPFpLJjX6gBwHkMqvkWhsJEojxkFVQ==
=gxlb
-----END PGP SIGNATURE-----

View File

@ -1,184 +0,0 @@
==============================
Expenses paid by donated BTC
==============================
`docs/donations.rst` describes the "Transparent Accounting" that we use for
BTC that has been donated to the Tahoe project. That document lists the
budget items for which we intend to spend these funds, and a Bitcoin public
key for each one. It is signed by the Tahoe-LAFS Release Signing Key, and
gets re-signed each time a new budget item is added.
For every expense that get paid, the BTC will first be moved from the primary
donation key into the budget-item -specific subkey, then moved from that
subkey to whatever vendor or individual is being paid.
This document tracks the actual payments made to each vendor. This file
changes more frequently than `donations.rst`, hence it is *not* signed.
However this file should never reference a budget item or public key which is
not present in `donations.rst`. And every payment in this file should
correspond to a transaction visible on the Bitcoin block chain explorer:
https://blockchain.info/address/1PxiFvW1jyLM5T6Q1YhpkCLxUh3Fw8saF3
Budget Items
============
Initial Testing
---------------
This was a small transfer to obtain proof-of-spendability for the new wallet.
* Budget: trivial
* Recipient: warner
* Address: 1387fFG7Jg1iwCzfmQ34FwUva7RnC6ZHYG
Expenses/Transactions:
* 17-Mar-2016: deposit+withdrawal of 0.01 BTC
* bcad5f46ebf9fd5d2d7a6a9bed81acf6382cd7216ceddbb5b5f5d968718ec139 (in)
* 13c7f4abf9d6e7f2223c20fefdc47837779bebf3bd95dbb1f225f0d2a2d62c44 (out 1/2)
* 7ca0828ea11fa2f93ab6b8afd55ebdca1415c82c567119d9bd943adbefccce84 (out 2/2)
DNS Registration
----------------
Yearly registration of the `tahoe-lafs.org` domain name.
* Budget: ~$15/yr
* Recipient: warner
* Address: 1552pt6wpudVCRcJaU14T7tAk8grpUza4D
Expenses/Transactions:
* 21-Aug-2012: 1 year, GANDI: $12.50
* 20-Aug-2013: 4 years, GANDI: $64.20
* 4ee7fbcb07f758d51187b6856eaf9999f14a7f3d816fe3afb7393f110814ae5e
0.11754609 BTC (@$653.41) = $76.70, plus 0.000113 tx-fee
TLS certificates
----------------
Yearly payment for TLS certificates from various vendors. We plan to move to
Lets Encrypt, so 2015 should be last time we pay for a cert.
* Budget: $0-$50/yr
* Recipient: warner
* Address: 1EkT8yLvQhnjnLpJ6bNFCfAHJrM9yDjsqa
Expenses/Transactions:
* 29-Oct-2012: RapidSSL: $49
* 02-Nov-2013: GlobalSign, free for open source projects: $0
* 14-Nov-2014: GANDI: $16
* 28-Oct-2015: GANDI: $16
* e8d1b78fab163baa45de0ec592f8d7547329343181e35c2cdb30e427a442337e
0.12400489 BTC (@$653.20) = $81, plus 0.000113 tx-fee
Web/Developer Server Hosting
----------------------------
This pays for the rental of a VPS (currently from Linode) for tahoe-lafs.org,
running the project website, Trac, buildbot, and other development tools.
* Budget: $20-$25/month, 2007-present
* Recipient: secorp
* Addresses:
1MSWNt1R1fohYxgaMV7gJSWbYjkGbXzKWu (<= may-2016)
1NHgVsq1nAU9x1Bb8Rs5K3SNtzEH95C5kU (>= jun-2016)
Expenses/Transactions:
* Invoice 311312, 12 Feb 2010: $339.83
* Invoice 607395, 05 Jan 2011: $347.39
* Invoice 1183568, 01 Feb 2012: $323.46
* Invoice 1973091, 01 Feb 2013: $323.46
* Invoice 2899489, 01 Feb 2014: $324.00
* Invoice 3387159, 05 July 2014: $6.54 (add backups)
* Multiple invoices monthly 01 Aug 2014 - 01 May 2016: $7.50*22 = $165.00
* Invoice 4083422, 01 Feb 2015: $324.00
* Invoice 5650991, 01 Feb 2016: $324.00
* -- Total through 01 May 2016: $2477.68
* 5861efda59f9ae10952389cf52f968bb469019c77a3642e276a9e35131c36600
3.78838567 BTC (@$654.02) = $2477.68, plus 0.000113 tx-fee
*
* June 2016 - Oct 2016 $27.45/mo, total $137.25
* 8975b03002166b20782b0f023116b3a391ac5176de1a27e851891bee29c11957
0.19269107 BTC (@$712.28) = $137.25, plus 0.000113 tx-fee
* (Oops, I forgot the process, and sent the BTC directly secorp's key. I
should have stuck with the 1MSWN key as the intermediary. Next time I'll go
back to doing it that way.)
Tahoe Summit
------------
This pays for office space rental and team dinners for each day of the
developer summit.
* Recipient: warner
* Address: 1DskmM8uCvmvTKjPbeDgfmVsGifZCmxouG
* 2016 Summit (Nov 8-9, San Francisco)
* Rental of the Mechanics Institute Library "Board Room": $300/day*2
* Team Dinner (Cha Cha Cha): $164.49
* Team Dinner (Rasoi): $255.34
* -- total: $1019.83
* dcd468fb2792b018e9ebc238e9b93992ad5a8fce48a8ff71db5d79ccbbe30a92
0.01403961 (@$712.28) = $10, plus 0.000113 tx-fee
* acdfc299c35eed3bb27f7463ad8cdfcdcd4dcfd5184f290f87530c2be999de3e
1.41401086 (@$714.16) = $1009.83, plus 0.000133 tx-fee
Aspiration Contract
-------------------
In December 2018, we entered into an agreement with a non-profit named
Aspiration (https://aspirationtech.org/) to fund contractors for development
work. They handle payroll, taxes, and oversight, in exchange for an 8%
management fee. The first phase of work will extend through most of 2019.
* Recipient: Aspiration
* Address: 1gDXYQNH4kCJ8Dk7kgiztfjNUaA1KJcHv
These txids record the transfers from the primary 1Pxi address to the
Aspiration-specific 1gDXY subaddress. In some cases, leftover funds
were swept back into the main 1Pxi address after the transfers were
complete.
First phase, transfers performed 28-Dec-2018 - 31-Dec-2018, total 89
BTC, about $350K.
* 95c68d488bd92e8c164195370aaa516dff05aa4d8c543d3fb8cfafae2b811e7a
1.0 BTC plus 0.00002705 tx-fee
* c0a5b8e3a63c56c4365d4c3ded0821bc1170f6351502849168bc34e30a0582d7
89.0 BTC plus 0.00000633 tx-fee
* 421cff5f398509aaf48951520738e0e63dfddf1157920c15bdc72c34e24cf1cf
return 0.00005245 BTC to 1Pxi, less 0.00000211 tx-fee
In November 2020, we funded a second phase of the work: 51.38094 BTC,
about $800K.
* 7558cbf3b24e8d835809d2d6f01a8ba229190102efdf36280d0639abaa488721
1.0 BTC plus 0.00230766 tx-fee
* 9c78ae6bb7db62cbd6be82fd52d50a2f015285b562f05de0ebfb0e5afc6fd285
56.0 BTC plus 0.00057400 tx-fee
* fbee4332e8c7ffbc9c1bcaee773f063550e589e58d350d14f6daaa473966c368
returning 5.61906 BTC to 1Pxi, less 0.00012000 tx-fee
Open Collective
---------------
In August 2023, we started working with Open Collective to fund a
grant covering development work performed over the last year.
* Recipient: Open Collective (US)
* Address: 1KZYr8UU2XjuEdSPzn2pF8eRPZZvffByDf
The first phase transferred 7.5 BTC (about $260K).
* (txid)
(amount)

View File

@ -10,7 +10,7 @@ The Tahoe-LAFS CLI commands
1. `Unicode Support`_
3. `Node Management`_
4. `File Store Manipulation`_
4. `Filesystem Manipulation`_
1. `Starting Directories`_
2. `Command Syntax Summary`_
@ -23,10 +23,21 @@ The Tahoe-LAFS CLI commands
Overview
========
Tahoe-LAFS provides a single executable named "``tahoe``", which can be used
to create and manage client/server nodes, manipulate the file store, and
perform several debugging/maintenance tasks. This executable is installed
into your virtualenv when you run ``pip install tahoe-lafs``.
Tahoe-LAFS provides a single executable named "``tahoe``", which can be used to
create and manage client/server nodes, manipulate the filesystem, and perform
several debugging/maintenance tasks.
This executable lives in the source tree at "``bin/tahoe``". Once you've done a
build (by running "``make``" or "``python setup.py build``"), ``bin/tahoe`` can
be run in-place: if it discovers that it is being run from within a Tahoe-LAFS
source tree, it will modify ``sys.path`` as necessary to use all the source code
and dependent libraries contained in that tree.
If you've installed Tahoe-LAFS (using "``make install``" or
"``python setup.py install``", or by installing a binary package), then the
``tahoe`` executable will be available somewhere else, perhaps in
``/usr/bin/tahoe``. In this case, it will use your platform's normal
PYTHONPATH search path to find the Tahoe-LAFS code and other libraries.
CLI Command Overview
@ -35,7 +46,7 @@ CLI Command Overview
The "``tahoe``" tool provides access to three categories of commands.
* node management: create a client/server node, start/stop/restart it
* file store manipulation: list files, upload, download, unlink, rename
* filesystem manipulation: list files, upload, download, unlink, rename
* debugging: unpack cap-strings, examine share files
To get a list of all commands, just run "``tahoe``" with no additional
@ -44,7 +55,7 @@ arguments. "``tahoe --help``" might also provide something useful.
Running "``tahoe --version``" will display a list of version strings, starting
with the "allmydata" module (which contains the majority of the Tahoe-LAFS
functionality) and including versions for a number of dependent libraries,
like Twisted, Foolscap, cryptography, and zfec. "``tahoe --version-and-path``"
like Twisted, Foolscap, pycryptopp, and zfec. "``tahoe --version-and-path``"
will also show the path from which each library was imported.
On Unix systems, the shell expands filename wildcards (``'*'`` and ``'?'``)
@ -83,18 +94,18 @@ the command line.
Node Management
===============
"``tahoe create-node [NODEDIR]``" is the basic make-a-new-node
command. It creates a new directory and populates it with files that
will allow the "``tahoe run``" and related commands to use it later
on. ``tahoe create-node`` creates nodes that have client functionality
(upload/download files), web API services (controlled by the
'[node]web.port' configuration), and storage services (unless
``--no-storage`` is specified).
"``tahoe create-node [NODEDIR]``" is the basic make-a-new-node command. It
creates a new directory and populates it with files that will allow the
"``tahoe start``" command to use it later on. This command creates nodes that
have client functionality (upload/download files), web API services
(controlled by the '[node]web.port' configuration), and storage services
(unless ``--no-storage`` is specified).
NODEDIR defaults to ``~/.tahoe/`` , and newly-created nodes default to
publishing a web server on port 3456 (limited to the loopback interface, at
127.0.0.1, to restrict access to other programs on the same host). All of the
other "``tahoe``" subcommands use corresponding defaults.
other "``tahoe``" subcommands use corresponding defaults (with the exception
that "``tahoe run``" defaults to running a node in the current directory).
"``tahoe create-client [NODEDIR]``" creates a node with no storage service.
That is, it behaves like "``tahoe create-node --no-storage [NODEDIR]``".
@ -105,26 +116,38 @@ This node provides introduction services and nothing else. When started, this
node will produce a ``private/introducer.furl`` file, which should be
published to all clients.
"``tahoe create-key-generator [NODEDIR]``" is used to create a special
"key-generation" service, which allows a client to offload their RSA key
generation to a separate process. Since RSA key generation takes several
seconds, and must be done each time a directory is created, moving it to a
separate process allows the first process (perhaps a busy web-API server) to
continue servicing other requests. The key generator exports a FURL that can
be copied into a node to enable this functionality.
Running Nodes
-------------
"``tahoe run [NODEDIR]``" will start a previously-created node in the foreground.
No matter what kind of node you created, the correct way to run it is
to use the ``tahoe run`` command. "``tahoe run [NODEDIR]``" will start
a previously-created node in the foreground. This command functions
the same way on all platforms and logs to stdout. If you want to run
the process as a daemon, it is recommended that you use your favourite
daemonization tool.
"``tahoe start [NODEDIR]``" will launch a previously-created node. It will
launch the node into the background, using the standard Twisted "``twistd``"
daemon-launching tool. On some platforms (including Windows) this command is
unable to run a daemon in the background; in that case it behaves in the
same way as "``tahoe run``".
File Store Manipulation
"``tahoe stop [NODEDIR]``" will shut down a running node.
"``tahoe restart [NODEDIR]``" will stop and then restart a running node. This
is most often used by developers who have just modified the code and want to
start using their changes.
Filesystem Manipulation
=======================
These commands let you exmaine a Tahoe-LAFS file store, providing basic
These commands let you exmaine a Tahoe-LAFS filesystem, providing basic
list/upload/download/unlink/rename/mkdir functionality. They can be used as
primitives by other scripts. Most of these commands are fairly thin wrappers
around web-API calls, which are described in :doc:`webapi`.
around web-API calls, which are described in `<webapi.rst>`__.
By default, all file store manipulation commands look in ``~/.tahoe/`` to
By default, all filesystem-manipulation commands look in ``~/.tahoe/`` to
figure out which Tahoe-LAFS node they should use. When the CLI command makes
web-API calls, it will use ``~/.tahoe/node.url`` for this purpose: a running
Tahoe-LAFS node that provides a web-API port will write its URL into this
@ -138,12 +161,13 @@ they ought to use a starting point. This is explained in more detail below.
Starting Directories
--------------------
As described in :doc:`../architecture`, the Tahoe-LAFS distributed file store
consists of a collection of directories and files, each of which has a
"read-cap" or a "write-cap" (also known as a URI). Each directory is simply a
table that maps a name to a child file or directory, and this table is turned
into a string and stored in a mutable file. The whole set of directory and
file "nodes" are connected together into a directed graph.
As described in `docs/architecture.rst <../architecture.rst>`__, the
Tahoe-LAFS distributed filesystem consists of a collection of directories
and files, each of which has a "read-cap" or a "write-cap" (also known as
a URI). Each directory is simply a table that maps a name to a child file
or directory, and this table is turned into a string and stored in a
mutable file. The whole set of directory and file "nodes" are connected
together into a directed graph.
To use this collection of files and directories, you need to choose a
starting point: some specific directory that we will refer to as a
@ -175,14 +199,12 @@ and later will use it if necessary. However, once you've set a ``tahoe:``
alias with "``tahoe set-alias``", that will override anything in the old
``root_dir.cap`` file.
The Tahoe-LAFS CLI commands use a similar path syntax to ``scp`` and
The Tahoe-LAFS CLI commands use the same path syntax as ``scp`` and
``rsync`` -- an optional ``ALIAS:`` prefix, followed by the pathname or
filename. Some commands (like "``tahoe cp``") use the lack of an alias to
mean that you want to refer to a local file, instead of something from the
Tahoe-LAFS file store. Another way to indicate this is to start the
pathname with "./", "~/", "~username/", or "/". On Windows, aliases
cannot be a single character, so that it is possible to distinguish a
path relative to an alias from a path starting with a local drive specifier.
Tahoe-LAFS filesystem. Another way to indicate this is to start the
pathname with "./", "~/", "~username/", or "/".
When you're dealing a single starting directory, the ``tahoe:`` alias is
all you need. But when you want to refer to something that isn't yet
@ -331,7 +353,7 @@ Command Examples
``tahoe ls subdir``
This lists a subdirectory of your file store.
This lists a subdirectory of your filesystem.
``tahoe webopen``
@ -514,10 +536,10 @@ Command Examples
the pattern will be matched against any level of the directory tree;
it's still impossible to specify absolute path exclusions.
``tahoe backup --exclude-from-utf-8=/path/to/filename ~ work:backups``
``tahoe backup --exclude-from=/path/to/filename ~ work:backups``
``--exclude-from-utf-8`` is similar to ``--exclude``, but reads exclusion
patterns from a UTF-8-encoded ``/path/to/filename``, one per line.
``--exclude-from`` is similar to ``--exclude``, but reads exclusion
patterns from ``/path/to/filename``, one per line.
``tahoe backup --exclude-vcs ~ work:backups``
@ -608,6 +630,14 @@ into separate pieces. The most useful aspect of this command is to reveal the
storage index for any given URI. This can be used to locate the share files
that are holding the encoded+encrypted data for this file.
"``tahoe debug repl``" will launch an interactive Python interpreter in which
the Tahoe-LAFS packages and modules are available on ``sys.path`` (e.g. by using
'``import allmydata``'). This is most useful from a source tree: it simply sets
the PYTHONPATH correctly and runs the Python executable.
"``tahoe debug corrupt-share SHAREFILE``" will flip a bit in the given
sharefile. This can be used to test the client-side verification/repair code.
Obviously, this command should not be used during normal operation.
"``tahoe debug trial [OPTIONS] [TESTSUITE]``" will run the tests specified by
TESTSUITE (defaulting to the whole Tahoe test suite), using Twisted Trial.

View File

@ -1,20 +1,22 @@
.. -*- coding: utf-8-with-signature -*-
========================
Tahoe-LAFS SFTP Frontend
========================
=================================
Tahoe-LAFS SFTP and FTP Frontends
=================================
1. `SFTP Background`_
1. `SFTP/FTP Background`_
2. `Tahoe-LAFS Support`_
3. `Creating an Account File`_
4. `Configuring SFTP Access`_
5. `Dependencies`_
6. `Immutable and Mutable Files`_
7. `Known Issues`_
4. `Running An Account Server (accounts.url)`_
5. `Configuring SFTP Access`_
6. `Configuring FTP Access`_
7. `Dependencies`_
8. `Immutable and Mutable Files`_
9. `Known Issues`_
SFTP Background
===============
SFTP/FTP Background
===================
FTP is the venerable internet file-transfer protocol, first developed in
1971. The FTP server usually listens on port 21. A separate connection is
@ -31,24 +33,26 @@ Both FTP and SFTP were developed assuming a UNIX-like server, with accounts
and passwords, octal file modes (user/group/other, read/write/execute), and
ctime/mtime timestamps.
Previous versions of Tahoe-LAFS supported FTP, but now only the superior SFTP
frontend is supported. See `Known Issues`_, below, for details on the
limitations of SFTP.
We recommend SFTP over FTP, because the protocol is better, and the server
implementation in Tahoe-LAFS is more complete. See `Known Issues`_, below,
for details.
Tahoe-LAFS Support
==================
All Tahoe-LAFS client nodes can run a frontend SFTP server, allowing regular
SFTP clients (like ``/usr/bin/sftp``, the ``sshfs`` FUSE plugin, and many
others) to access the file store.
others) to access the virtual filesystem. They can also run an FTP server,
so FTP clients (like ``/usr/bin/ftp``, ``ncftp``, and others) can too. These
frontends sit at the same level as the web-API interface.
Since Tahoe-LAFS does not use user accounts or passwords, the SFTP
Since Tahoe-LAFS does not use user accounts or passwords, the SFTP/FTP
servers must be configured with a way to first authenticate a user (confirm
that a prospective client has a legitimate claim to whatever authorities we
might grant a particular user), and second to decide what directory cap
should be used as the root directory for a log-in by the authenticated user.
As of Tahoe-LAFS v1.17,
RSA/DSA public key authentication is the only supported mechanism.
A username and password can be used; as of Tahoe-LAFS v1.11, RSA or DSA
public key authentication is also supported.
Tahoe-LAFS provides two mechanisms to perform this user-to-cap mapping.
The first (recommended) is a simple flat file with one account per line.
@ -59,18 +63,51 @@ Creating an Account File
To use the first form, create a file (for example ``BASEDIR/private/accounts``)
in which each non-comment/non-blank line is a space-separated line of
(USERNAME, KEY-TYPE, PUBLIC-KEY, ROOTCAP), like so::
(USERNAME, PASSWORD, ROOTCAP), like so::
% cat BASEDIR/private/accounts
# This is a password line: username password cap
alice password URI:DIR2:ioej8xmzrwilg772gzj4fhdg7a:wtiizszzz2rgmczv4wl6bqvbv33ag4kvbr6prz3u6w3geixa6m6a
bob sekrit URI:DIR2:6bdmeitystckbl9yqlw7g56f4e:serp5ioqxnh34mlbmzwvkp3odehsyrr7eytt5f64we3k9hhcrcja
# This is a public key line: username keytype pubkey cap
# (Tahoe-LAFS v1.11 or later)
carol ssh-rsa AAAA... URI:DIR2:ovjy4yhylqlfoqg2vcze36dhde:4d4f47qko2xm5g7osgo2yyidi5m4muyo2vjjy53q4vjju2u55mfa
The key type may be either "ssh-rsa" or "ssh-dsa".
For public key authentication, the keytype may be either "ssh-rsa" or "ssh-dsa".
To avoid ambiguity between passwords and public key types, a password cannot
start with "ssh-".
Now add an ``accounts.file`` directive to your ``tahoe.cfg`` file, as described in
the next sections.
Running An Account Server (accounts.url)
========================================
The accounts.url directive allows access requests to be controlled by an
HTTP-based login service, useful for centralized deployments. This was used
by AllMyData to provide web-based file access, where the service used a
simple PHP script and database lookups to map an account email address and
password to a Tahoe-LAFS directory cap. The service will receive a
multipart/form-data POST, just like one created with a <form> and <input>
fields, with three parameters:
• action: "authenticate" (this is a static string)
• email: USERNAME (Tahoe-LAFS has no notion of email addresses, but the
authentication service uses them as account names, so the interface
presents this argument as "email" rather than "username").
• passwd: PASSWORD
It should return a single string that either contains a Tahoe-LAFS directory
cap (URI:DIR2:...), or "0" to indicate a login failure.
Tahoe-LAFS recommends the service be secure, preferably localhost-only. This
makes it harder for attackers to brute force the password or use DNS
poisoning to cause the Tahoe-LAFS gateway to talk with the wrong server,
thereby revealing the usernames and passwords.
Public key authentication is not supported when an account server is used.
Configuring SFTP Access
=======================
@ -136,24 +173,64 @@ clients and with the sshfs filesystem, see wiki:SftpFrontend_
.. _wiki:SftpFrontend: https://tahoe-lafs.org/trac/tahoe-lafs/wiki/SftpFrontend
Configuring FTP Access
======================
To enable the FTP server with an accounts file, add the following lines to
the BASEDIR/tahoe.cfg file::
[ftpd]
enabled = true
port = tcp:8021:interface=127.0.0.1
accounts.file = private/accounts
The FTP server will listen on the given port number and on the loopback
interface only. The "accounts.file" pathname will be interpreted relative to
the node's BASEDIR.
To enable the FTP server with an account server instead, provide the URL of
that server in an "accounts.url" directive::
[ftpd]
enabled = true
port = tcp:8021:interface=127.0.0.1
accounts.url = https://example.com/login
You can provide both accounts.file and accounts.url, although it probably
isn't very useful except for testing.
FTP provides no security, and so your password or caps could be eavesdropped
if you connect to the FTP server remotely. The examples above include
":interface=127.0.0.1" in the "port" option, which causes the server to only
accept connections from localhost.
Public key authentication is not supported for FTP.
Dependencies
============
The Tahoe-LAFS SFTP server requires the Twisted "Conch" component (a "conch"
is a twisted shell, get it?). Many Linux distributions package the Conch code
separately: debian puts it in the "python-twisted-conch" package.
separately: debian puts it in the "python-twisted-conch" package. Conch
requires the "pycrypto" package, which is a Python+C implementation of many
cryptographic functions (the debian package is named "python-crypto").
Note that "pycrypto" is different than the "pycryptopp" package that
Tahoe-LAFS uses (which is a Python wrapper around the C++ -based Crypto++
library, a library that is frequently installed as /usr/lib/libcryptopp.a, to
avoid problems with non-alphanumerics in filenames).
Immutable and Mutable Files
===========================
All files created via SFTP are immutable files. However, files can
All files created via SFTP (and FTP) are immutable files. However, files can
only be created in writeable directories, which allows the directory entry to
be relinked to a different file. Normally, when the path of an immutable file
is opened for writing by SFTP, the directory entry is relinked to another
file with the newly written contents when the file handle is closed. The old
file is still present on the grid, and any other caps to it will remain
valid. (See :doc:`../garbage-collection` for how to reclaim the space used by
files that are no longer needed.)
valid. (See `docs/garbage-collection.rst`_ for how to reclaim the space used
by files that are no longer needed.)
The 'no-write' metadata field of a directory entry can override this
behaviour. If the 'no-write' field holds a true value, then a permission
@ -170,6 +247,8 @@ directory, that link will become read-only.
If SFTP is used to write to an existing mutable file, it will publish a new
version when the file handle is closed.
.. _docs/garbage-collection.rst: file:../garbage-collection.rst
Known Issues
============
@ -186,3 +265,18 @@ See also wiki:SftpFrontend_.
.. _ticket #1059: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1059
.. _ticket #1089: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1089
Known Issues in the FTP Frontend
--------------------------------
Mutable files are not supported by the FTP frontend (`ticket #680`_).
Non-ASCII filenames are not supported by FTP (`ticket #682`_).
The FTP frontend sometimes fails to report errors, for example if an upload
fails because it does meet the "servers of happiness" threshold (`ticket
#1081`_).
.. _ticket #680: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/680
.. _ticket #682: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/682
.. _ticket #1081: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1081

View File

@ -0,0 +1,158 @@
.. -*- coding: utf-8-with-signature -*-
===============================
Tahoe-LAFS Drop-Upload Frontend
===============================
1. `Introduction`_
2. `Configuration`_
3. `Known Issues and Limitations`_
Introduction
============
The drop-upload frontend allows an upload to a Tahoe-LAFS grid to be triggered
automatically whenever a file is created or changed in a specific local
directory. This is a preview of a feature that we expect to support across
several platforms, but it currently works only on Linux.
The implementation was written as a prototype at the First International
Tahoe-LAFS Summit in June 2011, and is not currently in as mature a state as
the other frontends (web, CLI, SFTP and FTP). This means that you probably
should not keep important data in the upload directory, and should not rely
on all changes to files in the local directory to result in successful uploads.
There might be (and have been) incompatible changes to how the feature is
configured. There is even the possibility that it may be abandoned, for
example if unsolveable reliability issues are found.
We are very interested in feedback on how well this feature works for you, and
suggestions to improve its usability, functionality, and reliability.
Configuration
=============
The drop-upload frontend runs as part of a gateway node. To set it up, you
need to choose the local directory to monitor for file changes, and a mutable
directory on the grid to which files will be uploaded.
These settings are configured in the ``[drop_upload]`` section of the
gateway's ``tahoe.cfg`` file.
``[drop_upload]``
``enabled = (boolean, optional)``
If this is ``True``, drop-upload will be enabled. The default value is
``False``.
``local.directory = (UTF-8 path)``
This specifies the local directory to be monitored for new or changed
files. If the path contains non-ASCII characters, it should be encoded
in UTF-8 regardless of the system's filesystem encoding. Relative paths
will be interpreted starting from the node's base directory.
In addition, the file ``private/drop_upload_dircap`` must contain a
writecap pointing to an existing mutable directory to be used as the target
of uploads. It will start with ``URI:DIR2:``, and cannot include an alias
or path.
After setting the above fields and starting or restarting the gateway,
you can confirm that the feature is working by copying a file into the
local directory. Then, use the WUI or CLI to check that it has appeared
in the upload directory with the same filename. A large file may take some
time to appear, since it is only linked into the directory after the upload
has completed.
The 'Operational Statistics' page linked from the Welcome page shows
counts of the number of files uploaded, the number of change events currently
queued, and the number of failed uploads. The 'Recent Uploads and Downloads'
page and the node log_ may be helpful to determine the cause of any failures.
.. _log: ../logging.rst
Known Issues and Limitations
============================
This frontend only works on Linux. There is an even-more-experimental
implementation for Windows (`#1431`_), and a ticket to add support for
Mac OS X and BSD-based systems (`#1432`_).
Subdirectories of the local directory are not monitored. If a subdirectory
is created, it will be ignored. (`#1433`_)
If files are created or changed in the local directory just after the gateway
has started, it might not have connected to a sufficient number of servers
when the upload is attempted, causing the upload to fail. (`#1449`_)
Files that were created or changed in the local directory while the gateway
was not running, will not be uploaded. (`#1458`_)
The only way to determine whether uploads have failed is to look at the
'Operational Statistics' page linked from the Welcome page. This only shows
a count of failures, not the names of files. Uploads are never retried.
The drop-upload frontend performs its uploads sequentially (i.e. it waits
until each upload is finished before starting the next), even when there
would be enough memory and bandwidth to efficiently perform them in parallel.
A drop-upload can occur in parallel with an upload by a different frontend,
though. (`#1459`_)
If there are a large number of near-simultaneous file creation or
change events (greater than the number specified in the file
``/proc/sys/fs/inotify/max_queued_events``), it is possible that some events
could be missed. This is fairly unlikely under normal circumstances, because
the default value of ``max_queued_events`` in most Linux distributions is
16384, and events are removed from this queue immediately without waiting for
the corresponding upload to complete. (`#1430`_)
Some filesystems may not support the necessary change notifications.
So, it is recommended for the local directory to be on a directly attached
disk-based filesystem, not a network filesystem or one provided by a virtual
machine.
Attempts to read the mutable directory at about the same time as an uploaded
file is being linked into it, might fail, even if they are done through the
same gateway. (`#1105`_)
When a local file is changed and closed several times in quick succession,
it may be uploaded more times than necessary to keep the remote copy
up-to-date. (`#1440`_)
Files deleted from the local directory will not be unlinked from the upload
directory. (`#1710`_)
The ``private/drop_upload_dircap`` file cannot use an alias or path to
specify the upload directory. (`#1711`_)
Files are always uploaded as immutable. If there is an existing mutable file
of the same name in the upload directory, it will be unlinked and replaced
with an immutable file. (`#1712`_)
If a file in the upload directory is changed (actually relinked to a new
file), then the old file is still present on the grid, and any other caps to
it will remain valid. See `docs/garbage-collection.rst`_ for how to reclaim
the space used by files that are no longer needed.
Unicode names are supported, but the local name of a file must be encoded
correctly in order for it to be uploaded. The expected encoding is that
printed by ``python -c "import sys; print sys.getfilesystemencoding()"``.
.. _`#1105`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1105
.. _`#1430`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1430
.. _`#1431`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1431
.. _`#1432`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1432
.. _`#1433`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1433
.. _`#1440`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1440
.. _`#1449`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1449
.. _`#1458`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1458
.. _`#1459`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1459
.. _`#1710`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1710
.. _`#1711`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1711
.. _`#1712`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1712
.. _docs/garbage-collection.rst: ../garbage-collection.rst

View File

@ -71,8 +71,8 @@ port 3456, on the loopback (127.0.0.1) interface.
Basic Concepts: GET, PUT, DELETE, POST
======================================
As described in :doc:`../architecture`, each file and directory in a
Tahoe-LAFS file store is referenced by an identifier that combines the
As described in `docs/architecture.rst`_, each file and directory in a Tahoe
virtual filesystem is referenced by an identifier that combines the
designation of the object with the authority to do something with it (such as
read or modify the contents). This identifier is called a "read-cap" or
"write-cap", depending upon whether it enables read-only or read-write
@ -93,7 +93,7 @@ Other variations (generally implemented by adding query parameters to the
URL) will return information about the object, such as metadata. GET
operations are required to have no side-effects.
PUT is used to upload new objects into the file store, or to replace an
PUT is used to upload new objects into the filesystem, or to replace an
existing link or the contents of a mutable file. DELETE is used to unlink
objects from directories. Both PUT and DELETE are required to be idempotent:
performing the same operation multiple times must have the same side-effects
@ -107,12 +107,12 @@ unlinking), because otherwise a regular web browser has no way to accomplish
these tasks. In general, everything that can be done with a PUT or DELETE can
also be done with a POST.
Tahoe-LAFS' web API is designed for two different kinds of consumer. The
first is a program that needs to manipulate the file store. Such programs are
Tahoe's web API is designed for two different kinds of consumer. The first is
a program that needs to manipulate the virtual file system. Such programs are
expected to use the RESTful interface described above. The second is a human
using a standard web browser to work with the file store. This user is
presented with a series of HTML pages with links to download files, and forms
that use POST actions to upload, rename, and unlink files.
using a standard web browser to work with the filesystem. This user is given
a series of HTML pages with links to download files, and forms that use POST
actions to upload, rename, and unlink files.
When an error occurs, the HTTP response code will be set to an appropriate
400-series code (like 404 Not Found for an unknown childname, or 400 Bad Request
@ -128,6 +128,7 @@ a plain text stack trace instead. If the Accept header contains ``*/*``, or
be generated.
.. _RFC3986: https://tools.ietf.org/html/rfc3986
.. _docs/architecture.rst: ../architecture.rst
URLs
@ -192,12 +193,12 @@ servers is required, /uri should be used.
Child Lookup
------------
Tahoe directories contain named child entries, just like directories in a
regular local filesystem. These child entries, called "dirnodes", consist of
a name, metadata, a write slot, and a read slot. The write and read slots
normally contain a write-cap and read-cap referring to the same object, which
can be either a file or a subdirectory. The write slot may be empty
(actually, both may be empty, but that is unusual).
Tahoe directories contain named child entries, just like directories in a regular
local filesystem. These child entries, called "dirnodes", consist of a name,
metadata, a write slot, and a read slot. The write and read slots normally contain
a write-cap and read-cap referring to the same object, which can be either a file
or a subdirectory. The write slot may be empty (actually, both may be empty,
but that is unusual).
If you have a Tahoe URL that refers to a directory, and want to reference a
named child inside it, just append the child name to the URL. For example, if
@ -332,7 +333,7 @@ Programmatic Operations
=======================
Now that we know how to build URLs that refer to files and directories in a
Tahoe-LAFS file store, what sorts of operations can we do with those URLs?
Tahoe virtual filesystem, what sorts of operations can we do with those URLs?
This section contains a catalog of GET, PUT, DELETE, and POST operations that
can be performed on these URLs. This set of operations are aimed at programs
that use HTTP to communicate with a Tahoe node. A later section describes
@ -351,11 +352,11 @@ Reading a File
The "Range:" header can be used to restrict which portions of the file are
returned (see RFC 2616 section 14.35.1 "Byte Ranges"), however Tahoe only
supports a single "bytes" range and never provides a
``multipart/byteranges`` response. An attempt to begin a read past the end
of the file will provoke a 416 Requested Range Not Satisfiable error, but
normal overruns (reads which start at the beginning or middle and go beyond
the end) are simply truncated.
supports a single "bytes" range and never provides a `multipart/byteranges`
response. An attempt to begin a read past the end of the file will provoke a
416 Requested Range Not Satisfiable error, but normal overruns (reads which
start at the beginning or middle and go beyond the end) are simply
truncated.
To view files in a web browser, you may want more control over the
Content-Type and Content-Disposition headers. Please see the next section
@ -419,7 +420,7 @@ Writing/Uploading a File
``PUT /uri``
This uploads a file, and produces a file-cap for the contents, but does not
attach the file into the file store. No directories will be modified by
attach the file into the filesystem. No directories will be modified by
this operation. The file-cap is returned as the body of the HTTP response.
This method accepts format= and mutable=true as query string arguments, and
@ -435,7 +436,7 @@ Creating a New Directory
Create a new empty directory and return its write-cap as the HTTP response
body. This does not make the newly created directory visible from the
file store. The "PUT" operation is provided for backwards compatibility:
filesystem. The "PUT" operation is provided for backwards compatibility:
new code should use POST.
This supports a format= argument in the query string. The format=
@ -511,7 +512,7 @@ Creating a New Directory
The metadata may have a "no-write" field. If this is set to true in the
metadata of a link, it will not be possible to open that link for writing
via the SFTP frontend; see :doc:`FTP-and-SFTP` for details. Also, if the
via the SFTP frontend; see FTP-and-SFTP.rst_ for details. Also, if the
"no-write" field is set to true in the metadata of a link to a mutable
child, it will cause the link to be diminished to read-only.
@ -670,6 +671,8 @@ Creating a New Directory
This operation will return an error if the parent directory is immutable,
or already has a child named NAME.
.. _FTP-and-SFTP.rst: FTP-and-SFTP.rst
Getting Information About a File Or Directory (as JSON)
-------------------------------------------------------
@ -807,8 +810,8 @@ child is set. The value of the 'tahoe':'linkcrtime' key is updated whenever
a link to a child is created -- i.e. when there was not previously a link
under that name.
Note however, that if the edge in the Tahoe-LAFS file store points to a
mutable file and the contents of that mutable file is changed, then the
Note however, that if the edge in the Tahoe filesystem points to a mutable
file and the contents of that mutable file is changed, then the
'tahoe':'linkmotime' value on that edge will *not* be updated, since the
edge itself wasn't updated -- only the mutable file was.
@ -835,8 +838,8 @@ The reason we added the new fields in Tahoe v1.4.0 is that there is a
values of the 'mtime'/'ctime' pair, and this API is used by the
"tahoe backup" command (in Tahoe v1.3.0 and later) to set the 'mtime' and
'ctime' values when backing up files from a local filesystem into the
Tahoe-LAFS file store. As of Tahoe v1.4.0, the set_children API cannot be
used to set anything under the 'tahoe' key of the metadata dict -- if you
Tahoe filesystem. As of Tahoe v1.4.0, the set_children API cannot be used
to set anything under the 'tahoe' key of the metadata dict -- if you
include 'tahoe' keys in your 'metadata' arguments then it will silently
ignore those keys.
@ -864,8 +867,8 @@ When an edge is created or updated by "tahoe backup", the 'mtime' and
There are several ways that the 'ctime' field could be confusing:
1. You might be confused about whether it reflects the time of the creation
of a link in the Tahoe-LAFS file store (by a version of Tahoe < v1.7.0)
or a timestamp copied in by "tahoe backup" from a local filesystem.
of a link in the Tahoe filesystem (by a version of Tahoe < v1.7.0) or a
timestamp copied in by "tahoe backup" from a local filesystem.
2. You might be confused about whether it is a copy of the file creation
time (if "tahoe backup" was run on a Windows system) or of the last
@ -895,7 +898,7 @@ Attaching an Existing File or Directory by its read- or write-cap
``PUT /uri/$DIRCAP/[SUBDIRS../]CHILDNAME?t=uri``
This attaches a child object (either a file or directory) to a specified
location in the Tahoe-LAFS file store. The child object is referenced by its
location in the virtual filesystem. The child object is referenced by its
read- or write- cap, as provided in the HTTP request body. This will create
intermediate directories as necessary.
@ -1008,9 +1011,9 @@ Browser Operations: Human-oriented interfaces
This section describes the HTTP operations that provide support for humans
running a web browser. Most of these operations use HTML forms that use POST
to drive the Tahoe-LAFS node. This section is intended for HTML authors who
want to write web pages containing user interfaces for manipulating the
Tahoe-LAFS file store.
to drive the Tahoe node. This section is intended for HTML authors who want
to write web pages that contain forms and buttons which manipulate the Tahoe
filesystem.
Note that for all POST operations, the arguments listed can be provided
either as URL query arguments or as form body fields. URL query arguments are
@ -1040,30 +1043,15 @@ Viewing/Downloading a File
``GET /uri/$DIRCAP/[SUBDIRS../]FILENAME``
``GET /named/$FILECAP/FILENAME``
These will retrieve the contents of the given file. The HTTP response body
This will retrieve the contents of the given file. The HTTP response body
will contain the sequence of bytes that make up the file.
The ``/named/`` form is an alternative to ``/uri/$FILECAP`` which makes it
easier to get the correct filename. The Tahoe server will provide the
contents of the given file, with a Content-Type header derived from the
given filename. This form is used to get browsers to use the "Save Link As"
feature correctly, and also helps command-line tools like "wget" and "curl"
use the right filename. Note that this form can *only* be used with file
caps; it is an error to use a directory cap after the /named/ prefix.
URLs may also use /file/$FILECAP/FILENAME as a synonym for
/named/$FILECAP/FILENAME. The use of "/file/" is deprecated in favor of
"/named/" and support for "/file/" will be removed in a future release of
Tahoe-LAFS.
If you use the first form (``/uri/$FILECAP``) and want the HTTP response to
include a useful Content-Type header, add a "filename=foo" query argument,
like "GET /uri/$FILECAP?filename=foo.jpg". The bare "GET /uri/$FILECAP" does
not give the Tahoe node enough information to determine a Content-Type
(since LAFS immutable files are merely sequences of bytes, not typed and
named file objects).
If you want the HTTP response to include a useful Content-Type header,
either use the second form (which starts with a $DIRCAP), or add a
"filename=foo" query argument, like "GET /uri/$FILECAP?filename=foo.jpg".
The bare "GET /uri/$FILECAP" does not give the Tahoe node enough information
to determine a Content-Type (since Tahoe immutable files are merely
sequences of bytes, not typed+named file objects).
If the URL has both filename= and "save=true" in the query arguments, then
the server to add a "Content-Disposition: attachment" header, along with a
@ -1072,12 +1060,25 @@ Viewing/Downloading a File
most browsers will refuse to display it inline). "true", "t", "1", and other
case-insensitive equivalents are all treated the same.
Character-set handling in URLs and HTTP headers is a :ref:`dubious
art<urls-and-utf8>`. For maximum compatibility, Tahoe simply copies the
bytes from the filename= argument into the Content-Disposition header's
filename= parameter, without trying to interpret them in any particular way.
Character-set handling in URLs and HTTP headers is a dubious art [1]_. For
maximum compatibility, Tahoe simply copies the bytes from the filename=
argument into the Content-Disposition header's filename= parameter, without
trying to interpret them in any particular way.
``GET /named/$FILECAP/FILENAME``
This is an alternate download form which makes it easier to get the correct
filename. The Tahoe server will provide the contents of the given file, with
a Content-Type header derived from the given filename. This form is used to
get browsers to use the "Save Link As" feature correctly, and also helps
command-line tools like "wget" and "curl" use the right filename. Note that
this form can *only* be used with file caps; it is an error to use a
directory cap after the /named/ prefix.
URLs may also use /file/$FILECAP/FILENAME as a synonym for
/named/$FILECAP/FILENAME.
Getting Information About a File Or Directory (as HTML)
-------------------------------------------------------
@ -1107,8 +1108,8 @@ Creating a Directory
``POST /uri?t=mkdir``
This creates a new empty directory, but does not attach it to any other
directory in the Tahoe-LAFS file store.
This creates a new empty directory, but does not attach it to the virtual
filesystem.
If a "redirect_to_result=true" argument is provided, then the HTTP response
will cause the web browser to be redirected to a /uri/$DIRCAP page that
@ -1150,8 +1151,8 @@ Uploading a File
``POST /uri?t=upload``
This uploads a file, and produces a file-cap for the contents, but does not
attach the file to any directory in the Tahoe-LAFS file store. That is, no
directories will be modified by this operation.
attach the file into the filesystem. No directories will be modified by
this operation.
The file must be provided as the "file" field of an HTML encoded form body,
produced in response to an HTML form like this::
@ -1312,9 +1313,9 @@ Relinking ("Moving") a Child
is still reachable through any path from which it was formerly reachable,
and the storage space occupied by its ciphertext is not affected.
The source and destination directories must be writeable. If ``to_dir`` is
The source and destination directories must be writeable. If {{{to_dir}}} is
not present, the child link is renamed within the same directory. If
``to_name`` is not present then it defaults to ``from_name``. If the
{{{to_name}}} is not present then it defaults to {{{from_name}}}. If the
destination link (directory and name) is the same as the source link, the
operation has no effect.
@ -1423,7 +1424,7 @@ mainly intended for developers.
True. For distributed files, this dictionary has the following
keys:
count-happiness: the servers-of-happiness level of the file, as
defined in doc/specifications/servers-of-happiness.
defined in `docs/specifications/servers-of-happiness.rst`_.
count-shares-good: the number of good shares that were found
count-shares-needed: 'k', the number of shares required for recovery
count-shares-expected: 'N', the number of total shares generated
@ -1469,9 +1470,10 @@ mainly intended for developers.
'seq%d-%s-sh%d', containing the sequence number, the
roothash, and the share number.
Before Tahoe-LAFS v1.11, the ``results`` dictionary also had a
``needs-rebalancing`` field, but that has been removed since it was computed
incorrectly.
Before Tahoe-LAFS v1.11, the `results` dictionary also had a `needs-rebalancing`
field, but that has been removed since it was computed incorrectly.
.. _`docs/specifications/servers-of-happiness.rst`: ../specifications/servers-of-happiness.rst
``POST $URL?t=start-deep-check`` (must add &ophandle=XYZ)
@ -1699,7 +1701,7 @@ incorrectly.
for debugging. This is a table of (path, filecap/dircap), for every object
reachable from the starting directory. The path will be slash-joined, and
the filecap/dircap will contain a link to the object in question. This page
gives immediate access to every object in the file store subtree.
gives immediate access to every object in the virtual filesystem subtree.
This operation uses the same ophandle= mechanism as deep-check. The
corresponding /operations/$HANDLE page has three different forms. The
@ -1751,9 +1753,6 @@ incorrectly.
keys may be missing until 'finished' is True)::
finished: (bool) True if the operation has finished, else False
api-version: (int), number of deep-stats API version. Will be increased every
time backwards-incompatible change is introduced.
Current version is 1.
count-immutable-files: count of how many CHK files are in the set
count-mutable-files: same, for mutable files (does not include directories)
count-literal-files: same, for LIT files (data contained inside the URI)
@ -1833,9 +1832,9 @@ Other Useful Pages
==================
The portion of the web namespace that begins with "/uri" (and "/named") is
dedicated to giving users (both humans and programs) access to the Tahoe-LAFS
file store. The rest of the namespace provides status information about the
state of the Tahoe-LAFS node.
dedicated to giving users (both humans and programs) access to the Tahoe
virtual filesystem. The rest of the namespace provides status information
about the state of the Tahoe node.
``GET /`` (the root page)
@ -1843,47 +1842,13 @@ This is the "Welcome Page", and contains a few distinct sections::
Node information: library versions, local nodeid, services being provided.
File store access forms: create a new directory, view a file/directory by
Filesystem Access Forms: create a new directory, view a file/directory by
URI, upload a file (unlinked), download a file by
URI.
Grid status: introducer information, helper information, connected storage
Grid Status: introducer information, helper information, connected storage
servers.
``GET /?t=json`` (the json welcome page)
This is the "json Welcome Page", and contains connectivity status
of the introducer(s) and storage server(s), here's an example::
{
"introducers": {
"statuses": []
},
"servers": [{
"nodeid": "other_nodeid",
"available_space": 123456,
"nickname": "George \u263b",
"version": "1.0",
"connection_status": "summary",
"last_received_data": 1487811257
}]
}
The above json ``introducers`` section includes a list of
introducer connectivity status messages.
The above json ``servers`` section is an array with map elements. Each map
has the following properties:
1. ``nodeid`` - an identifier derived from the node's public key
2. ``available_space`` - the available space in bytes expressed as an integer
3. ``nickname`` - the storage server nickname
4. ``version`` - the storage server Tahoe-LAFS version
5. ``connection_status`` - connectivity status
6. ``last_received_data`` - the time when data was last received,
expressed in seconds since epoch
``GET /status/``
This page lists all active uploads and downloads, and contains a short list
@ -2028,25 +1993,23 @@ Safety and Security Issues -- Names vs. URIs
============================================
Summary: use explicit file- and dir- caps whenever possible, to reduce the
potential for surprises when the file store structure is changed.
potential for surprises when the filesystem structure is changed.
Tahoe-LAFS provides a mutable file store, but the ways that the store can
change are limited. The only things that can change are:
Tahoe provides a mutable filesystem, but the ways that the filesystem can
change are limited. The only thing that can change is that the mapping from
child names to child objects that each directory contains can be changed by
adding a new child name pointing to an object, removing an existing child name,
or changing an existing child name to point to a different object.
* the mapping from child names to child objects inside mutable directories
(by adding a new child, removing an existing child, or changing an
existing child to point to a different object)
* the contents of mutable files
Obviously if you query for information about the file store and then act
to change it (such as by getting a listing of the contents of a mutable
directory and then adding a file to the directory), then the store might
have been changed after you queried it and before you acted upon it.
However, if you use the URI instead of the pathname of an object when you
act upon the object, then it will be the same object; only its contents
can change (if it is mutable). If, on the other hand, you act upon the
object using its pathname, then a different object might be in that place,
which can result in more kinds of surprises.
Obviously if you query Tahoe for information about the filesystem and then act
to change the filesystem (such as by getting a listing of the contents of a
directory and then adding a file to the directory), then the filesystem might
have been changed after you queried it and before you acted upon it. However,
if you use the URI instead of the pathname of an object when you act upon the
object, then the only change that can happen is if the object is a directory
then the set of child names it has might be different. If, on the other hand,
you act upon the object using its pathname, then a different object might be in
that place, which can result in more kinds of surprises.
For example, suppose you are writing code which recursively downloads the
contents of a directory. The first thing your code does is fetch the listing
@ -2054,14 +2017,15 @@ of the contents of the directory. For each child that it fetched, if that
child is a file then it downloads the file, and if that child is a directory
then it recurses into that directory. Now, if the download and the recurse
actions are performed using the child's name, then the results might be
wrong, because for example a child name that pointed to a subdirectory when
wrong, because for example a child name that pointed to a sub-directory when
you listed the directory might have been changed to point to a file (in which
case your attempt to recurse into it would result in an error), or a child
name that pointed to a file when you listed the directory might now point to
a subdirectory (in which case your attempt to download the child would result
in a file containing HTML text describing the subdirectory!).
case your attempt to recurse into it would result in an error and the file
would be skipped), or a child name that pointed to a file when you listed the
directory might now point to a sub-directory (in which case your attempt to
download the child would result in a file containing HTML text describing the
sub-directory!).
If your recursive algorithm uses the URI of the child instead of the name of
If your recursive algorithm uses the uri of the child instead of the name of
the child, then those kinds of mistakes just can't happen. Note that both the
child's name and the child's URI are included in the results of listing the
parent directory, so it isn't any harder to use the URI for this purpose.
@ -2121,7 +2085,9 @@ Tahoe-1.1; back with Tahoe-1.0 the web client was responsible for serializing
web requests themselves).
For more details, please see the "Consistency vs Availability" and "The Prime
Coordination Directive" sections of :doc:`../specifications/mutable`.
Coordination Directive" sections of mutable.rst_.
.. _mutable.rst: ../specifications/mutable.rst
Access Blacklist
@ -2146,7 +2112,7 @@ you could do the following::
tahoe debug dump-cap URI:CHK:n7r3m6wmomelk4sep3kw5cvduq:os7ijw5c3maek7pg65e5254k2fzjflavtpejjyhshpsxuqzhcwwq:3:20:14861
-> storage index: whpepioyrnff7orecjolvbudeu
echo "whpepioyrnff7orecjolvbudeu my puppy told me to" >>$NODEDIR/access.blacklist
# ... restart the node to re-read configuration ...
tahoe restart $NODEDIR
tahoe get URI:CHK:n7r3m6wmomelk4sep3kw5cvduq:os7ijw5c3maek7pg65e5254k2fzjflavtpejjyhshpsxuqzhcwwq:3:20:14861
-> error, 403 Access Prohibited: my puppy told me to
@ -2158,7 +2124,7 @@ When modifying the file, be careful to update it atomically, otherwise a
request may arrive while the file is only halfway written, and the partial
file may be incorrectly parsed.
The blacklist is applied to all access paths (including SFTP and CLI
The blacklist is applied to all access paths (including SFTP, FTP, and CLI
operations), not just the web-API. The blacklist also applies to directories.
If a directory is blacklisted, the gateway will refuse access to both that
directory and any child files/directories underneath it, when accessed via
@ -2168,10 +2134,8 @@ file/dir will bypass the blacklist.
The node will log the SI of the file being blocked, and the reason code, into
the ``logs/twistd.log`` file.
URLs and HTTP and UTF-8
=======================
.. _urls-and-utf8:
.. [1] URLs and HTTP and UTF-8, Oh My
HTTP does not provide a mechanism to specify the character set used to
encode non-ASCII names in URLs (`RFC3986#2.1`_). We prefer the convention
@ -2230,3 +2194,4 @@ URLs and HTTP and UTF-8
.. _RFC2231#4: https://tools.ietf.org/html/rfc2231#section-4
.. _some developers have reported: http://markmail.org/message/dsjyokgl7hv64ig3
.. _RFC2616#19.5.1: https://tools.ietf.org/html/rfc2616#section-19.5.1

View File

@ -13,7 +13,7 @@ Garbage Collection in Tahoe
Overview
========
When a file or directory in a Tahoe-LAFS file store is no longer referenced,
When a file or directory in the virtual filesystem is no longer referenced,
the space that its shares occupied on each storage server can be freed,
making room for other shares. Tahoe currently uses a garbage collection
("GC") mechanism to implement this space-reclamation process. Each share has
@ -30,11 +30,7 @@ next renewal pass.
There are several tradeoffs to be considered when choosing the renewal timer
and the lease duration, and there is no single optimal pair of values. See
the following diagram to get an idea of the tradeoffs involved:
.. image:: lease-tradeoffs.svg
the lease-tradeoffs.svg_ diagram to get an idea for the tradeoffs involved.
If lease renewal occurs quickly and with 100% reliability, than any renewal
time that is shorter than the lease duration will suffice, but a larger ratio
of duration-over-renewal-time will be more robust in the face of occasional
@ -50,6 +46,7 @@ processed) to something other than 31 days.
Renewing leases can be expected to take about one second per file/directory,
depending upon the number of servers and the network speeds involved.
.. _lease-tradeoffs.svg: lease-tradeoffs.svg
Client-side Renewal

View File

@ -1,18 +0,0 @@
Preparing to Authenticate Release (Setting up GPG)
--------------------------------------------------
In other to keep releases authentic it's required that releases are signed before being
published. This ensure's that users of Tahoe are able to verify that the version of Tahoe
they are using is coming from a trusted or at the very least known source.
The authentication is done using the ``GPG`` implementation of ``OpenGPG`` to be able to complete
the release steps you would have to download the ``GPG`` software and setup a key(identity).
- `Download <https://www.gnupg.org/download/>`__ and install GPG for your operating system.
- Generate a key pair using ``gpg --gen-key``. *Some questions would be asked to personalize your key configuration.*
You might take additional steps including:
- Setting up a revocation certificate (Incase you lose your secret key)
- Backing up your key pair
- Upload your fingerprint to a keyserver such as `openpgp.org <https://keys.openpgp.org/>`__

View File

@ -13,12 +13,14 @@ Overview
========
As described in the "Swarming Download, Trickling Upload" section of
:doc:`architecture`, Tahoe uploads require more bandwidth than downloads: you
`architecture.rst`_, Tahoe uploads require more bandwidth than downloads: you
must push the redundant shares during upload, but you do not need to retrieve
them during download. With the default 3-of-10 encoding parameters, this
means that an upload will require about 3.3x the traffic as a download of the
same file.
.. _architecture.rst: architecture.rst
Unfortunately, this "expansion penalty" occurs in the same upstream direction
that most consumer DSL lines are slow anyways. Typical ADSL lines get 8 times
as much download capacity as upload capacity. When the ADSL upstream penalty
@ -122,7 +124,7 @@ Who should consider using a Helper?
* clients who experience problems with TCP connection fairness: if other
programs or machines in the same home are getting less than their fair
share of upload bandwidth. If the connection is being shared fairly, then
a Tahoe upload that is happening at the same time as a single SFTP upload
a Tahoe upload that is happening at the same time as a single FTP upload
should get half the bandwidth.
* clients who have been given the helper.furl by someone who is running a
Helper and is willing to let them use it
@ -130,7 +132,9 @@ Who should consider using a Helper?
To take advantage of somebody else's Helper, take the helper furl that they
give you, and edit your tahoe.cfg file. Enter the helper's furl into the
value of the key "helper.furl" in the "[client]" section of tahoe.cfg, as
described in the "Client Configuration" section of :doc:`configuration`.
described in the "Client Configuration" section of configuration.rst_.
.. _configuration.rst: configuration.rst
Then restart the node. This will signal the client to try and connect to the
helper. Subsequent uploads will use the helper rather than using direct

View File

@ -20,10 +20,10 @@ Config setting File Comment
``[node]log_gatherer.furl`` ``BASEDIR/log_gatherer.furl`` (one per line)
``[node]timeout.keepalive`` ``BASEDIR/keepalive_timeout``
``[node]timeout.disconnect`` ``BASEDIR/disconnect_timeout``
``BASEDIR/introducer.furl`` ``BASEDIR/private/introducers.yaml``
``[client]introducer.furl`` ``BASEDIR/introducer.furl``
``[client]helper.furl`` ``BASEDIR/helper.furl``
``[client]key_generator.furl`` ``BASEDIR/key_generator.furl``
``BASEDIR/stats_gatherer.furl`` Stats gatherer has been removed.
``[client]stats_gatherer.furl`` ``BASEDIR/stats_gatherer.furl``
``[storage]enabled`` ``BASEDIR/no_storage`` (``False`` if ``no_storage`` exists)
``[storage]readonly`` ``BASEDIR/readonly_storage`` (``True`` if ``readonly_storage`` exists)
``[storage]sizelimit`` ``BASEDIR/sizelimit``
@ -47,10 +47,3 @@ the now (since Tahoe-LAFS v1.3.0) unsupported
addresses specified in ``advertised_ip_addresses`` were used in
addition to any that were automatically discovered), whereas the new
``tahoe.cfg`` directive is not (``tub.location`` is used verbatim).
The stats gatherer has been broken at least since Tahoe-LAFS v1.13.0.
The (broken) functionality of ``[client]stats_gatherer.furl`` (which
was previously in ``BASEDIR/stats_gatherer.furl``), is scheduled to be
completely removed after Tahoe-LAFS v1.15.0. After that point, if
your configuration contains a ``[client]stats_gatherer.furl``, your
node will refuse to start.

View File

@ -177,7 +177,7 @@ mutable files, you may be able to avoid the potential for "rollback"
failure.
A future version of Tahoe will include a fix for this issue. Here is
[https://lists.tahoe-lafs.org/pipermail/tahoe-dev/2008-May/000628.html the
[https://tahoe-lafs.org/pipermail/tahoe-dev/2008-May/000630.html the
mailing list discussion] about how that future version will work.
@ -272,3 +272,22 @@ that size, assume that they have been corrupted and are not retrievable from the
Tahoe storage grid. Tahoe v1.1 clients will refuse to upload files larger than
12 GiB with a clean failure. A future release of Tahoe will remove this
limitation so that larger files can be uploaded.
=== pycryptopp defect resulting in data corruption ===
Versions of pycryptopp earlier than pycryptopp-0.5.0 had a defect
which, when compiled with some compilers, would cause AES-256
encryption and decryption to be computed incorrectly. This could
cause data corruption. Tahoe v1.0 required, and came with a bundled
copy of, pycryptopp v0.3.
==== how to manage it ====
You can detect whether pycryptopp-0.3 has this failure when it is
compiled by your compiler. Run the unit tests that come with
pycryptopp-0.3: unpack the "pycryptopp-0.3.tar" file that comes in the
Tahoe v1.0 {{{misc/dependencies}}} directory, cd into the resulting
{{{pycryptopp-0.3.0}}} directory, and execute {{{python ./setup.py
test}}}. If the tests pass, then your compiler does not trigger this
failure.

View File

@ -0,0 +1,80 @@
* Tahoe Release Checklist [0/19]
- [ ] NEWS.rst: summarize user-visible changes, aim for one page of text
- [ ] update doc files
- NEWS.rst: Add final release name and date to top-most item in NEWS.
- relnotes.txt
- CREDITS
- docs/known_issues.rst
- [ ] change docs/quickstart.rst to point to just the current
allmydata-tahoe-X.Y.Z.zip source code file, or else to point to a
directory which contains only allmydata-tahoe-X.Y.Z.* source code files
- [ ] git pull
- [ ] git tag -s -u 68666A7A allmydata-tahoe-X.Y.Z
- produces a "signed tag"
- tag body: allmydata-tahoe-X.Y.Z
- [ ] build locally to make sure the release is reporting itself as the
intended version
- [ ] make sure buildbot is green
- [ ] make sure other people aren't committing at that moment
- [ ] push tag to trigger buildslaves. Making a code change is no longer
necessary
- git push official master TAGNAME
- that will build tarballs
- [ ] make sure buildbot is green
- [ ] make sure a sumo sdist tarball got built and uploaded properly
- [ ] download tarballs, sign with "gpg -ba -u 68666a7a TAR", upload *.asc
- [ ] symlink the release tarball on tahoe-lafs.org:
/var/www/source/tahoe-lafs/releases/
- [ ] update Wiki: front page news, news, old news, parade of release
notes ("Doc"), Installation
- [ ] send out relnotes.txt:
- modify to include hashes of tarballs, git revision
- GPG-sign the email
- send to tahoe-announce@tahoe-lafs.org and tahoe-dev@tahoe-lafs.org
- [ ] update https://tahoe-lafs.org/hacktahoelafs/
- [ ] update pypi:
- python setup.py register
- login to pypi
- manually upload .tar.gz tarball and .asc signature (so they match the
ones on tahoe-lafs.org), or use https://pypi.python.org/pypi/twine and
run "twine upload *.tar.gz *.asc"
- [ ] close the Milestone on the trac Roadmap
- [ ] make an "announcement of new release" on freshmeat
- [ ] make an "announcement of new release" on launchpad
- [ ] send out relnotes.txt to:
- p2p-hackers@lists.zooko.com
- lwn@lwn.net
- a Google+ page
- cap-talk@mail.eros-os.org
- cryptography@metzdown.com
- cryptography@randombit.net
- twisted-python@twistedmatrix.com
- owncloud@kde.org
- liberationtech@lists.stanford.edu
- the "decentralization" group on groups.yahoo.com
- pycrypto mailing list
- fuse-devel@lists.sourceforge.net
- fuse-sshfs@lists.sourceforge.net
- duplicity-talk@nongnu.org
- news@phoronix.com
- python-list@python.org
- cygwin@cygwin.com
- The Boulder Linux Users' Group
- The Boulder Hackerspace mailing list
- cryptopp-users@googlegroups.com
- tiddlywiki
- hdfs-dev@hadoop.apache.org
- bzr
- mercurial
- http://listcultures.org/pipermail/p2presearch_listcultures.org/
- deltacloud
- libcloud
- swift@lists.launchpad.net
- stephen@fosketts.net
- Chris Mellor of The Register
- nosql@mypopescu.com
- The H Open
- fans/customers of cleversafe
- fans/customers of bitcasa
- fans/customers of wuala
- fans/customers of spideroak

View File

@ -1,72 +0,0 @@
Tahoe-LAFS
==========
.. Please view a nicely formatted version of this documentation at
http://tahoe-lafs.readthedocs.io/en/latest/
Contents:
.. toctree::
:maxdepth: 2
about-tahoe
Installation/install-tahoe
Installation/install-on-windows
Installation/install-on-linux
Installation/install-on-desert-island
running
magic-wormhole-invites
configuration
architecture
frontends/CLI
frontends/webapi
frontends/FTP-and-SFTP
frontends/download-status
known_issues
contributing
CODE_OF_CONDUCT
release-checklist
gpg-setup
servers
managed-grid
helper
convergence-secret
garbage-collection
backdoors
donations
accepting-donations
expenses
cautions
write_coordination
backupdb
developer-guide
ticket-triage
anonymity-configuration
nodekeys
performance
logging
stats
debian
build/build-pyOpenSSL
specifications/index
proposed/index
filesystem-notes
historical/configuration
key-value-store
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -1,9 +1,5 @@
.. -*- coding: utf-8-with-signature-unix; fill-column: 77 -*-
********************************
Using Tahoe as a key-value store
********************************
There are several ways you could use Tahoe-LAFS as a key-value store.
Looking only at things that are *already implemented*, there are three
@ -26,7 +22,7 @@ options:
This is spelled "`GET /uri/$FILECAP`_" in the API. "$FILECAP" is the
key.
For details, see "immutable files" in :doc:`performance`, but in summary:
For details, see "immutable files" in `performance.rst`_, but in summary:
the performance is not great but not bad.
That document doesn't mention that if the size of the A-byte mutable file
@ -57,7 +53,7 @@ options:
change what value you get when you read) depends on the type of the
key.
Again, for details, see "mutable files" in :doc:`performance` (and
Again, for details, see "mutable files" in `performance.rst`_ (and
`these tickets`_ about how that doc is incomplete), but in summary, the
performance of the create() operation is *terrible*! (It involves
generating a 2048-bit RSA key pair.) The performance of the set and get
@ -71,7 +67,7 @@ options:
This is spelled "`POST /uri?t=mkdir`_".
:doc:`performance` does not mention directories (`#2228`_), but in order
`performance.rst`_ does not mention directories (`#2228`_), but in order
to understand the performance of directories you have to understand how
they are implemented. Mkdir creates a new mutable file, exactly the
same, and with exactly the same performance, as the "create() mutable"
@ -134,6 +130,8 @@ sqlite db in a Tahoe-LAFS mutable". ☺
.. _PUT /uri?format=mdmf: https://tahoe-lafs.org/trac/tahoe-lafs/browser/trunk/docs/frontends/webapi.rst#writing-uploading-a-file
.. _performance.rst: https://tahoe-lafs.org/trac/tahoe-lafs/browser/trunk/docs/performance.rst
.. _#2226: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2226
.. _these tickets: https://tahoe-lafs.org/trac/tahoe-lafs/query?status=assigned&status=new&status=reopened&keywords=~doc&description=~performance.rst&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=milestone&order=priority

View File

@ -1,6 +1,8 @@
.. -*- coding: utf-8-with-signature -*-
See also :doc:`cautions.rst<cautions>`.
See also `cautions.rst`_.
.. _cautions.rst: cautions.rst
============
Known Issues
@ -8,22 +10,23 @@ Known Issues
Below is a list of known issues in recent releases of Tahoe-LAFS, and how to
manage them. The current version of this file can be found at
https://github.com/tahoe-lafs/tahoe-lafs/blob/master/docs/known_issues.rst .
https://tahoe-lafs.org/source/tahoe-lafs/trunk/docs/known_issues.rst .
If you've been using Tahoe-LAFS since v1.1 (released 2008-06-11) or if you're
just curious about what sort of mistakes we've made in the past, then you
might want to read the "historical known issues" document in
``docs/historical/historical_known_issues.txt``.
just curious about what sort of mistakes we've made in the past, then you might
want to read `the "historical known issues" document`_.
.. _the "historical known issues" document: historical/historical_known_issues.txt
Known Issues in Tahoe-LAFS v1.10.3, released 30-Mar-2016
Known Issues in Tahoe-LAFS v1.10.1, released 15-Jun-2015
========================================================
* `Unauthorized access by JavaScript in unrelated files`_
* `Disclosure of file through embedded hyperlinks or JavaScript in that file`_
* `Command-line arguments are leaked to other local users`_
* `Capabilities may be leaked to web browser phishing filter / "safe browsing" servers`_
* `Known issues in the SFTP frontend`_
* `Known issues in the FTP and SFTP frontends`_
* `Traffic analysis based on sizes of files/directories, storage indices, and timing`_
* `Privacy leak via Google Chart API link in map-update timing web page`_
@ -213,12 +216,12 @@ To disable the filter in Chrome:
----
Known issues in the SFTP frontend
---------------------------------
Known issues in the FTP and SFTP frontends
------------------------------------------
These are documented in :doc:`frontends/FTP-and-SFTP` and on `the
SftpFrontend page`_ on the wiki.
These are documented in `docs/frontends/FTP-and-SFTP.rst`_ and on `the SftpFrontend page`_ on the wiki.
.. _docs/frontends/FTP-and-SFTP.rst: frontends/FTP-and-SFTP.rst
.. _the SftpFrontend page: https://tahoe-lafs.org/trac/tahoe-lafs/wiki/SftpFrontend

View File

@ -13,8 +13,9 @@ Tahoe Logging
1. `Incident Gatherer`_
2. `Log Gatherer`_
6. `Adding log messages`_
7. `Log Messages During Unit Tests`_
6. `Local twistd.log files`_
7. `Adding log messages`_
8. `Log Messages During Unit Tests`_
Overview
========
@ -25,11 +26,18 @@ primarily for use by programmers and grid operators who want to find out what
went wrong.
The Foolscap logging system is documented at
`<https://github.com/warner/foolscap/blob/latest-release/doc/logging.rst>`__.
`<http://foolscap.lothar.com/docs/logging.html>`__.
The Foolscap distribution includes a utility named "``flogtool``" that is
used to get access to many Foolscap logging features. ``flogtool`` should get
installed into the same virtualenv as the ``tahoe`` command.
used to get access to many Foolscap logging features. This command only
works when foolscap and its dependencies are installed correctly.
Tahoe-LAFS v1.10.0 and later include a ``tahoe debug flogtool`` command
that can be used even when foolscap is not installed; to use this, prefix
all of the example commands below with ``tahoe debug``.
For earlier versions since Tahoe-LAFS v1.8.2, installing Foolscap v0.6.1
or later and then running ``bin/tahoe @flogtool`` from the root of a
Tahoe-LAFS source distribution may work (but only on Unix, not Windows).
Realtime Logging
@ -128,9 +136,10 @@ provided in ``misc/incident-gatherer/support_classifiers.py`` . There is
roughly one category for each ``log.WEIRD``-or-higher level event in the
Tahoe source code.
The incident gatherer is created with the "``flogtool create-incident-gatherer
WORKDIR``" command, and started with "``tahoe run``". The generated
"``gatherer.tac``" file should be modified to add classifier functions.
The incident gatherer is created with the "``flogtool
create-incident-gatherer WORKDIR``" command, and started with "``tahoe
start``". The generated "``gatherer.tac``" file should be modified to add
classifier functions.
The incident gatherer writes incident names (which are simply the relative
pathname of the ``incident-\*.flog.bz2`` file) into ``classified/CATEGORY``.
@ -174,10 +183,10 @@ things that happened on multiple machines (such as comparing a client node
making a request with the storage servers that respond to that request).
Create the Log Gatherer with the "``flogtool create-gatherer WORKDIR``"
command, and start it with "``twistd -ny gatherer.tac``". Then copy the contents of the
command, and start it with "``tahoe start``". Then copy the contents of the
``log_gatherer.furl`` file it creates into the ``BASEDIR/tahoe.cfg`` file
(under the key ``log_gatherer.furl`` of the section ``[node]``) of all nodes
that should be sending it log events. (See :doc:`configuration`)
that should be sending it log events. (See `<configuration.rst>`__.)
The "``flogtool filter``" command, described above, is useful to cut down the
potentially large flogfiles into a more focussed form.
@ -189,6 +198,24 @@ the outbound TCP queue), publishing nodes will start dropping log events when
the outbound queue grows too large. When this occurs, there will be gaps
(non-sequential event numbers) in the log-gatherer's flogfiles.
Local twistd.log files
======================
[TODO: not yet true, requires foolscap-0.3.1 and a change to ``allmydata.node``]
In addition to the foolscap-based event logs, certain high-level events will
be recorded directly in human-readable text form, in the
``BASEDIR/logs/twistd.log`` file (and its rotated old versions:
``twistd.log.1``, ``twistd.log.2``, etc). This form does not contain as much
information as the flogfiles available through the means described
previously, but they are immediately available to the curious developer, and
are retained until the twistd.log.NN files are explicitly deleted.
Only events at the ``log.OPERATIONAL`` level or higher are bridged to
``twistd.log`` (i.e. not the ``log.NOISY`` debugging events). In addition,
foolscap internal events (like connection negotiation messages) are not
bridged to ``twistd.log``.
Adding log messages
===================

View File

@ -1,71 +0,0 @@
**********************
Magic Wormhole Invites
**********************
Magic Wormhole
==============
`magic wormhole`_ is a server and a client which together use Password
Authenticated Key Exchange (PAKE) to use a short code to establish a
secure channel between two computers. These codes are one-time use and
an attacker gets at most one "guess", thus allowing low-entropy codes
to be used.
.. _magic wormhole: https://github.com/warner/magic-wormhole#design
Invites and Joins
=================
Inside Tahoe-LAFS we are using a channel created using `magic
wormhole`_ to exchange configuration and the secret fURL of the
Introducer with new clients.
This is a two-part process. Alice runs a grid and wishes to have her
friend Bob use it as a client. She runs ``tahoe invite bob`` which
will print out a short "wormhole code" like ``2-unicorn-quiver``. You
may also include some options for total, happy and needed shares if
you like.
Alice then transmits this one-time secret code to Bob. Alice must keep
her command running until Bob has done his step as it is waiting until
a secure channel is established before sending the data.
Bob then runs ``tahoe create-client --join <secret code>`` with any
other options he likes. This will "use up" the code establishing a
secure session with Alice's computer. If an attacker tries to guess
the code, they get only once chance to do so (and then Bob's side will
fail). Once Bob's computer has connected to Alice's computer, the two
computers performs the protocol described below, resulting in some
JSON with the Introducer fURL, nickname and any other options being
sent to Bob's computer. The ``tahoe create-client`` command then uses
these options to set up Bob's client.
Tahoe-LAFS Secret Exchange
==========================
The protocol that the Alice (the one doing the invite) and Bob (the
one being invited) sides perform once a magic wormhole secure channel
has been established goes as follows:
Alice and Bob both immediately send an "abilities" message as
JSON. For Alice this is ``{"abilities": {"server-v1": {}}}``. For Bob,
this is ``{"abilities": {"client-v1": {}}}``.
After receiving the message from the other side and confirming the
expected protocol, Alice transmits the configuration JSON::
{
"needed": 3,
"total": 10,
"happy": 7,
"nickname": "bob",
"introducer": "pb://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@example.com:41505/yyyyyyyyyyyyyyyyyyyyyyy"
}
Both sides then disconnect.
As you can see, there is room for future revisions of the protocol but
as of yet none have been sketched out.

View File

@ -1,7 +1,7 @@
.TH TAHOE 1 "July 2011" "Tahoe-LAFS \[em] tahoe command" "User Commands"
.SH NAME
.PP
tahoe - Secure distributed file store.
tahoe - Secure distributed filesystem.
.SH SYNOPSIS
.PP
tahoe \f[I]COMMAND\f[] [\f[I]OPTION\f[]]... [\f[I]PARAMETER\f[]]...
@ -45,6 +45,12 @@ Create a client node (with storage initially disabled).
.TP
.B \f[B]create-introducer\f[]
Create an introducer node.
.TP
.B \f[B]create-key-generator\f[]
Create a key generator service.
.TP
.B \f[B]create-stats-gatherer\f[]
Create a stats-gatherer service.
.SS OPTIONS
.TP
.B \f[B]-C,\ --basedir=\f[]
@ -127,7 +133,7 @@ other than \f[B]run\f[]: `$HOME/.tahoe/').
Display help and exit
.RS
.RE
.SS USING THE FILE STORE
.SS USING THE FILESYSTEM
.TP
.B \f[B]mkdir\f[]
Create a new directory.
@ -251,6 +257,16 @@ Describe all shares in node dirs.
Corrupt a share by flipping a bit.
.RS
.RE
.TP
.B \f[B]repl\f[]
Open a Python interpreter.
.RS
.RE
.TP
.B \f[B]trial\f[]
Run tests using Twisted Trial with the right imports.
.RS
.RE
.PP
Please run e.g.\ `tahoe debug dump-share --help' for more
details on each subcommand.
@ -268,7 +284,7 @@ For known security issues see
.PP
Tahoe-LAFS home page: <https://tahoe-lafs.org/>
.PP
tahoe-dev mailing list: <https://lists.tahoe-lafs.org/mailman/listinfo/tahoe-dev>
tahoe-dev mailing list: <https://tahoe-lafs.org/cgi-bin/mailman/listinfo/tahoe-dev>
.SH COPYRIGHT
.PP
Copyright \@ 2006\[en]2013 The Tahoe-LAFS Software Foundation

View File

@ -1,342 +0,0 @@
Managed Grid
============
This document explains the "Grid Manager" concept and the
`grid-manager` command. Someone operating a grid may choose to use a
Grid Manager. Operators of storage-servers and clients will then be
given additional configuration in this case.
Overview and Motivation
-----------------------
In a grid using an Introducer, a client will use any storage-server
the Introducer announces (and the Introducer will announce any
storage-server that connects to it). This means that anyone with the
Introducer fURL can connect storage to the grid.
Sometimes, this is just what you want!
For some use-cases, though, you want to have clients only use certain
servers. One case might be a "managed" grid, where some entity runs
the grid; clients of this grid don't want their uploads to go to
"unmanaged" storage if some other client decides to provide storage.
One way to limit which storage servers a client connects to is via the
"server list" (:ref:`server_list`) (aka "Introducerless"
mode). Clients are given static lists of storage-servers, and connect
only to those. This means manually updating these lists if the storage
servers change, however.
Another method is for clients to use `[client] peers.preferred=`
configuration option (:ref:`Client Configuration`), which suffers
from a similar disadvantage.
Grid Manager
------------
A "grid-manager" consists of some data defining a keypair (along with
some other details) and Tahoe sub-commands to manipulate the data and
produce certificates to give to storage-servers. Certificates assert
the statement: "Grid Manager X suggests you use storage-server Y to
upload shares to" (X and Y are public-keys). Such a certificate
consists of:
- the version of the format the certificate conforms to (`1`)
- the public-key of a storage-server
- an expiry timestamp
- a signature of the above
A client will always use any storage-server for downloads (expired
certificate, or no certificate) because clients check the ciphertext
and re-assembled plaintext against the keys in the capability;
"grid-manager" certificates only control uploads.
Clients make use of this functionality by configuring one or more Grid Manager public keys.
This tells the client to only upload to storage-servers that have a currently-valid certificate from any of the Grid Managers their client allows.
In case none are configured, the default behavior (of using any storage server) prevails.
Grid Manager Data Storage
-------------------------
The data defining the grid-manager is stored in an arbitrary
directory, which you indicate with the ``--config`` option (in the
future, we may add the ability to store the data directly in a grid,
at which time you may be able to pass a directory-capability to this
option).
If you don't want to store the configuration on disk at all, you may
use ``--config -`` (the last character is a dash) and write a valid
JSON configuration to stdin.
All commands require the ``--config`` option and they all behave
similarly for "data from stdin" versus "data from disk". A directory
(and not a file) is used on disk because in that mode, each
certificate issued is also stored alongside the configuration
document; in "stdin / stdout" mode, an issued certificate is only
ever available on stdout.
The configuration is a JSON document. It is subject to change as Grid
Manager evolves. It contains a version number in the
`grid_manager_config_version` key which will increment whenever the
document schema changes.
grid-manager create
```````````````````
Create a new grid-manager.
If you specify ``--config -`` then a new grid-manager configuration is
written to stdout. Otherwise, a new grid-manager is created in the
directory specified by the ``--config`` option. It is an error if the
directory already exists.
grid-manager public-identity
````````````````````````````
Print out a grid-manager's public key. This key is derived from the
private-key of the grid-manager, so a valid grid-manager config must
be given via ``--config``
This public key is what is put in clients' configuration to actually
validate and use grid-manager certificates.
grid-manager add
````````````````
Takes two args: ``name pubkey``. The ``name`` is an arbitrary local
identifier for the new storage node (also sometimes called "a petname"
or "nickname"). The pubkey is the tahoe-encoded key from a ``node.pubkey``
file in the storage-server's node directory (minus any
whitespace). For example, if ``~/storage0`` contains a storage-node,
you might do something like this::
grid-manager --config ./gm0 add storage0 $(cat ~/storage0/node.pubkey)
This adds a new storage-server to a Grid Manager's
configuration. (Since it mutates the configuration, if you used
``--config -`` the new configuration will be printed to stdout). The
usefulness of the ``name`` is solely for reference within this Grid
Manager.
grid-manager list
`````````````````
Lists all storage-servers that have previously been added using
``grid-manager add``.
grid-manager sign
`````````````````
Takes two args: ``name expiry_days``. The ``name`` is a nickname used
previously in a ``grid-manager add`` command and ``expiry_days`` is
the number of days in the future when the certificate should expire.
Note that this mutates the state of the grid-manager if it is on disk,
by adding this certificate to our collection of issued
certificates. If you used ``--config -``, the certificate isn't
persisted anywhere except to stdout (so if you wish to keep it
somewhere, that is up to you).
This command creates a new "version 1" certificate for a
storage-server (identified by its public key). The new certificate is
printed to stdout. If you stored the config on disk, the new
certificate will (also) be in a file named like ``alice.cert.0``.
Enrolling a Storage Server: CLI
-------------------------------
tahoe admin add-grid-manager-cert
`````````````````````````````````
- `--filename`: the file to read the cert from
- `--name`: the name of this certificate
Import a "version 1" storage-certificate produced by a grid-manager A
storage server may have zero or more such certificates installed; for
now just one is sufficient. You will have to re-start your node after
this. Subsequent announcements to the Introducer will include this
certificate.
.. note::
This command will simply edit the `tahoe.cfg` file and direct you
to re-start. In the Future(tm), we should consider (in exarkun's
words):
"A python program you run as a new process" might not be the
best abstraction to layer on top of the configuration
persistence system, though. It's a nice abstraction for users
(although most users would probably rather have a GUI) but it's
not a great abstraction for automation. So at some point it
may be better if there is CLI -> public API -> configuration
persistence system. And maybe "public API" is even a network
API for the storage server so it's equally easy to access from
an agent implemented in essentially any language and maybe if
the API is exposed by the storage node itself then this also
gives you live-configuration-updates, avoiding the need for
node restarts (not that this is the only way to accomplish
this, but I think it's a good way because it avoids the need
for messes like inotify and it supports the notion that the
storage node process is in charge of its own configuration
persistence system, not just one consumer among many ... which
has some nice things going for it ... though how this interacts
exactly with further node management automation might bear
closer scrutiny).
Enrolling a Storage Server: Config
----------------------------------
You may edit the ``[storage]`` section of the ``tahoe.cfg`` file to
turn on grid-management with ``grid_management = true``. You then must
also provide a ``[grid_management_certificates]`` section in the
config-file which lists ``name = path/to/certificate`` pairs.
These certificate files are issued by the ``grid-manager sign``
command; these should be transmitted to the storage server operator
who includes them in the config for the storage server. Relative paths
are based from the node directory. Example::
[storage]
grid_management = true
[grid_management_certificates]
default = example_grid.cert
This will cause us to give this certificate to any Introducers we
connect to (and subsequently, the Introducer will give the certificate
out to clients).
Enrolling a Client: Config
--------------------------
You may instruct a Tahoe client to use only storage servers from given
Grid Managers. If there are no such keys, any servers are used
(but see https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3979). If
there are one or more keys, the client will only upload to a storage
server that has a valid certificate (from any of the keys).
To specify public-keys, add a ``[grid_managers]`` section to the
config. This consists of ``name = value`` pairs where ``name`` is an
arbitrary name and ``value`` is a public-key of a Grid
Manager. Example::
[grid_managers]
example_grid = pub-v0-vqimc4s5eflwajttsofisp5st566dbq36xnpp4siz57ufdavpvlq
See also https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3507 which
proposes a command to edit the config.
Example Setup of a New Managed Grid
-----------------------------------
This example creates an actual grid, but it's all just on one machine
with different "node directories" and a separate tahoe process for
each node. Usually of course each storage server would be on a
separate computer.
Note that we use the ``daemonize`` command in the following but that's
only one way to handle "running a command in the background". You
could instead run commands that start with ``daemonize ...`` in their
own shell/terminal window or via something like ``systemd``
We'll store our Grid Manager configuration on disk, in
``./gm0``. To initialize this directory::
grid-manager --config ./gm0 create
(If you already have a grid, you can :ref:`skip ahead <skip_ahead>`.)
First of all, create an Introducer. Note that we actually have to run
it briefly before it creates the "Introducer fURL" we want for the
next steps::
tahoe create-introducer --listen=tcp --port=5555 --location=tcp:localhost:5555 ./introducer
daemonize tahoe -d introducer run
Next, we attach a couple of storage nodes::
tahoe create-node --introducer $(cat introducer/private/introducer.furl) --nickname storage0 --webport 6001 --location tcp:localhost:6003 --port 6003 ./storage0
tahoe create-node --introducer $(cat introducer/private/introducer.furl) --nickname storage1 --webport 6101 --location tcp:localhost:6103 --port 6103 ./storage1
daemonize tahoe -d storage0 run
daemonize tahoe -d storage1 run
.. _skip_ahead:
We can now tell the Grid Manager about our new storage servers::
grid-manager --config ./gm0 add storage0 $(cat storage0/node.pubkey)
grid-manager --config ./gm0 add storage1 $(cat storage1/node.pubkey)
To produce a new certificate for each node, we do this::
grid-manager --config ./gm0 sign storage0 > ./storage0/gridmanager.cert
grid-manager --config ./gm0 sign storage1 > ./storage1/gridmanager.cert
Now, we want our storage servers to actually announce these
certificates into the grid. We do this by adding some configuration
(in ``tahoe.cfg``)::
[storage]
grid_management = true
[grid_manager_certificates]
default = gridmanager.cert
Add the above bit to each node's ``tahoe.cfg`` and re-start the
storage nodes. (Alternatively, use the ``tahoe add-grid-manager``
command).
Now try adding a new storage server ``storage2``. This client can join
the grid just fine, and announce itself to the Introducer as providing
storage::
tahoe create-node --introducer $(cat introducer/private/introducer.furl) --nickname storage2 --webport 6301 --location tcp:localhost:6303 --port 6303 ./storage2
daemonize tahoe -d storage2 run
At this point any client will upload to any of these three
storage-servers. Make a client "alice" and try!
::
tahoe create-client --introducer $(cat introducer/private/introducer.furl) --nickname alice --webport 6401 --shares-total=3 --shares-needed=2 --shares-happy=3 ./alice
daemonize tahoe -d alice run
tahoe -d alice put README.rst # prints out a read-cap
find storage2/storage/shares # confirm storage2 has a share
Now we want to make Alice only upload to the storage servers that the
grid-manager has given certificates to (``storage0`` and
``storage1``). We need the grid-manager's public key to put in Alice's
configuration::
grid-manager --config ./gm0 public-identity
Put the key printed out above into Alice's ``tahoe.cfg`` in section
``client``::
[grid_managers]
example_name = pub-v0-vqimc4s5eflwajttsofisp5st566dbq36xnpp4siz57ufdavpvlq
Now, re-start the "alice" client. Since we made Alice's parameters
require 3 storage servers to be reachable (``--happy=3``), all their
uploads should now fail (so ``tahoe put`` will fail) because they
won't use storage2 and thus can't "achieve happiness".
A proposal to expose more information about Grid Manager and
certificate status in the Welcome page is discussed in
https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3506

View File

@ -82,9 +82,8 @@ network: A
memory footprint: N/K*A
notes:
Tahoe-LAFS generates a new RSA keypair for each mutable file that it publishes to a grid.
This takes around 100 milliseconds on a relatively high-end laptop from 2021.
notes: Tahoe-LAFS generates a new RSA keypair for each mutable file that it
publishes to a grid. This takes up to 1 or 2 seconds on a typical desktop PC.
Part of the process of encrypting, encoding, and uploading a mutable file to a
Tahoe-LAFS grid requires that the entire file be in memory at once. For larger

View File

@ -1,6 +1,6 @@
The lossmodel.lyx file is the source document for an in-progress paper
that analyzes the probability of losing files stored in a Tahoe-LAFS
file store under various scenarios. It describes:
that analyzes the probability of losing files stored in a Tahoe
Least-acces File System under various scenarios. It describes:
1. How to estimate peer reliabilities, based on peer MTBF failure
data.

View File

@ -546,15 +546,16 @@ The "restrictions dictionary" is a table which establishes an upper bound on
how this authority (or any attenuations thereof) may be used. It is
effectively a set of key-value pairs.
A "signing key" is an EC-DSA192 private key string and is 12 bytes
long. A "verifying key" is an EC-DSA192 public key string, and is 24
bytes long. A "key identifier" is a string which securely identifies a
specific signing/verifying keypair: for long RSA keys it would be a
secure hash of the public key, but since ECDSA192 keys are so short,
we simply use the full verifying key verbatim. A "key hint" is a
variable-length prefix of the key identifier, perhaps zero bytes long,
used to help a recipient reduce the number of verifying keys that it
must search to find one that matches a signed message.
A "signing key" is an EC-DSA192 private key string, as supplied to the
pycryptopp SigningKey() constructor, and is 12 bytes long. A "verifying key"
is an EC-DSA192 public key string, as produced by pycryptopp, and is 24 bytes
long. A "key identifier" is a string which securely identifies a specific
signing/verifying keypair: for long RSA keys it would be a secure hash of the
public key, but since ECDSA192 keys are so short, we simply use the full
verifying key verbatim. A "key hint" is a variable-length prefix of the key
identifier, perhaps zero bytes long, used to help a recipient reduce the
number of verifying keys that it must search to find one that matches a
signed message.
==== Authority Chains ====

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
Proposed Specifications
=======================
This directory is where we hold design notes about upcoming/proposed
features. Usually this is kept in tickets on the `bug tracker`_, but
sometimes we put this directly into the source tree.
.. _bug tracker: https://tahoe-lafs.org/trac
Most of these files are plain text, should be read from a source tree. This
index only lists the files that are in .rst format.
.. toctree::
:maxdepth: 2
leasedb
http-storage-node-protocol

View File

@ -132,7 +132,8 @@ shnum) pair. This entry stores the times when the lease was last renewed and
when it is set to expire (if the expiration policy does not force it to
expire earlier), represented as Unix UTC-seconds-since-epoch timestamps.
For more on expiration policy, see :doc:`../garbage-collection`.
For more on expiration policy, see `docs/garbage-collection.rst
<../garbage-collection.rst>`__.
Share states

View File

@ -0,0 +1,114 @@
Magic Folder local filesystem integration design
================================================
*Scope*
This document describes how to integrate the local filesystem with Magic
Folder in an efficient and reliable manner. For now we ignore Remote to
Local synchronization; the design and implementation of this is scheduled
for a later time. We also ignore multiple writers for the same Magic
Folder, which may or may not be supported in future. The design here will
be updated to account for those features in later Objectives. Objective 3
may require modifying the database schema or operation, and Objective 5
may modify the User interface.
Tickets on the Tahoe-LAFS trac with the `otf-magic-folder-objective2`_
keyword are within the scope of the local filesystem integration for
Objective 2.
.. _otf-magic-folder-objective2: https://tahoe-lafs.org/trac/tahoe-lafs/query?status=!closed&keywords=~otf-magic-folder-objective2
*Local scanning and database*
When a Magic-Folder-enabled node starts up, it scans all directories
under the local directory and adds every file to a first-in first-out
"scan queue". When processing the scan queue, redundant uploads are
avoided by using the same mechanism the Tahoe backup command uses: we
keep track of previous uploads by recording each file's metadata such as
size, ``ctime`` and ``mtime``. This information is stored in a database,
referred to from now on as the magic folder db. Using this recorded
state, we ensure that when Magic Folder is subsequently started, the
local directory tree can be scanned quickly by comparing current
filesystem metadata with the previously recorded metadata. Each file
referenced in the scan queue is uploaded only if its metadata differs at
the time it is processed. If a change event is detected for a file that
is already queued (and therefore will be processed later), the redundant
event is ignored.
To implement the magic folder db, we will use an SQLite schema that
initially is the existing Tahoe-LAFS backup schema. This schema may
change in later objectives; this will cause no backward compatibility
problems, because this new feature will be developed on a branch that
makes no compatibility guarantees. However we will have a separate SQLite
database file and separate mutex lock just for Magic Folder. This avoids
usability problems related to mutual exclusion. (If a single file and
lock were used, a backup would block Magic Folder updates for a long
time, and a user would not be able to tell when backups are possible
because Magic Folder would acquire a lock at arbitrary times.)
*Eventual consistency property*
During the process of reading a file in order to upload it, it is not
possible to prevent further local writes. Such writes will result in
temporary inconsistency (that is, the uploaded file will not reflect
what the contents of the local file were at any specific time). Eventual
consistency is reached when the queue of pending uploads is empty. That
is, a consistent snapshot will be achieved eventually when local writes
to the target folder cease for a sufficiently long period of time.
*Detecting filesystem changes*
For the Linux implementation, we will use the inotify Linux kernel
subsystem to gather events on the local Magic Folder directory tree. This
implementation was already present in Tahoe-LAFS 1.9.0, but needs to be
changed to gather directory creation and move events, in addition to the
events indicating that a file has been written that are gathered by the
current code.
For the Windows implementation, we will use the ``ReadDirectoryChangesW``
Win32 API. The prototype implementation simulates a Python interface to
the inotify API in terms of ``ReadDirectoryChangesW``, allowing most of
the code to be shared across platforms.
The alternative of using `NTFS Change Journals`_ for Windows was
considered, but appears to be more complicated and does not provide any
additional functionality over the scanning approach described above.
The Change Journal mechanism is also only available for NTFS filesystems,
but FAT32 filesystems are still common in user installations of Windows.
.. _`NTFS Change Journals`: https://msdn.microsoft.com/en-us/library/aa363803%28VS.85%29.aspx
When we detect the creation of a new directory below the local Magic
Folder directory, we create it in the Tahoe-LAFS filesystem, and also
scan the new local directory for new files. This scan is necessary to
avoid missing events for creation of files in a new directory before it
can be watched, and to correctly handle cases where an existing directory
is moved to be under the local Magic Folder directory.
*User interface*
The Magic Folder local filesystem integration will initially have a
provisional configuration file-based interface that may not be ideal from
a usability perspective. Creating our local filesystem integration in
this manner will allow us to use and test it independently of the rest of
the Magic Folder software components. We will focus greater attention on
user interface design as a later milestone in our development roadmap.
The configuration file, ``tahoe.cfg``, must define a target local
directory to be synchronized. Provisionally, this configuration will
replace the current ``[drop_upload]`` section::
[magic_folder]
enabled = true
local.directory = "/home/human"
When a filesystem directory is first configured for Magic Folder, the user
needs to create the remote Tahoe-LAFS directory using ``tahoe mkdir``,
and configure the Magic-Folder-enabled node with its URI (e.g. by putting
it in a file ``private/magic_folder_dircap``). If there are existing
files in the local directory, they will be uploaded as a result of the
initial scan described earlier.

View File

@ -0,0 +1,898 @@
Magic Folder design for remote-to-local sync
============================================
Scope
-----
In this Objective we will design remote-to-local synchronization:
* How to efficiently determine which objects (files and directories) have
to be downloaded in order to bring the current local filesystem into sync
with the newly-discovered version of the remote filesystem.
* How to distinguish overwrites, in which the remote side was aware of
your most recent version and overwrote it with a new version, from
conflicts, in which the remote side was unaware of your most recent
version when it published its new version. The latter needs to be raised
to the user as an issue the user will have to resolve and the former must
not bother the user.
* How to overwrite the (stale) local versions of those objects with the
newly acquired objects, while preserving backed-up versions of those
overwritten objects in case the user didn't want this overwrite and wants
to recover the old version.
Tickets on the Tahoe-LAFS trac with the `otf-magic-folder-objective4`_
keyword are within the scope of the remote-to-local synchronization
design.
.. _otf-magic-folder-objective4: https://tahoe-lafs.org/trac/tahoe-lafs/query?status=!closed&keywords=~otf-magic-folder-objective4
Glossary
''''''''
Object: a file or directory
DMD: distributed mutable directory
Folder: an abstract directory that is synchronized between clients.
(A folder is not the same as the directory corresponding to it on
any particular client, nor is it the same as a DMD.)
Collective: the set of clients subscribed to a given Magic Folder.
Descendant: a direct or indirect child in a directory or folder tree
Subfolder: a folder that is a descendant of a magic folder
Subpath: the path from a magic folder to one of its descendants
Write: a modification to a local filesystem object by a client
Read: a read from a local filesystem object by a client
Upload: an upload of a local object to the Tahoe-LAFS file store
Download: a download from the Tahoe-LAFS file store to a local object
Pending notification: a local filesystem change that has been detected
but not yet processed.
Representing the Magic Folder in Tahoe-LAFS
-------------------------------------------
Unlike the local case where we use inotify or ReadDirectoryChangesW to
detect filesystem changes, we have no mechanism to register a monitor for
changes to a Tahoe-LAFS directory. Therefore, we must periodically poll
for changes.
An important constraint on the solution is Tahoe-LAFS' "`write
coordination directive`_", which prohibits concurrent writes by different
storage clients to the same mutable object:
Tahoe does not provide locking of mutable files and directories. If
there is more than one simultaneous attempt to change a mutable file
or directory, then an UncoordinatedWriteError may result. This might,
in rare cases, cause the file or directory contents to be accidentally
deleted. The user is expected to ensure that there is at most one
outstanding write or update request for a given file or directory at
a time. One convenient way to accomplish this is to make a different
file or directory for each person or process that wants to write.
.. _`write coordination directive`: ../../write_coordination.rst
Since it is a goal to allow multiple users to write to a Magic Folder,
if the write coordination directive remains the same as above, then we
will not be able to implement the Magic Folder as a single Tahoe-LAFS
DMD. In general therefore, we will have multiple DMDs —spread across
clients— that together represent the Magic Folder. Each client in a
Magic Folder collective polls the other clients' DMDs in order to detect
remote changes.
Six possible designs were considered for the representation of subfolders
of the Magic Folder:
1. All subfolders written by a given Magic Folder client are collapsed
into a single client DMD, containing immutable files. The child name of
each file encodes the full subpath of that file relative to the Magic
Folder.
2. The DMD tree under a client DMD is a direct copy of the folder tree
written by that client to the Magic Folder. Not all subfolders have
corresponding DMDs; only those to which that client has written files or
child subfolders.
3. The directory tree under a client DMD is a ``tahoe backup`` structure
containing immutable snapshots of the folder tree written by that client
to the Magic Folder. As in design 2, only objects written by that client
are present.
4. *Each* client DMD contains an eventually consistent mirror of all
files and folders written by *any* Magic Folder client. Thus each client
must also copy changes made by other Magic Folder clients to its own
client DMD.
5. *Each* client DMD contains a ``tahoe backup`` structure containing
immutable snapshots of all files and folders written by *any* Magic
Folder client. Thus each client must also create another snapshot in its
own client DMD when changes are made by another client. (It can potentially
batch changes, subject to latency requirements.)
6. The write coordination problem is solved by implementing `two-phase
commit`_. Then, the representation consists of a single DMD tree which is
written by all clients.
.. _`two-phase commit`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1755
Here is a summary of advantages and disadvantages of each design:
+----------------------------+
| Key |
+=======+====================+
| \+\+ | major advantage |
+-------+--------------------+
| \+ | minor advantage |
+-------+--------------------+
| | minor disadvantage |
+-------+--------------------+
| | major disadvantage |
+-------+--------------------+
| | showstopper |
+-------+--------------------+
123456+: All designs have the property that a recursive add-lease
operation starting from a *collective directory* containing all of
the client DMDs, will find all of the files and directories used in
the Magic Folder representation. Therefore the representation is
compatible with `garbage collection`_, even when a pre-Magic-Folder
client does the lease marking.
.. _`garbage collection`: https://tahoe-lafs.org/trac/tahoe-lafs/browser/trunk/docs/garbage-collection.rst
123456+: All designs avoid "breaking" pre-Magic-Folder clients that read
a directory or file that is part of the representation.
456++: Only these designs allow a readcap to one of the client
directories —or one of their subdirectories— to be directly shared
with other Tahoe-LAFS clients (not necessarily Magic Folder clients),
so that such a client sees all of the contents of the Magic Folder.
Note that this was not a requirement of the OTF proposal, although it
is useful.
135+: A Magic Folder client has only one mutable Tahoe-LAFS object to
monitor per other client. This minimizes communication bandwidth for
polling, or alternatively the latency possible for a given polling
bandwidth.
1236+: A client does not need to make changes to its own DMD that repeat
changes that another Magic Folder client had previously made. This reduces
write bandwidth and complexity.
1: If the Magic Folder has many subfolders, their files will all be
collapsed into the same DMD, which could get quite large. In practice a
single DMD can easily handle the number of files expected to be written
by a client, so this is unlikely to be a significant issue.
123 : In these designs, the set of files in a Magic Folder is
represented as the union of the files in all client DMDs. However,
when a file is modified by more than one client, it will be linked
from multiple client DMDs. We therefore need a mechanism, such as a
version number or a monotonically increasing timestamp, to determine
which copy takes priority.
35 : When a Magic Folder client detects a remote change, it must
traverse an immutable directory structure to see what has changed.
Completely unchanged subtrees will have the same URI, allowing some of
this traversal to be shortcutted.
24 : When a Magic Folder client detects a remote change, it must
traverse a mutable directory structure to see what has changed. This is
more complex and less efficient than traversing an immutable structure,
because shortcutting is not possible (each DMD retains the same URI even
if a descendant object has changed), and because the structure may change
while it is being traversed. Also the traversal needs to be robust
against cycles, which can only occur in mutable structures.
45 : When a change occurs in one Magic Folder client, it will propagate
to all the other clients. Each client will therefore see multiple
representation changes for a single logical change to the Magic Folder
contents, and must suppress the duplicates. This is particularly
problematic for design 4 where it interacts with the preceding issue.
4 , 5 : There is the potential for client DMDs to get "out of sync"
with each other, potentially for long periods if errors occur. Thus each
client must be able to "repair" its client directory (and its
subdirectory structure) concurrently with performing its own writes. This
is a significant complexity burden and may introduce failure modes that
could not otherwise happen.
6 : While two-phase commit is a well-established protocol, its
application to Tahoe-LAFS requires significant design work, and may still
leave some corner cases of the write coordination problem unsolved.
+------------------------------------------------+-----------------------------------------+
| Design Property | Designs Proposed |
+================================================+======+======+======+======+======+======+
| **advantages** | *1* | *2* | *3* | *4* | *5* | *6* |
+------------------------------------------------+------+------+------+------+------+------+
| Compatible with garbage collection |\+ |\+ |\+ |\+ |\+ |\+ |
+------------------------------------------------+------+------+------+------+------+------+
| Does not break old clients |\+ |\+ |\+ |\+ |\+ |\+ |
+------------------------------------------------+------+------+------+------+------+------+
| Allows direct sharing | | | |\+\+ |\+\+ |\+\+ |
+------------------------------------------------+------+------+------+------+------+------+
| Efficient use of bandwidth |\+ | |\+ | |\+ | |
+------------------------------------------------+------+------+------+------+------+------+
| No repeated changes |\+ |\+ |\+ | | |\+ |
+------------------------------------------------+------+------+------+------+------+------+
| **disadvantages** | *1* | *2* | *3* | *4* | *5* | *6* |
+------------------------------------------------+------+------+------+------+------+------+
| Can result in large DMDs | | | | | | |
+------------------------------------------------+------+------+------+------+------+------+
| Need version number to determine priority | | | | | | |
+------------------------------------------------+------+------+------+------+------+------+
| Must traverse immutable directory structure | | | | | | |
+------------------------------------------------+------+------+------+------+------+------+
| Must traverse mutable directory structure | | | | | | |
+------------------------------------------------+------+------+------+------+------+------+
| Must suppress duplicate representation changes | | | | | | |
+------------------------------------------------+------+------+------+------+------+------+
| "Out of sync" problem | | | | | | |
+------------------------------------------------+------+------+------+------+------+------+
| Unsolved design problems | | | | | | |
+------------------------------------------------+------+------+------+------+------+------+
Evaluation of designs
'''''''''''''''''''''
Designs 2 and 3 have no significant advantages over design 1, while
requiring higher polling bandwidth and greater complexity due to the need
to create subdirectories. These designs were therefore rejected.
Design 4 was rejected due to the out-of-sync problem, which is severe
and possibly unsolvable for mutable structures.
For design 5, the out-of-sync problem is still present but possibly
solvable. However, design 5 is substantially more complex, less efficient
in bandwidth/latency, and less scalable in number of clients and
subfolders than design 1. It only gains over design 1 on the ability to
share directory readcaps to the Magic Folder (or subfolders), which was
not a requirement. It would be possible to implement this feature in
future by switching to design 6.
For the time being, however, design 6 was considered out-of-scope for
this project.
Therefore, design 1 was chosen. That is:
All subfolders written by a given Magic Folder client are collapsed
into a single client DMD, containing immutable files. The child name
of each file encodes the full subpath of that file relative to the
Magic Folder.
Each directory entry in a DMD also stores a version number, so that the
latest version of a file is well-defined when it has been modified by
multiple clients.
To enable representing empty directories, a client that creates a
directory should link a corresponding zero-length file in its DMD,
at a name that ends with the encoded directory separator character.
We want to enable dynamic configuration of the membership of a Magic
Folder collective, without having to reconfigure or restart each client
when another client joins. To support this, we have a single collective
directory that links to all of the client DMDs, named by their client
nicknames. If the collective directory is mutable, then it is possible
to change its contents in order to add clients. Note that a client DMD
should not be unlinked from the collective directory unless all of its
files are first copied to some other client DMD.
A client needs to be able to write to its own DMD, and read from other DMDs.
To be consistent with the `Principle of Least Authority`_, each client's
reference to its own DMD is a write capability, whereas its reference
to the collective directory is a read capability. The latter transitively
grants read access to all of the other client DMDs and the files linked
from them, as required.
.. _`Principle of Least Authority`: http://www.eros-os.org/papers/secnotsep.pdf
Design and implementation of the user interface for maintaining this
DMD structure and configuration will be addressed in Objectives 5 and 6.
During operation, each client will poll for changes on other clients
at a predetermined frequency. On each poll, it will reread the collective
directory (to allow for added or removed clients), and then read each
client DMD linked from it.
"Hidden" files, and files with names matching the patterns used for backup,
temporary, and conflicted files, will be ignored, i.e. not synchronized
in either direction. A file is hidden if it has a filename beginning with
"." (on any platform), or has the hidden or system attribute on Windows.
Conflict Detection and Resolution
---------------------------------
The combination of local filesystems and distributed objects is
an example of shared state concurrency, which is highly error-prone
and can result in race conditions that are complex to analyze.
Unfortunately we have no option but to use shared state in this
situation.
We call the resulting design issues "dragons" (as in "Here be dragons"),
which as a convenient mnemonic we have named after the classical
Greek elements Earth, Fire, Air, and Water.
Note: all filenames used in the following sections are examples,
and the filename patterns we use in the actual implementation may
differ. The actual patterns will probably include timestamps, and
for conflicted files, the nickname of the client that last changed
the file.
Earth Dragons: Collisions between local filesystem operations and downloads
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Write/download collisions
~~~~~~~~~~~~~~~~~~~~~~~~~
Suppose that Alice's Magic Folder client is about to write a
version of ``foo`` that it has downloaded in response to a remote
change.
The criteria for distinguishing overwrites from conflicts are
described later in the `Fire Dragons`_ section. Suppose that the
remote change has been initially classified as an overwrite.
(As we will see, it may be reclassified in some circumstances.)
.. _`Fire Dragons`: #fire-dragons-distinguishing-conflicts-from-overwrites
A *write/download collision* occurs when another program writes
to ``foo`` in the local filesystem, concurrently with the new
version being written by the Magic Folder client. We need to
ensure that this does not cause data loss, as far as possible.
An important constraint on the design is that on Windows, it is
not possible to rename a file to the same name as an existing
file in that directory. Also, on Windows it may not be possible to
delete or rename a file that has been opened by another process
(depending on the sharing flags specified by that process).
Therefore we need to consider carefully how to handle failure
conditions.
In our proposed design, Alice's Magic Folder client follows
this procedure for an overwrite in response to a remote change:
1. Write a temporary file, say ``.foo.tmp``.
2. Use the procedure described in the `Fire Dragons_` section
to obtain an initial classification as an overwrite or a
conflict. (This takes as input the ``last_downloaded_uri``
field from the directory entry of the changed ``foo``.)
3. Set the ``mtime`` of the replacement file to be *T* seconds
before the current local time.
4. Perform a ''file replacement'' operation (explained below)
with backup filename ``foo.backup``, replaced file ``foo``,
and replacement file ``.foo.tmp``. If any step of this
operation fails, reclassify as a conflict and stop.
To reclassify as a conflict, attempt to rename ``.foo.tmp`` to
``foo.conflicted``, suppressing errors.
The implementation of file replacement differs between Unix
and Windows. On Unix, it can be implemented as follows:
* 4a. Set the permissions of the replacement file to be the
same as the replaced file, bitwise-or'd with octal 600
(``rw-------``).
* 4b. Attempt to move the replaced file (``foo``) to the
backup filename (``foo.backup``).
* 4c. Attempt to create a hard link at the replaced filename
(``foo``) pointing to the replacement file (``.foo.tmp``).
* 4d. Attempt to unlink the replacement file (``.foo.tmp``),
suppressing errors.
Note that, if there is no conflict, the entry for ``foo``
recorded in the `magic folder db`_ will reflect the ``mtime``
set in step 3. The link operation in step 4c will cause an
``IN_CREATE`` event for ``foo``, but this will not trigger an
upload, because the metadata recorded in the database entry
will exactly match the metadata for the file's inode on disk.
(The two hard links — ``foo`` and, while it still exists,
``.foo.tmp`` — share the same inode and therefore the same
metadata.)
.. _`magic folder db`: filesystem_integration.rst#local-scanning-and-database
On Windows, file replacement can be implemented as a single
call to the `ReplaceFileW`_ API (with the
``REPLACEFILE_IGNORE_MERGE_ERRORS`` flag).
Similar to the Unix case, the `ReplaceFileW`_ operation will
cause a change notification for ``foo``. The replaced ``foo``
has the same ``mtime`` as the replacement file, and so this
notification will not trigger an unwanted upload.
.. _`ReplaceFileW`: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365512%28v=vs.85%29.aspx
To determine whether this procedure adequately protects against data
loss, we need to consider what happens if another process attempts to
update ``foo``, for example by renaming ``foo.other`` to ``foo``.
This requires us to analyze all possible interleavings between the
operations performed by the Magic Folder client and the other process.
(Note that atomic operations on a directory are totally ordered.)
The set of possible interleavings differs between Windows and Unix.
On Unix, we have:
* Interleaving A: the other process' rename precedes our rename in
step 4b, and we get an ``IN_MOVED_TO`` event for its rename by
step 2. Then we reclassify as a conflict; its changes end up at
``foo`` and ours end up at ``foo.conflicted``. This avoids data
loss.
* Interleaving B: its rename precedes ours in step 4b, and we do
not get an event for its rename by step 2. Its changes end up at
``foo.backup``, and ours end up at ``foo`` after being linked there
in step 4c. This avoids data loss.
* Interleaving C: its rename happens between our rename in step 4b,
and our link operation in step 4c of the file replacement. The
latter fails with an ``EEXIST`` error because ``foo`` already
exists. We reclassify as a conflict; the old version ends up at
``foo.backup``, the other process' changes end up at ``foo``, and
ours at ``foo.conflicted``. This avoids data loss.
* Interleaving D: its rename happens after our link in step 4c,
and causes an ``IN_MOVED_TO`` event for ``foo``. Its rename also
changes the ``mtime`` for ``foo`` so that it is different from
the ``mtime`` calculated in step 3, and therefore different
from the metadata recorded for ``foo`` in the magic folder db.
(Assuming no system clock changes, its rename will set an ``mtime``
timestamp corresponding to a time after step 4c, which is not
equal to the timestamp *T* seconds before step 4a, provided that
*T* seconds is sufficiently greater than the timestamp granularity.)
Therefore, an upload will be triggered for ``foo`` after its
change, which is correct and avoids data loss.
On Windows, the internal implementation of `ReplaceFileW`_ is similar
to what we have described above for Unix; it works like this:
* 4a. Copy metadata (which does not include ``mtime``) from the
replaced file (``foo``) to the replacement file (``.foo.tmp``).
* 4b. Attempt to move the replaced file (``foo``) onto the
backup filename (``foo.backup``), deleting the latter if it
already exists.
* 4c. Attempt to move the replacement file (``.foo.tmp``) to the
replaced filename (``foo``); fail if the destination already
exists.
Notice that this is essentially the same as the algorithm we use
for Unix, but steps 4c and 4d on Unix are combined into a single
step 4c. (If there is a failure at steps 4c after step 4b has
completed, the `ReplaceFileW`_ call will fail with return code
``ERROR_UNABLE_TO_MOVE_REPLACEMENT_2``. However, it is still
preferable to use this API over two `MoveFileExW`_ calls, because
it retains the attributes and ACLs of ``foo`` where possible.)
However, on Windows the other application will not be able to
directly rename ``foo.other`` onto ``foo`` (which would fail because
the destination already exists); it will have to rename or delete
``foo`` first. Without loss of generality, let's say ``foo`` is
deleted. This complicates the interleaving analysis, because we
have two operations done by the other process interleaving with
three done by the magic folder process (rather than one operation
interleaving with four as on Unix). The cases are:
* Interleaving A: the other process' deletion of ``foo`` and its
rename of ``foo.other`` to ``foo`` both precede our rename in
step 4b. We get an event corresponding to its rename by step 2.
Then we reclassify as a conflict; its changes end up at ``foo``
and ours end up at ``foo.conflicted``. This avoids data loss.
* Interleaving B: the other process' deletion of ``foo`` and its
rename of ``foo.other`` to ``foo`` both precede our rename in
step 4b. We do not get an event for its rename by step 2.
Its changes end up at ``foo.backup``, and ours end up at ``foo``
after being moved there in step 4c. This avoids data loss.
* Interleaving C: the other process' deletion of ``foo`` precedes
our rename of ``foo`` to ``foo.backup`` done by `ReplaceFileW`_,
but its rename of ``foo.other`` to ``foo`` does not, so we get
an ``ERROR_FILE_NOT_FOUND`` error from `ReplaceFileW`_ indicating
that the replaced file does not exist. Then we reclassify as a
conflict; the other process' changes end up at ``foo`` (after
it has renamed ``foo.other`` to ``foo``) and our changes end up
at ``foo.conflicted``. This avoids data loss.
* Interleaving D: the other process' deletion and/or rename happen
during the call to `ReplaceFileW`_, causing the latter to fail.
There are two subcases:
* if the error is ``ERROR_UNABLE_TO_MOVE_REPLACEMENT_2``, then
``foo`` is renamed to ``foo.backup`` and ``.foo.tmp`` remains
at its original name after the call.
* for all other errors, ``foo`` and ``.foo.tmp`` both remain at
their original names after the call.
In both subcases, we reclassify as a conflict and rename ``.foo.tmp``
to ``foo.conflicted``. This avoids data loss.
* Interleaving E: the other process' deletion of ``foo`` and attempt
to rename ``foo.other`` to ``foo`` both happen after all internal
operations of `ReplaceFileW`_ have completed. This causes deletion
and rename events for ``foo`` (which will in practice be merged due
to the pending delay, although we don't rely on that for correctness).
The rename also changes the ``mtime`` for ``foo`` so that it is
different from the ``mtime`` calculated in step 3, and therefore
different from the metadata recorded for ``foo`` in the magic folder
db. (Assuming no system clock changes, its rename will set an
``mtime`` timestamp corresponding to a time after the internal
operations of `ReplaceFileW`_ have completed, which is not equal to
the timestamp *T* seconds before `ReplaceFileW`_ is called, provided
that *T* seconds is sufficiently greater than the timestamp
granularity.) Therefore, an upload will be triggered for ``foo``
after its change, which is correct and avoids data loss.
.. _`MoveFileExW`: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240%28v=vs.85%29.aspx
We also need to consider what happens if another process opens ``foo``
and writes to it directly, rather than renaming another file onto it:
* On Unix, open file handles refer to inodes, not paths. If the other
process opens ``foo`` before it has been renamed to ``foo.backup``,
and then closes the file, changes will have been written to the file
at the same inode, even if that inode is now linked at ``foo.backup``.
This avoids data loss.
* On Windows, we have two subcases, depending on whether the sharing
flags specified by the other process when it opened its file handle
included ``FILE_SHARE_DELETE``. (This flag covers both deletion and
rename operations.)
i. If the sharing flags *do not* allow deletion/renaming, the
`ReplaceFileW`_ operation will fail without renaming ``foo``.
In this case we will end up with ``foo`` changed by the other
process, and the downloaded file still in ``foo.tmp``.
This avoids data loss.
ii. If the sharing flags *do* allow deletion/renaming, then
data loss or corruption may occur. This is unavoidable and
can be attributed to other process making a poor choice of
sharing flags (either explicitly if it used `CreateFile`_, or
via whichever higher-level API it used).
.. _`CreateFile`: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx
Note that it is possible that another process tries to open the file
between steps 4b and 4c (or 4b and 4c on Windows). In this case the
open will fail because ``foo`` does not exist. Nevertheless, no data
will be lost, and in many cases the user will be able to retry the
operation.
Above we only described the case where the download was initially
classified as an overwrite. If it was classed as a conflict, the
procedure is the same except that we choose a unique filename
for the conflicted file (say, ``foo.conflicted_unique``). We write
the new contents to ``.foo.tmp`` and then rename it to
``foo.conflicted_unique`` in such a way that the rename will fail
if the destination already exists. (On Windows this is a simple
rename; on Unix it can be implemented as a link operation followed
by an unlink, similar to steps 4c and 4d above.) If this fails
because another process wrote ``foo.conflicted_unique`` after we
chose the filename, then we retry with a different filename.
Read/download collisions
~~~~~~~~~~~~~~~~~~~~~~~~
A *read/download collision* occurs when another program reads
from ``foo`` in the local filesystem, concurrently with the new
version being written by the Magic Folder client. We want to
ensure that any successful attempt to read the file by the other
program obtains a consistent view of its contents.
On Unix, the above procedure for writing downloads is sufficient
to achieve this. There are three cases:
* A. The other process opens ``foo`` for reading before it is
renamed to ``foo.backup``. Then the file handle will continue to
refer to the old file across the rename, and the other process
will read the old contents.
* B. The other process attempts to open ``foo`` after it has been
renamed to ``foo.backup``, and before it is linked in step c.
The open call fails, which is acceptable.
* C. The other process opens ``foo`` after it has been linked to
the new file. Then it will read the new contents.
On Windows, the analysis is very similar, but case A needs to
be split into two subcases, depending on the sharing mode the other
process uses when opening the file for reading:
* A. The other process opens ``foo`` before the Magic Folder
client's attempt to rename ``foo`` to ``foo.backup`` (as part
of the implementation of `ReplaceFileW`_). The subcases are:
i. The other process uses sharing flags that deny deletion and
renames. The `ReplaceFileW`_ call fails, and the download is
reclassified as a conflict. The downloaded file ends up at
``foo.conflicted``, which is correct.
ii. The other process uses sharing flags that allow deletion
and renames. The `ReplaceFileW`_ call succeeds, and the
other process reads inconsistent data. This can be attributed
to a poor choice of sharing flags by the other process.
* B. The other process attempts to open ``foo`` at the point
during the `ReplaceFileW`_ call where it does not exist.
The open call fails, which is acceptable.
* C. The other process opens ``foo`` after it has been linked to
the new file. Then it will read the new contents.
For both write/download and read/download collisions, we have
considered only interleavings with a single other process, and
only the most common possibilities for the other process'
interaction with the file. If multiple other processes are
involved, or if a process performs operations other than those
considered, then we cannot say much about the outcome in general;
however, we believe that such cases will be much less common.
Fire Dragons: Distinguishing conflicts from overwrites
''''''''''''''''''''''''''''''''''''''''''''''''''''''
When synchronizing a file that has changed remotely, the Magic Folder
client needs to distinguish between overwrites, in which the remote
side was aware of your most recent version and overwrote it with a
new version, and conflicts, in which the remote side was unaware of
your most recent version when it published its new version. Those two
cases have to be handled differently — the latter needs to be raised
to the user as an issue the user will have to resolve and the former
must not bother the user.
For example, suppose that Alice's Magic Folder client sees a change
to ``foo`` in Bob's DMD. If the version it downloads from Bob's DMD
is "based on" the version currently in Alice's local filesystem at
the time Alice's client attempts to write the downloaded file, then
it is an overwrite. Otherwise it is initially classified as a
conflict.
This initial classification is used by the procedure for writing a
file described in the `Earth Dragons`_ section above. As explained
in that section, we may reclassify an overwrite as a conflict if an
error occurs during the write procedure.
.. _`Earth Dragons`: #earth-dragons-collisions-between-local-filesystem-operations-and-downloads
In order to implement this policy, we need to specify how the
"based on" relation between file versions is recorded and updated.
We propose to record this information:
* in the `magic folder db`_, for local files;
* in the Tahoe-LAFS directory metadata, for files stored in the
Magic Folder.
In the magic folder db we will add a *last-downloaded record*,
consisting of ``last_downloaded_uri`` and ``last_downloaded_timestamp``
fields, for each path stored in the database. Whenever a Magic Folder
client downloads a file, it stores the downloaded version's URI and
the current local timestamp in this record. Since only immutable
files are used, the URI will be an immutable file URI, which is
deterministically and uniquely derived from the file contents and
the Tahoe-LAFS node's `convergence secret`_.
(Note that the last-downloaded record is updated regardless of
whether the download is an overwrite or a conflict. The rationale
for this to avoid "conflict loops" between clients, where every
new version after the first conflict would be considered as another
conflict.)
.. _`convergence secret`: https://tahoe-lafs.org/trac/tahoe-lafs/browser/docs/convergence-secret.rst
Later, in response to a local filesystem change at a given path, the
Magic Folder client reads the last-downloaded record associated with
that path (if any) from the database and then uploads the current
file. When it links the uploaded file into its client DMD, it
includes the ``last_downloaded_uri`` field in the metadata of the
directory entry, overwriting any existing field of that name. If
there was no last-downloaded record associated with the path, this
field is omitted.
Note that ``last_downloaded_uri`` field does *not* record the URI of
the uploaded file (which would be redundant); it records the URI of
the last download before the local change that caused the upload.
The field will be absent if the file has never been downloaded by
this client (i.e. if it was created on this client and no change
by any other client has been detected).
A possible refinement also takes into account the
``last_downloaded_timestamp`` field from the magic folder db, and
compares it to the timestamp of the change that caused the upload
(which should be later, assuming no system clock changes).
If the duration between these timestamps is very short, then we
are uncertain about whether the process on Bob's system that wrote
the local file could have taken into account the last download.
We can use this information to be conservative about treating
changes as conflicts. So, if the duration is less than a configured
threshold, we omit the ``last_downloaded_uri`` field from the
metadata. This will have the effect of making other clients treat
this change as a conflict whenever they already have a copy of the
file.
Now we are ready to describe the algorithm for determining whether a
download for the file ``foo`` is an overwrite or a conflict (refining
step 2 of the procedure from the `Earth Dragons`_ section).
Let ``last_downloaded_uri`` be the field of that name obtained from
the directory entry metadata for ``foo`` in Bob's DMD (this field
may be absent). Then the algorithm is:
* 2a. If Alice has no local copy of ``foo``, classify as an overwrite.
* 2b. Otherwise, "stat" ``foo`` to get its *current statinfo* (size
in bytes, ``mtime``, and ``ctime``).
* 2c. Read the following information for the path ``foo`` from the
local magic folder db:
* the *last-uploaded statinfo*, if any (this is the size in
bytes, ``mtime``, and ``ctime`` stored in the ``local_files``
table when the file was last uploaded);
* the ``filecap`` field of the ``caps`` table for this file,
which is the URI under which the file was last uploaded.
Call this ``last_uploaded_uri``.
* 2d. If any of the following are true, then classify as a conflict:
* there are pending notifications of changes to ``foo``;
* the last-uploaded statinfo is either absent, or different
from the current statinfo;
* either ``last_downloaded_uri`` or ``last_uploaded_uri``
(or both) are absent, or they are different.
Otherwise, classify as an overwrite.
Air Dragons: Collisions between local writes and uploads
''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Short of filesystem-specific features on Unix or the `shadow copy service`_
on Windows (which is per-volume and therefore difficult to use in this
context), there is no way to *read* the whole contents of a file
atomically. Therefore, when we read a file in order to upload it, we
may read an inconsistent version if it was also being written locally.
.. _`shadow copy service`: https://technet.microsoft.com/en-us/library/ee923636%28v=ws.10%29.aspx
A well-behaved application can avoid this problem for its writes:
* On Unix, if another process modifies a file by renaming a temporary
file onto it, then we will consistently read either the old contents
or the new contents.
* On Windows, if the other process uses sharing flags to deny reads
while it is writing a file, then we will consistently read either
the old contents or the new contents, unless a sharing error occurs.
In the case of a sharing error we should retry later, up to a
maximum number of retries.
In the case of a not-so-well-behaved application writing to a file
at the same time we read from it, the magic folder will still be
eventually consistent, but inconsistent versions may be visible to
other users' clients.
In Objective 2 we implemented a delay, called the *pending delay*,
after the notification of a filesystem change and before the file is
read in order to upload it (Tahoe-LAFS ticket `#1440`_). If another
change notification occurs within the pending delay time, the delay
is restarted. This helps to some extent because it means that if
files are written more quickly than the pending delay and less
frequently than the pending delay, we shouldn't encounter this
inconsistency.
.. _`#1440`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1440
The likelihood of inconsistency could be further reduced, even for
writes by not-so-well-behaved applications, by delaying the actual
upload for a further period —called the *stability delay*— after the
file has finished being read. If a notification occurs between the
end of the pending delay and the end of the stability delay, then
the read would be aborted and the notification requeued.
This would have the effect of ensuring that no write notifications
have been received for the file during a time window that brackets
the period when it was being read, with margin before and after
this period defined by the pending and stability delays. The delays
are intended to account for asynchronous notification of events, and
caching in the filesystem.
Note however that we cannot guarantee that the delays will be long
enough to prevent inconsistency in any particular case. Also, the
stability delay would potentially affect performance significantly
because (unlike the pending delay) it is not overlapped when there
are multiple files on the upload queue. This performance impact
could be mitigated by uploading files in parallel where possible
(Tahoe-LAFS ticket `#1459`_).
We have not yet decided whether to implement the stability delay, and
it is not planned to be implemented for the OTF objective 4 milestone.
Ticket `#2431`_ has been opened to track this idea.
.. _`#1459`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1459
.. _`#2431`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2431
Note that the situation of both a local process and the Magic Folder
client reading a file at the same time cannot cause any inconsistency.
Water Dragons: Handling deletion and renames
''''''''''''''''''''''''''''''''''''''''''''
Deletion of a file
~~~~~~~~~~~~~~~~~~
When a file is deleted from the filesystem of a Magic Folder client,
the most intuitive behavior is for it also to be deleted under that
name from other clients. To avoid data loss, the other clients should
actually rename their copies to a backup filename.
It would not be sufficient for a Magic Folder client that deletes
a file to implement this simply by removing the directory entry from
its DMD. Indeed, the entry may not exist in the client's DMD if it
has never previously changed the file.
Instead, the client links a zero-length file into its DMD and sets
``deleted: true`` in the directory entry metadata. Other clients
take this as a signal to rename their copies to the backup filename.
Note that the entry for this zero-length file has a version number as
usual, and later versions may restore the file.
When a Magic Folder client restarts, we can detect files that had
been downloaded but were deleted while it was not running, because
their paths will have last-downloaded records in the magic folder db
without any corresponding local file.
Deletion of a directory
~~~~~~~~~~~~~~~~~~~~~~~
Local filesystems (unlike a Tahoe-LAFS filesystem) normally cannot
unlink a directory that has any remaining children. Therefore a
Magic Folder client cannot delete local copies of directories in
general, because they will typically contain backup files. This must
be done manually on each client if desired.
Nevertheless, a Magic Folder client that deletes a directory should
set ``deleted: true`` on the metadata entry for the corresponding
zero-length file. This avoids the directory being recreated after
it has been manually deleted from a client.
Renaming
~~~~~~~~
It is sufficient to handle renaming of a file by treating it as a
deletion and an addition under the new name.
This also applies to directories, although users may find the
resulting behavior unintuitive: all of the files under the old name
will be renamed to backup filenames, and a new directory structure
created under the new name. We believe this is the best that can be
done without imposing unreasonable implementation complexity.
Summary
-------
This completes the design of remote-to-local synchronization.
We realize that it may seem very complicated. Anecdotally, proprietary
filesystem synchronization designs we are aware of, such as Dropbox,
are said to incur similar or greater design complexity.

View File

@ -0,0 +1,207 @@
Magic Folder user interface design
==================================
Scope
-----
In this Objective we will design a user interface to allow users to conveniently
and securely indicate which folders on some devices should be "magically" linked
to which folders on other devices.
This is a critical usability and security issue for which there is no known perfect
solution, but which we believe is amenable to a "good enough" trade-off solution.
This document explains the design and justifies its trade-offs in terms of security,
usability, and time-to-market.
Tickets on the Tahoe-LAFS trac with the `otf-magic-folder-objective6`_
keyword are within the scope of the user interface design.
.. _otf-magic-folder-objective6: https://tahoe-lafs.org/trac/tahoe-lafs/query?status=!closed&keywords=~otf-magic-folder-objective6
Glossary
''''''''
Object: a file or directory
DMD: distributed mutable directory
Folder: an abstract directory that is synchronized between clients.
(A folder is not the same as the directory corresponding to it on
any particular client, nor is it the same as a DMD.)
Collective: the set of clients subscribed to a given Magic Folder.
Diminishing: the process of deriving, from an existing capability,
another capability that gives less authority (for example, deriving a
read cap from a read/write cap).
Design Constraints
------------------
The design of the Tahoe-side representation of a Magic Folder, and the polling
mechanism that the Magic Folder clients will use to detect remote changes was
discussed in `<remote-to-local-sync.rst>`_, and we will not revisit that here.
The assumption made by that design was that each client would be configured with
the following information:
* a write cap to its own *client DMD*.
* a read cap to a *collective directory*.
The collective directory contains links to each client DMD named by the
corresponding client's nickname.
This design was chosen to allow straightforward addition of clients without
requiring each existing client to change its configuration.
Note that each client in a Magic Folder collective has the authority to add,
modify or delete any object within the Magic Folder. It is also able to control
to some extent whether its writes will be treated by another client as overwrites
or as conflicts. However, there is still a reliability benefit to preventing a
client from accidentally modifying another client's DMD, or from accidentally
modifying the collective directory in a way that would lose data. This motivates
ensuring that each client only has access to the caps above, rather than, say,
every client having a write cap to the collective directory.
Another important design constraint is that we cannot violate the
`write coordination directive`_; that is, we cannot write to the same mutable
directory from multiple clients, even during the setup phase when adding a
client.
.. _`write coordination directive`: ../../write_coordination.rst
Within these constraints, for usability we want to minimize the number of steps
required to configure a Magic Folder collective.
Proposed Design
---------------
Three ``tahoe`` subcommands are added::
tahoe magic-folder create MAGIC: [MY_NICKNAME LOCAL_DIR]
Create an empty Magic Folder. The MAGIC: local alias is set
to a write cap which can be used to refer to this Magic Folder
in future ``tahoe magic-folder invite`` commands.
If MY_NICKNAME and LOCAL_DIR are given, the current client
immediately joins the newly created Magic Folder with that
nickname and local directory.
tahoe magic-folder invite MAGIC: THEIR_NICKNAME
Print an "invitation" that can be used to invite another
client to join a Magic Folder, with the given nickname.
The invitation must be sent to the user of the other client
over a secure channel (e.g. PGP email, OTR, or ssh).
This command will normally be run by the same client that
created the Magic Folder. However, it may be run by a
different client if the ``MAGIC:`` alias is copied to
the ``private/aliases`` file of that other client, or if
``MAGIC:`` is replaced by the write cap to which it points.
tahoe magic-folder join INVITATION LOCAL_DIR
Accept an invitation created by ``tahoe magic-folder invite``.
The current client joins the specified Magic Folder, which will
appear in the local filesystem at the given directory.
There are no commands to remove a client or to revoke an
invitation, although those are possible features that could
be added in future. (When removing a client, it is necessary
to copy each file it added to some other client's DMD, if it
is the most recent version of that file.)
Implementation
''''''''''''''
For "``tahoe magic-folder create MAGIC: [MY_NICKNAME LOCAL_DIR]``" :
1. Run "``tahoe create-alias MAGIC:``".
2. If ``MY_NICKNAME`` and ``LOCAL_DIR`` are given, do the equivalent of::
INVITATION=`tahoe invite-magic-folder MAGIC: MY_NICKNAME`
tahoe join-magic-folder INVITATION LOCAL_DIR
For "``tahoe magic-folder invite COLLECTIVE_WRITECAP NICKNAME``" :
(``COLLECTIVE_WRITECAP`` can, as a special case, be an alias such as ``MAGIC:``.)
1. Create an empty client DMD. Let its write URI be ``CLIENT_WRITECAP``.
2. Diminish ``CLIENT_WRITECAP`` to ``CLIENT_READCAP``, and
diminish ``COLLECTIVE_WRITECAP`` to ``COLLECTIVE_READCAP``.
3. Run "``tahoe ln CLIENT_READCAP COLLECTIVE_WRITECAP/NICKNAME``".
4. Print "``COLLECTIVE_READCAP+CLIENT_WRITECAP``" as the invitation,
accompanied by instructions on how to accept the invitation and
the need to send it over a secure channel.
For "``tahoe magic-folder join INVITATION LOCAL_DIR``" :
1. Parse ``INVITATION`` as ``COLLECTIVE_READCAP+CLIENT_WRITECAP``.
2. Write ``CLIENT_WRITECAP`` to the file ``magic_folder_dircap``
under the client's ``private`` directory.
3. Write ``COLLECTIVE_READCAP`` to the file ``collective_dircap``
under the client's ``private`` directory.
4. Edit the client's ``tahoe.cfg`` to set
``[magic_folder] enabled = True`` and
``[magic_folder] local.directory = LOCAL_DIR``.
Discussion
----------
The proposed design has a minor violation of the
`Principle of Least Authority`_ in order to reduce the number
of steps needed. The invoker of "``tahoe magic-folder invite``"
creates the client DMD on behalf of the invited client, and
could retain its write cap (which is part of the invitation).
.. _`Principle of Least Authority`: http://www.eros-os.org/papers/secnotsep.pdf
A possible alternative design would be for the invited client
to create its own client DMD, and send it back to the inviter
to be linked into the collective directory. However this would
require another secure communication and another command
invocation per client. Given that, as mentioned earlier, each
client in a Magic Folder collective already has the authority
to add, modify or delete any object within the Magic Folder,
we considered the potential security/reliability improvement
here not to be worth the loss of usability.
We also considered a design where each client had write access
to the collective directory. This would arguably be a more
serious violation of the Principle of Least Authority than the
one above (because all clients would have excess authority rather
than just the inviter). In any case, it was not clear how to make
such a design satisfy the `write coordination directive`_,
because the collective directory would have needed to be written
to by multiple clients.
The reliance on a secure channel to send the invitation to its
intended recipient is not ideal, since it may involve additional
software such as clients for PGP, OTR, ssh etc. However, we believe
that this complexity is necessary rather than incidental, because
there must be some way to distinguish the intended recipient from
potential attackers who would try to become members of the Magic
Folder collective without authorization. By making use of existing
channels that have likely already been set up by security-conscious
users, we avoid reinventing the wheel or imposing substantial extra
implementation costs.
The length of an invitation will be approximately the combined
length of a Tahoe-LAFS read cap and write cap. This is several
lines long, but still short enough to be cut-and-pasted successfully
if care is taken. Errors in copying the invitation can be detected
since Tahoe-LAFS cap URIs are self-authenticating.
The implementation of the ``tahoe`` subcommands is straightforward
and raises no further difficult design issues.

76
docs/quickstart.rst Normal file
View File

@ -0,0 +1,76 @@
.. -*- coding: utf-8-with-signature-unix; fill-column: 77 -*-
==================
Getting Tahoe-LAFS
==================
Welcome to `the Tahoe-LAFS project`_, a secure, decentralized, fault-tolerant
storage system.
`about Tahoe-LAFS <about.rst>`__
.. _the Tahoe-LAFS project: https://tahoe-lafs.org
How To Get Tahoe-LAFS
=====================
This procedure has been verified to work on Windows, Mac, OpenSolaris, and
too many flavors of Linux and of BSD to list.
In Case Of Trouble
------------------
There are a few 3rd party libraries that Tahoe-LAFS depends on that might not
be easy to set up on your platform. If the following instructions don't Just
Work without any further effort on your part, then please write to `the
tahoe-dev mailing list`_ where friendly hackers will help you out.
.. _the tahoe-dev mailing list: https://tahoe-lafs.org/cgi-bin/mailman/listinfo/tahoe-dev
Install Python
--------------
Check if you already have an adequate version of Python installed by running
``python -V``. Python v2.6 (v2.6.6 or greater recommended) or Python v2.7
will work. Python v3 does not work. On Windows, we recommend the use of
native Python v2.7, not Cygwin Python. If you don't have one of these
versions of Python installed, `download`_ and install the latest version of
Python v2.7. Make sure that the path to the installation directory has no
spaces in it (e.g. on Windows, do not install Python in the "Program Files"
directory).
.. _download: https://www.python.org/downloads/
Get Tahoe-LAFS
--------------
Download the latest stable release, `Tahoe-LAFS v1.10.1`_.
.. _Tahoe-LAFS v1.10.1: https://tahoe-lafs.org/source/tahoe-lafs/releases/allmydata-tahoe-1.10.1.zip
Set Up Tahoe-LAFS
-----------------
Unpack the zip file and cd into the top-level directory.
Run "``python setup.py build``" to generate the ``tahoe`` executable in a
subdirectory of the current directory named ``bin``. This will download and
build anything you need from various websites.
On Windows, the ``build`` step might tell you to open a new Command Prompt
(or, on XP and earlier, to log out and back in again). This is needed the
first time you set up Tahoe-LAFS on a particular installation of Windows.
Run "``bin/tahoe --version``" (on Windows, "``bin\tahoe --version``") to
verify that the executable tool prints out the right version number after
"``allmydata-tahoe:``".
Optionally run "``python setup.py trial``" to verify that it passes all of
its self-tests.
Run Tahoe-LAFS
--------------
Now you are ready to deploy a decentralized filesystem. The ``tahoe``
executable in the ``bin`` directory can configure and launch your Tahoe-LAFS
nodes. See `<running.rst>`__ for instructions on how to do that.

View File

@ -1,266 +0,0 @@
=================
Release Checklist
=================
This release checklist specifies a series of checks that anyone engaged in
releasing a version of Tahoe should follow.
Any contributor can do the first part of the release preparation. Only
certain contributors can perform other parts. These are the two main
sections of this checklist (and could be done by different people).
A final section describes how to announce the release.
This checklist is based on the original instructions (in old revisions in the file
`docs/how_to_make_a_tahoe-lafs_release.org`).
Any Contributor
===============
Anyone who can create normal PRs should be able to complete this
portion of the release process.
Prepare for the Release
```````````````````````
The `master` branch should always be releasable.
It may be worth asking (on IRC or mailing-ist) if anything will be
merged imminently (for example, "I will prepare a release this coming
Tuesday if you want to get anything in").
- Create a ticket for the release in Trac
- Ticket number needed in next section
- Making first release? See `GPG Setup Instructions <gpg-setup.rst>`__ to make sure you can sign releases. [One time setup]
Get a clean checkout
````````````````````
The release proccess involves compressing source files and putting them in formats
suitable for distribution such as ``.tar.gz`` and ``zip``. That said, it's neccesary to
the release process begins with a clean checkout to avoid making a release with
previously generated files.
- Inside the tahoe root dir run ``git clone . ../tahoe-release-x.x.x`` where (x.x.x is the release number such as 1.16.0).
.. note::
The above command would create a new directory at the same level as your original clone named ``tahoe-release-x.x.x``. You can name this folder however you want but it would be a good
practice to give it the release name. You MAY also discard this directory once the release
process is complete.
Get into the release directory and install dependencies by running
- cd ../tahoe-release-x.x.x (assuming you are still in your original clone)
- python -m venv venv
- ./venv/bin/pip install --editable .[test]
Create Branch and Apply Updates
```````````````````````````````
- Create a branch for the release/candidate (e.g. ``XXXX.release-1.16.0``)
- run tox -e news to produce a new NEWS.txt file (this does a commit)
- create the news for the release
- newsfragments/<ticket number>.minor
- commit it
- manually fix NEWS.txt
- proper title for latest release ("Release 1.16.0" instead of "Release ...post1432")
- double-check date (maybe release will be in the future)
- spot-check the release notes (these come from the newsfragments
files though so don't do heavy editing)
- commit these changes
- update "relnotes.txt"
- update all mentions of ``1.16.0`` to new and higher release version for example ``1.16.1``
- update "previous release" statement and date
- summarize major changes
- commit it
- update "nix/tahoe-lafs.nix"
- change the value given for `version` from `OLD.post1` to `NEW.post1`
- update "docs/known_issues.rst" if appropriate
- Push the branch to github
- Create a (draft) PR; this should trigger CI (note that github
doesn't let you create a PR without some changes on the branch so
running + committing the NEWS.txt file achieves that without changing
any code)
- Confirm CI runs successfully on all platforms
Create Release Candidate
````````````````````````
Before "officially" tagging any release, we will make a
release-candidate available. So there will be at least 1.15.0rc0 (for
example). If there are any problems, an rc1 or rc2 etc may also be
released. Anyone can sign these releases (ideally they'd be signed
"officially" as well, but it's better to get them out than to wait for
that).
Typically expert users will be the ones testing release candidates and
they will need to evaluate which contributors' signatures they trust.
- (all steps above are completed)
- sign the release
- git tag -s -u 0xE34E62D06D0E69CFCA4179FFBDE0D31D68666A7A -m "release Tahoe-LAFS-1.16.0rc0" tahoe-lafs-1.16.0rc0
.. note::
- Replace the key-id above with your own, which can simply be your email if it's attached to your fingerprint.
- Don't forget to put the correct tag message and name. In this example, the tag message is "release Tahoe-LAFS-1.16.0rc0" and the tag name is ``tahoe-lafs-1.16.0rc0``
- build all code locally
- these should all pass:
- tox -e py37,codechecks,docs,integration
- these can fail (ideally they should not of course):
- tox -e deprecations,upcoming-deprecations
- clone to a clean, local checkout (to avoid extra files being included in the release)
- cd /tmp
- git clone /home/meejah/src/tahoe-lafs
- build tarballs
- tox -e tarballs
- Confirm that release tarballs exist by runnig:
- ls dist/ | grep 1.16.0rc0
- inspect and test the tarballs
- install each in a fresh virtualenv
- run `tahoe` command
- when satisfied, sign the tarballs:
- gpg --pinentry=loopback --armor -u 0xE34E62D06D0E69CFCA4179FFBDE0D31D68666A7A --detach-sign dist/tahoe_lafs-1.16.0rc0-py2.py3-none-any.whl
- gpg --pinentry=loopback --armor --detach-sign dist/tahoe_lafs-1.16.0rc0.tar.gz
Privileged Contributor
======================
Steps in this portion require special access to keys or
infrastructure. For example, **access to tahoe-lafs.org** to upload
binaries or edit HTML.
Hack Tahoe-LAFS
```````````````
Did anyone contribute a hack since the last release? If so, then
https://tahoe-lafs.org/hacktahoelafs/ needs to be updated.
Sign Git Tag
````````````
- git tag -s -u 0xE34E62D06D0E69CFCA4179FFBDE0D31D68666A7A -m "release Tahoe-LAFS-X.Y.Z" tahoe-lafs-X.Y.Z
Upload Artifacts
````````````````
Any release-candidate or actual release plus signature (.asc file)
need to be uploaded to https://tahoe-lafs.org in `~source/downloads`
- secure-copy all release artifacts to the download area on the
tahoe-lafs.org host machine. `~source/downloads` on there maps to
https://tahoe-lafs.org/downloads/ on the Web:
- scp dist/*1.15.0* username@tahoe-lafs.org:/home/source/downloads
- the following developers have access to do this:
- exarkun
- meejah
- warner
Push the signed tag to the main repository:
- git push origin tahoe-lafs-1.17.1
For the actual release, the tarball and signature files need to be
uploaded to PyPI as well.
- ls dist/*1.19.0*
- twine upload --username __token__ --password `cat SECRET-pypi-tahoe-publish-token` dist/*1.19.0*
The following developers have access to do this:
- warner
- meejah
- exarkun (partial?)
Announcing the Release Candidate
````````````````````````````````
The release-candidate should be announced by posting to the
mailing-list (tahoe-dev@lists.tahoe-lafs.org). For example:
https://lists.tahoe-lafs.org/pipermail/tahoe-dev/2020-October/009978.html
Is The Release Done Yet?
````````````````````````
If anyone reports a problem with a release-candidate then a new
release-candidate should be made once a fix has been merged to
master. Repeat the above instructions with `rc1` or `rc2` or whatever
is appropriate.
Once a release-candidate has marinated for some time then it can be
made into a the actual release.
The actual release follows the same steps as above, with some differences:
- there is no "-rcX" on the end of release names
- the release is uploaded to PyPI (using Twine)
- the version is tagged in Git (ideally using "the tahoe release key"
but can be done with any of the authorized core developers' personal
key)
- the release-candidate branches must be merged back to master after
the release is official (e.g. causing newsfragments to be deleted on
master, etc)
Announcing the Release
----------------------
mailing-lists
`````````````
A new Tahoe release is traditionally announced on our mailing-list
(tahoe-dev@tahoe-lafs.org). The former version of these instructions
also announced the release on the following other lists:
- tahoe-announce@tahoe-lafs.org
- twisted-python@twistedmatrix.com
- liberationtech@lists.stanford.edu
- lwn@lwn.net
- p2p-hackers@lists.zooko.com
- python-list@python.org
- http://listcultures.org/pipermail/p2presearch_listcultures.org/
- cryptopp-users@googlegroups.com
wiki
````
Edit the "News" section of the front page of https://tahoe-lafs.org
with a link to the mailing-list archive of the announcement message.

Some files were not shown because too many files have changed in this diff Show More