Compare commits

..

1 Commits

Author SHA1 Message Date
Daira Hopwood 69a2979040 Further refine error handling in windows_getenv to avoid a Win32 API design flaw.
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
2015-02-04 16:49:40 +00:00
642 changed files with 65251 additions and 104017 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>`__.

77
CREDITS
View File

@ -8,8 +8,7 @@ Thanks.
----------
N: Brian Warner
E: warner@lothar.com
P: A476 E2E6 1188 0C98 5B3C 3A39 0386 E81B 11CA A07A
E: warner-tahoe@lothar.com
D: main developer
N: Zooko
@ -113,8 +112,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 +182,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 +191,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

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

349
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,121 @@ test-py3-all: .tox/create-venvs.log
make-version:
$(PYTHON) ./setup.py update_version
# Build OS X pkg packages.
.PHONY: build-osx-pkg
build-osx-pkg:
misc/build_helpers/build-osx-pkg.sh $(APPNAME)
.built:
$(MAKE) build
.PHONY: test-osx-pkg
test-osx-pkg:
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.
# The editing of .egg-link and .pth files ensures that we reference the source at the correct path.
.PHONY: build-osx-pkg
build-osx-pkg: build
find support -name $(APPNAME).egg-link -execdir sh -c "echo >> {}; echo /Applications/tahoe.app/src >> {}" \;
find support -name easy-install.pth -execdir sed -i.bak 's|^.*/src$$|../../../../src|' '{}' \;
# create component pkg
pkgbuild --root $(shell pwd) \
--identifier com.leastauthority.tahoe \
--version $(shell sh -c "cat src/allmydata/_version.py | grep verstr | head -n 1 | cut -d' ' -f 3") \
--ownership recommended \
--install-location /Applications/tahoe.app \
--scripts $(shell pwd)/misc/build_helpers/osx/scripts \
tahoe-lafs.pkg
# create product archive
productbuild --distribution $(shell pwd)/misc/build_helpers/osx/Distribution.xml \
--package-path . \
tahoe-lafs-osx.pkg
# remove intermediate pkg
rm -f tahoe-lafs.pkg
# test the result
$(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
# 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 +143,7 @@ check-miscaptures:
.PHONY: pyflakes
pyflakes:
$(PYFLAKES) $(SOURCES) |sort |uniq
@$(PYTHON) -OOu `which pyflakes` $(SOURCES) |sort |uniq
@echo
.PHONY: check-umids
@ -132,23 +175,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 +255,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 +282,31 @@ 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"
# 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

1362
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 Software/Open Source decentralized data store. It
distributes your filesystem across multiple servers, and even if some of the
servers fail or are taken over by an attacker, the entire filesystem continues
to work correctly and to preserve 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-2014 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

@ -1,112 +0,0 @@
Building pyOpenSSL on Windows
=============================
This document details the steps to build an pyOpenSSL egg with embedded
OpenSSL library, for use by Tahoe-LAFS on Windows.
The instructions were tried on Windows 7 64-bit and Windows XP 32-bit.
They should work on other versions of Windows, maybe with minor variations.
Download and install Microsoft Visual C++ compiler for Python 2.7
-----------------------------------------------------------------
For reasons detailed in `the Python documentation`_, Python extension modules
need to be built using a compiler compatible with the same version of Visual C++
that was used to build Python itself. Until recently, this meant downloading
Microsoft Visual Studio 2008 Express Edition and Windows SDK 3.5. The recent
release of the Microsoft Visual C++ compiler for Python 2.7 made things a lot
simpler.
So, the first step is to download and install the C++ compiler from Microsoft
from `this link`_.
Find the location where it installed the ``vcvarsall.bat`` file; depending on
the version of Windows it could be either
``"%USERPROFILE%\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0"``
or ``"%CommonProgramFiles%\Microsoft\Visual C++ for Python\9.0"``, for example.
We'll call this ``%VCDIR%`` below.
.. _the Python documentation: https://docs.python.org/2/extending/windows.html
.. _this link: https://www.microsoft.com/en-us/download/details.aspx?id=44266
Download and install Perl
-------------------------
Download and install ActiveState Perl:
* go to `the ActiveState Perl download page`_.
* identify the correct link and manually change it from http to https.
.. _the ActiveState Perl download page: https://www.activestate.com/activeperl/downloads
Download and install the latest OpenSSL version
-----------------------------------------------
* Download the latest OpenSSL from `the OpenSSL source download page`_ and untar it.
At the time of writing, the latest version was OpenSSL 1.0.1m.
* Set up the build environment. For 64-bit Windows::
"%VCDIR%\vcvarsall.bat" amd64
or for 32-bit Windows::
"%VCDIR%\vcvarsall.bat" x86
* Go to the untar'ed OpenSSL source base directory. For 64-bit Windows, run::
mkdir c:\dist
perl Configure VC-WIN64A --prefix=c:\dist\openssl no-asm enable-tlsext
ms\do_win64a.bat
nmake -f ms\ntdll.mak
nmake -f ms\ntdll.mak install
or for 32-bit Windows, run::
mkdir c:\dist
perl Configure VC-WIN32 --prefix=c:\dist\openssl no-asm enable-tlsext
ms\do_ms.bat
nmake -f ms\ntdll.mak
nmake -f ms\ntdll.mak install
To check that it is working, run ``c:\dist\openssl\bin\openssl version``.
.. _the OpenSSL source download page: https://www.openssl.org/source/
Building PyOpenSSL
------------------
* Download and untar pyOpenSSL 0.13.1 (see `ticket #2221`_ for why we
currently use this version). The MD5 hash of pyOpenSSL-0.13.1.tar.gz is
e27a3b76734c39ea03952ca94cc56715.
* Set up the build environment by running ``vcvarsall.bat`` as for building
OpenSSL above.
* Set OpenSSL ``LIB``, ``INCLUDE`` and ``PATH``::
set LIB=c:\dist\openssl\lib;%LIB%
set INCLUDE=c:\dist\openssl\include;%INCLUDE%
set PATH=c:\dist\openssl\bin;%PATH%
* A workaround is needed to ensure that the setuptools ``bdist_egg`` command
is available. Edit pyOpenSSL's ``setup.py`` around line 13 as follows::
< from distutils.core import Extension, setup
---
> from setuptools import setup
> from distutils.core import Extension
* Run ``python setup.py bdist_egg``
The generated egg will be in the ``dist`` directory. It is a good idea
to check that Tahoe-LAFS is able to use it before uploading the egg to
tahoe-lafs.org. This can be done by putting it in the ``tahoe-deps`` directory
of a Tahoe-LAFS checkout or release, then running ``python setup.py test``.
.. _ticket #2221: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2221

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,61 @@ 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
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 host:port location hints, like
this::
The value is a comma-separated string of method: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
tub.port = 8098
tub.location = 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::
has been configured to forward 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
* 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 = 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 +191,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 +208,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 +262,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 +287,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 +297,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 +306,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 +342,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 +380,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 +401,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 +443,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 +487,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 +503,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 +533,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 +555,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 +570,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 +599,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 +631,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 +661,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,29 +676,27 @@ 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
readonly = True
reserved_space = 10000000000
[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 +704,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. [TODO] Another way to indicate this is to start
the pathname with a dot, slash, or tilde.
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``
@ -433,21 +455,6 @@ Command Examples
all source arguments which are directories will be copied into new
subdirectories of the target.
The behavior of ``tahoe cp``, like the regular UNIX ``/bin/cp``, is subtly
different depending upon the exact form of the arguments. In particular:
* Trailing slashes indicate directories, but are not required.
* If the target object does not already exist:
* and if the source is a single file, it will be copied into the target;
* otherwise, the target will be created as a directory.
* If there are multiple sources, the target must be a directory.
* If the target is a pre-existing file, the source must be a single file.
* If the target is a directory, each source must be a named file, a named
directory, or an unnamed directory. It is not possible to copy an unnamed
file (e.g. a raw filecap) into a directory, as there is no way to know what
the new file should be named.
``tahoe unlink uploaded.txt``
``tahoe unlink tahoe:uploaded.txt``
@ -514,10 +521,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 +615,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
@ -349,14 +350,6 @@ Reading a File
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 "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.
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
"Browser Operations", for details on how to modify these URLs for that
@ -419,7 +412,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 +428,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 +504,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.
@ -539,7 +532,7 @@ Creating a New Directory
checking that they are immutable. The "imm." prefix must not be stripped
off without performing this check. (Future versions of the web-API server
will perform it where necessary.)
The cap for each child may be given either in the "rw_uri" or "ro_uri"
field of the PROPDICT (not both). If a cap is given in the "rw_uri" field,
then the web-API server will check that it is an immutable read-cap of a
@ -595,7 +588,7 @@ Creating a New Directory
format of the named target directory; intermediate directories, if created,
are created using the default mutable type setting, as configured on the
Tahoe-LAFS server responding to the request.
This operation will return an error if a blocking file is present at any of
the parent names, preventing the server from creating the necessary parent
directory; or if it would require changing an immutable directory; or if
@ -655,7 +648,7 @@ Creating a New Directory
the immediate parent directory already has a a child named NAME.
Note that the name= argument must be passed as a queryarg, because the POST
request body is used for the initial children JSON.
request body is used for the initial children JSON.
``POST /uri/$DIRCAP/[SUBDIRS../]?t=mkdir-immutable&name=NAME``
@ -670,6 +663,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)
-------------------------------------------------------
@ -770,7 +765,7 @@ Getting Information About a File Or Directory (as JSON)
if and only if you have read-write access to that directory. The verify_uri
field will be present if and only if the object has a verify-cap
(non-distributed LIT files do not have verify-caps).
If the cap is of an unknown format, then the file size and verify_uri will
not be available::
@ -807,8 +802,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 +830,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.
@ -861,11 +856,11 @@ When an edge is created or updated by "tahoe backup", the 'mtime' and
the UNIX "ctime" of the local file, which means the last time that
either the contents or the metadata of the local file was changed.
There are several ways that the 'ctime' field could be confusing:
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 +890,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.
@ -917,7 +912,7 @@ Attaching an Existing File or Directory by its read- or write-cap
command). Note that "true", "t", and "1" are all synonyms for "True", and
"false", "f", and "0" are synonyms for "False", and the parameter is
case-insensitive.
Note that this operation does not take its child cap in the form of
separate "rw_uri" and "ro_uri" fields. Therefore, it cannot accept a
child cap in a format unknown to the web-API server, unless its URI
@ -966,7 +961,7 @@ Adding Multiple Files or Directories to a Parent Directory at Once
currently placed here are "linkcrtime" and "linkmotime". For details, see
the section above entitled "Getting Information About a File Or Directory (as
JSON)", in the "About the metadata" subsection.
Note that this command was introduced with the name "set_children", which
uses an underscore rather than a hyphen as other multi-word command names
do. The variant with a hyphen is now accepted, but clients that desire
@ -1008,9 +1003,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 +1035,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 +1052,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 +1100,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,12 +1143,12 @@ 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::
<form action="/uri" method="POST" enctype="multipart/form-data">
<input type="hidden" name="t" value="upload" />
<input type="file" name="file" />
@ -1182,7 +1175,7 @@ Uploading a File
This uploads a file, and attaches it as a new child of the given directory,
which must be mutable. The file must be provided as the "file" field of an
HTML-encoded form body, produced in response to an HTML form like this::
<form action="." method="POST" enctype="multipart/form-data">
<input type="hidden" name="t" value="upload" />
<input type="file" name="file" />
@ -1312,9 +1305,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 +1416,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 +1462,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 +1693,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 +1745,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 +1824,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 +1834,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 +1985,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 +2009,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 +2077,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 +2104,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 +2116,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 +2126,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 +2186,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,77 @@
* 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 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
- [ ] 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, released 01-May-2013
======================================================
* `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

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.0`_.
.. _Tahoe-LAFS v1.10.0: https://tahoe-lafs.org/source/tahoe-lafs/releases/allmydata-tahoe-1.10.0.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.

View File

@ -1,4 +0,0 @@
sphinx
docutils<0.18 # https://github.com/sphinx-doc/sphinx/issues/9788
recommonmark
sphinx_rtd_theme

View File

@ -1,21 +1,21 @@
.. -*- coding: utf-8-with-signature-unix; fill-column: 73; -*-
.. -*- indent-tabs-mode: nil -*-
*********************
=====================
How To Run Tahoe-LAFS
*********************
=====================
Introduction
============
Intro
=====
This is how to run a Tahoe-LAFS client or a complete Tahoe-LAFS grid.
First you have to install the Tahoe-LAFS software, as documented in
:doc:`Installing Tahoe-LAFS <../Installation/install-tahoe>`.
quickstart.rst_.
The ``tahoe`` program in your virtualenv's ``bin`` directory is used to
create, start, and stop nodes. Each node lives in a separate base
directory, in which there is a configuration file named ``tahoe.cfg``.
Nodes read and write files within this base directory.
The ``tahoe`` program in the ``bin`` directory is used to create,
start, and stop nodes. Each node lives in a separate base directory, in
which there is a configuration file named ``tahoe.cfg``. Nodes read and
write files within this base directory.
A grid consists of a set of *storage nodes* and *client nodes* running
the Tahoe-LAFS code. There is also an *introducer node* that is
@ -26,156 +26,57 @@ grid`_ as you only need to create a client node. When you want to create your
own grid you'll need to create the introducer and several initial storage
nodes (see the note about small grids below).
Being Introduced to a Grid
--------------------------
A collection of Tahoe servers is called a Grid and usually has 1
Introducer (but sometimes more, and it's possible to run with zero). The
Introducer announces which storage servers constitute the Grid and how to
contact them. There is a secret "fURL" you need to know to talk to the
Introducer.
One way to get this secret is using traditional tools such as encrypted
email, encrypted instant-messaging, etcetera. It is important to transmit
this fURL secretly as knowing it gives you access to the Grid.
An additional way to share the fURL securely is via `magic
wormhole`_. This uses a weak one-time password and a server on the
internet (at `wormhole.tahoe-lafs.org`) to open a secure channel between
two computers. In Tahoe-LAFS this functions via the commands `tahoe
invite` and `tahoe create-client --join`. A person who already has access
to a Grid can use `tahoe invite` to create one end of the `magic
wormhole`_ and then transmits some JSON (including the Introducer's
secret fURL) to the other end. `tahoe invite` will print a one-time
secret code; you must then communicate this code to the person who will
join the Grid.
The other end of the `magic wormhole`_ in this case is `tahoe
create-client --join <one-time code>`, where the person being invited
types in the code they were given. Ideally, this code would be
transmitted securely. It is, however, only useful exactly once. Also, it
is much easier to transcribe by a human. Codes look like
`7-surrender-tunnel` (a short number and two words).
Running a Client
----------------
If the Tahoe-LAFS ``bin`` directory is not on your PATH, then in all
the command lines below, specify the full path to ``bin/tahoe``.
To construct a client node, run “``tahoe create-client``”, which will create
``~/.tahoe`` to be the node's base directory. Acquire the ``introducer.furl``
(see below if you are running your own introducer, or use the one from the
`TestGrid page`_), and write it to ``~/.tahoe/private/introducers.yaml``
(see :ref:`introducer-definitions`). Then use “``tahoe run ~/.tahoe``”.
After that, the node should be off and running. The first thing
`TestGrid page`_), and paste it after ``introducer.furl =`` in the
``[client]`` section of ``~/.tahoe/tahoe.cfg``. Then use “``tahoe run
~/.tahoe``”. After that, the node should be off and running. The first thing
it will do is connect to the introducer and get itself connected to all other
nodes on the grid.
Some Grids use "magic wormhole" one-time codes to configure the basic
options. In such a case you use ``tahoe create-client --join
<one-time-code>`` and do not have to do any of the ``tahoe.cfg`` editing
mentioned above.
By default, “``tahoe create-client``” creates a client-only node, that
does not offer its disk space to other nodes. To configure other behavior,
use “``tahoe create-node``” or see :doc:`configuration`.
use “``tahoe create-node``” or see configuration.rst_.
To construct an introducer, create a new base directory for it (the
name of the directory is up to you), ``cd`` into it, and run
``tahoe create-introducer .``”. Now run the introducer using
``tahoe start .``”. After it starts, it will write a file named
``introducer.furl`` into the ``private/`` subdirectory of that base
directory. This file contains the URL the other nodes must use in order
to connect to this introducer. (Note that “``tahoe run .``” doesn't
work for introducers, this is a known issue: `#937`_.)
The “``tahoe run``” command above will run the node in the foreground.
``tahoe --help`` gives a summary of all commands.
On Unix, you can run it in the background instead by using the
``tahoe start``” command. To stop a node started in this way, use
``tahoe stop``”. ``tahoe --help`` gives a summary of all commands.
See configuration.rst_ for more details about how to configure Tahoe-LAFS,
including how to get other clients to connect to your node if it is behind a
firewall or NAT device.
Running a Server or Introducer
------------------------------
To build either a storage server node, or an introducer node, you'll need
a way for clients to connect to it. The simplest case is when the
computer is on the public internet (e.g. a "VPS" virtual private server,
with a public IP address and a DNS hostname like ``example.net``). See
:doc:`servers` for help with more complex scenarios, using the ``--port``
and ``--location`` arguments.
To construct an introducer, create a new base directory for it (the name
of the directory is up to you), ``cd`` into it, and run “``tahoe
create-introducer --hostname=example.net .``” (but using the hostname of
your VPS). Now run the introducer using “``tahoe run .``”. After it
starts, it will write a file named ``introducer.furl`` into the
``private/`` subdirectory of that base directory. This file contains the
URL the other nodes must use in order to connect to this introducer.
You can distribute your Introducer fURL securely to new clients by using
the ``tahoe invite`` command. This will prepare some JSON to send to the
other side, request a `magic wormhole`_ code from
``wormhole.tahoe-lafs.org`` and print it out to the terminal. This
one-time code should be transmitted to the user of the client, who can
then run ``tahoe create-client --join <one-time-code>``.
Storage servers are created the same way: ``tahoe create-node
--hostname=HOSTNAME .`` from a new directory. You'll need to provide the
introducer FURL (either as a ``--introducer=`` argument, or by editing
the ``tahoe.cfg`` configuration file afterwards) to connect to the
introducer of your choice.
See :doc:`configuration` for more details about how to configure
Tahoe-LAFS.
.. _quickstart.rst: quickstart.rst
.. _public test grid: https://tahoe-lafs.org/trac/tahoe-lafs/wiki/TestGrid
.. _TestGrid page: https://tahoe-lafs.org/trac/tahoe-lafs/wiki/TestGrid
.. _configuration.rst: configuration.rst
.. _#937: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/937
.. _magic wormhole: https://magic-wormhole.io/
Multiple Instances
------------------
Running multiple instances against the same configuration directory isn't supported.
This will lead to undefined behavior and could corrupt the configuration or state.
We attempt to avoid this situation with a "pidfile"-style file in the config directory called ``running.process``.
There may be a parallel file called ``running.process.lock`` in existence.
The ``.lock`` file exists to make sure only one process modifies ``running.process`` at once.
The lock file is managed by the `lockfile <https://pypi.org/project/lockfile/>`_ library.
If you wish to make use of ``running.process`` for any reason you should also lock it and follow the semantics of lockfile.
If ``running.process`` exists then it contains the PID and the creation-time of the process.
When no such file exists, there is no other process running on this configuration.
If there is a ``running.process`` file, it may be a leftover file or it may indicate that another process is running against this config.
To tell the difference, determine if the PID in the file exists currently.
If it does, check the creation-time of the process versus the one in the file.
If these match, there is another process currently running and using this config.
Otherwise, the file is stale -- it should be removed before starting Tahoe-LAFS.
Some example Python code to check the above situations:
.. literalinclude:: check_running.py
A note about small grids
------------------------
By default, Tahoe-LAFS ships with the configuration parameter
``shares.happy`` set to 7. If you are using Tahoe-LAFS on a grid with
fewer than 7 storage nodes, this won't work well for you — none of your
uploads will succeed. To fix this, see :doc:`configuration` to learn how
to set ``shares.happy`` to a more suitable value for your grid.
``shares.happy`` set to 7. If you are using Tahoe-LAFS on a grid with fewer
than 7 storage nodes, this won't work well for you — none of your uploads
will succeed. To fix this, see configuration.rst_ to learn how to set
``shares.happy`` to a more suitable value for your grid.
Development with Docker
-----------------------
If you want to stand up a small local test environment, you can install
`Docker`_ and `Docker Compose`_. Once you have cloned the repository, run
``docker-compose up`` from the project's root directory. This will start a
introducer, server, and a client configured to connect to them. After the
containers start, you can access the WUI by navigating to
``http://localhost:3456`` in your browser.
.. _Docker: https://docs.docker.com/
.. _Docker Compose: https://docs.docker.com/compose/
Do Stuff With It
================
@ -199,15 +100,14 @@ then you can never again come back to this directory.
The CLI
-------
Prefer the command-line? Run “``tahoe --help``” (the same command-line
tool that is used to start and stop nodes serves to navigate and use the
decentralized file store). To get started, create a new directory and
mark it as the 'tahoe:' alias by running “``tahoe create-alias tahoe``”.
Once you've done that, you can do “``tahoe ls tahoe:``” and “``tahoe cp
LOCALFILE tahoe:foo.txt``” to work with your file store. The Tahoe-LAFS
CLI uses similar syntax to the well-known scp and rsync tools. See
:doc:`frontends/CLI` for more details.
Prefer the command-line? Run “``tahoe --help``” (the same command-line tool
that is used to start and stop nodes serves to navigate and use the
decentralized filesystem). To get started, create a new directory and mark it
as the 'tahoe:' alias by running “``tahoe create-alias tahoe``”. Once you've
done that, you can do “``tahoe ls tahoe:``” and “``tahoe cp LOCALFILE
tahoe:foo.txt``” to work with your filesystem. The Tahoe-LAFS CLI uses
similar syntax to the well-known scp and rsync tools. See CLI.rst_ for more
details.
To backup a directory full of files and subdirectories, run “``tahoe backup
LOCALDIRECTORY tahoe:``”. This will create a new LAFS subdirectory inside the
@ -227,7 +127,7 @@ and if it gets interrupted (for example by a network outage, or by you
rebooting your computer during the backup, or so on), it will resume right
where it left off the next time you run ``tahoe backup``.
See :doc:`frontends/CLI` for more information about the ``tahoe backup``
See `<frontends/CLI.rst>`__ for more information about the ``tahoe backup``
command, as well as other commands.
As with the WUI (and with all current interfaces to Tahoe-LAFS), you
@ -235,20 +135,24 @@ are responsible for remembering directory capabilities yourself. If you
create a new directory and lose the capability to it, then you cannot
access that directory ever again.
.. _CLI.rst: frontends/CLI.rst
The SFTP frontend
-----------------
You can access your Tahoe-LAFS grid via any SFTP_ client. See
:doc:`frontends/FTP-and-SFTP` for how to set this up. On most Unix
platforms, you can also use SFTP to plug Tahoe-LAFS into your computer's
local filesystem via ``sshfs``, but see the `FAQ about performance
problems`_.
The SFTP and FTP frontends
--------------------------
You can access your Tahoe-LAFS grid via any SFTP_ or FTP_ client.
See `FTP-and-SFTP.rst`_ for how to set
this up. On most Unix platforms, you can also use SFTP to plug
Tahoe-LAFS into your computer's local filesystem via ``sshfs``, but see
the `FAQ about performance problems`_.
The SftpFrontend_ page on the wiki has more information about using SFTP with
Tahoe-LAFS.
.. _SFTP: https://en.wikipedia.org/wiki/SSH_file_transfer_protocol
.. _FTP: https://en.wikipedia.org/wiki/File_Transfer_Protocol
.. _FTP-and-SFTP.rst: frontends/FTP-and-SFTP.rst
.. _FAQ about performance problems: https://tahoe-lafs.org/trac/tahoe-lafs/wiki/FAQ#Q23_FUSE
.. _SftpFrontend: https://tahoe-lafs.org/trac/tahoe-lafs/wiki/SftpFrontend
@ -257,24 +161,16 @@ The WAPI
--------
Want to program your Tahoe-LAFS node to do your bidding? Easy! See
:doc:`frontends/webapi`.
webapi.rst_.
.. _webapi.rst: frontends/webapi.rst
Socialize
=========
You can chat with other users of and hackers of this software on the
#tahoe-lafs IRC channel at ``irc.libera.chat``, or on the `tahoe-dev mailing
#tahoe-lafs IRC channel at ``irc.freenode.net``, or on the `tahoe-dev mailing
list`_.
.. _tahoe-dev mailing list: https://lists.tahoe-lafs.org/mailman/listinfo/tahoe-dev
Complain
========
Bugs can be filed on the Tahoe-LAFS "Trac" instance, at
https://tahoe-lafs.org/trac/ .
You can also "fork" the repo and submit Pull Requests on Github:
https://github.com/tahoe-lafs/tahoe-lafs .
.. _tahoe-dev mailing list: https://tahoe-lafs.org/cgi-bin/mailman/listinfo/tahoe-dev

View File

@ -1,200 +0,0 @@
=========================
How To Configure A Server
=========================
Many Tahoe-LAFS nodes run as "servers", meaning they provide services for
other machines (i.e. "clients"). The two most important kinds are the
Introducer, and Storage Servers.
To be useful, servers must be reachable by clients. Tahoe servers can listen
on TCP ports, and advertise their "location" (hostname and TCP port number)
so clients can connect to them. They can also listen on Tor "onion services"
and I2P ports.
Storage servers advertise their location by announcing it to the Introducer,
which then broadcasts the location to all clients. So once the location is
determined, you don't need to do anything special to deliver it.
The Introducer itself has a location, which must be manually delivered to all
storage servers and clients. You might email it to the new members of your
grid. This location (along with other important cryptographic identifiers) is
written into a file named ``private/introducer.furl`` in the Introducer's
base directory, and should be provided as the ``--introducer=`` argument to
``tahoe create-client`` or ``tahoe create-node``.
The first step when setting up a server is to figure out how clients will
reach it. Then you need to configure the server to listen on some ports, and
then configure the location properly.
Manual Configuration
====================
Each server has two settings in their ``tahoe.cfg`` file: ``tub.port``, and
``tub.location``. The "port" controls what the server node listens to: this
is generally a TCP port.
The "location" controls what is advertised to the outside world. This is a
"foolscap connection hint", and it includes both the type of the connection
(tcp, tor, or i2p) and the connection details (hostname/address, port
number). Various proxies, port-forwardings, and privacy networks might be
involved, so it's not uncommon for ``tub.port`` and ``tub.location`` to look
different.
You can directly control the ``tub.port`` and ``tub.location`` configuration
settings by providing ``--port=`` and ``--location=`` when running ``tahoe
create-node``.
Automatic Configuration
=======================
Instead of providing ``--port=/--location=``, you can use ``--listen=``.
Servers can listen on TCP, Tor, I2P, a combination of those, or none at all.
The ``--listen=`` argument controls which kinds of listeners the new server
will use.
``--listen=none`` means the server should not listen at all. This doesn't
make sense for a server, but is appropriate for a client-only node. The
``tahoe create-client`` command automatically includes ``--listen=none``.
``--listen=tcp`` is the default, and turns on a standard TCP listening port.
Using ``--listen=tcp`` requires a ``--hostname=`` argument too, which will be
incorporated into the node's advertised location. We've found that computers
cannot reliably determine their externally-reachable hostname, so rather than
having the server make a guess (or scanning its interfaces for IP addresses
that might or might not be appropriate), node creation requires the user to
provide the hostname.
``--listen=tor`` will talk to a local Tor daemon and create a new "onion
server" address (which look like ``alzrgrdvxct6c63z.onion``). Likewise
``--listen=i2p`` will talk to a local I2P daemon and create a new server
address. See :doc:`anonymity-configuration` for details.
You could listen on all three by using ``--listen=tcp,tor,i2p``.
Deployment Scenarios
====================
The following are some suggested scenarios for configuring servers using
various network transports. These examples do not include specifying an
introducer FURL which normally you would want when provisioning storage
nodes. For these and other configuration details please refer to
:doc:`configuration`.
#. `Server has a public DNS name`_
#. `Server has a public IPv4/IPv6 address`_
#. `Server is behind a firewall with port forwarding`_
#. `Using I2P/Tor to Avoid Port-Forwarding`_
Server has a public DNS name
----------------------------
The simplest case is where your server host is directly connected to the
internet, without a firewall or NAT box in the way. Most VPS (Virtual Private
Server) and colocated servers are like this, although some providers block
many inbound ports by default.
For these servers, all you need to know is the external hostname. The system
administrator will tell you this. The main requirement is that this hostname
can be looked up in DNS, and it will map to an IPv4 or IPv6 address which
will reach the machine.
If your hostname is ``example.net``, then you'll create the introducer like
this::
tahoe create-introducer --hostname example.com ~/introducer
or a storage server like::
tahoe create-node --hostname=example.net
These will allocate a TCP port (e.g. 12345), assign ``tub.port`` to be
``tcp:12345``, and ``tub.location`` will be ``tcp:example.com:12345``.
Ideally this should work for IPv6-capable hosts too (where the DNS name
provides an "AAAA" record, or both "A" and "AAAA"). However Tahoe-LAFS
support for IPv6 is new, and may still have problems. Please see ticket
`#867`_ for details.
.. _#867: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/867
Server has a public IPv4/IPv6 address
-------------------------------------
If the host has a routeable (public) IPv4 address (e.g. ``203.0.113.1``), but
no DNS name, you will need to choose a TCP port (e.g. ``3457``), and use the
following::
tahoe create-node --port=tcp:3457 --location=tcp:203.0.113.1:3457
``--port`` is an "endpoint specification string" that controls which local
port the node listens on. ``--location`` is the "connection hint" that it
advertises to others, and describes the outbound connections that those
clients will make, so it needs to work from their location on the network.
Tahoe-LAFS nodes listen on all interfaces by default. When the host is
multi-homed, you might want to make the listening port bind to just one
specific interface by adding a ``interface=`` option to the ``--port=``
argument::
tahoe create-node --port=tcp:3457:interface=203.0.113.1 --location=tcp:203.0.113.1:3457
If the host's public address is IPv6 instead of IPv4, use square brackets to
wrap the address, and change the endpoint type to ``tcp6``::
tahoe create-node --port=tcp6:3457 --location=tcp:[2001:db8::1]:3457
You can use ``interface=`` to bind to a specific IPv6 interface too, however
you must backslash-escape the colons, because otherwise they are interpreted
as delimiters by the Twisted "endpoint" specification language. The
``--location=`` argument does not need colons to be escaped, because they are
wrapped by the square brackets::
tahoe create-node --port=tcp6:3457:interface=2001\:db8\:\:1 --location=tcp:[2001:db8::1]:3457
For IPv6-only hosts with AAAA DNS records, if the simple ``--hostname=``
configuration does not work, they can be told to listen specifically on an
IPv6-enabled port with this::
tahoe create-node --port=tcp6:3457 --location=tcp:example.net:3457
Server is behind a firewall with port forwarding
------------------------------------------------
To configure a storage node behind a firewall with port forwarding you will
need to know:
* public IPv4 address of the router
* the TCP port that is available from outside your network
* the TCP port that is the forwarding destination
* internal IPv4 address of the storage node (the storage node itself is
unaware of this address, and it is not used during ``tahoe create-node``,
but the firewall must be configured to send connections to this)
The internal and external TCP port numbers could be the same or different
depending on how the port forwarding is configured. If it is mapping ports
1-to-1, and the public IPv4 address of the firewall is 203.0.113.1 (and
perhaps the internal IPv4 address of the storage node is 192.168.1.5), then
use a CLI command like this::
tahoe create-node --port=tcp:3457 --location=tcp:203.0.113.1:3457
If however the firewall/NAT-box forwards external port *6656* to internal
port 3457, then do this::
tahoe create-node --port=tcp:3457 --location=tcp:203.0.113.1:6656
Using I2P/Tor to Avoid Port-Forwarding
--------------------------------------
I2P and Tor onion services, among other great properties, also provide NAT
penetration without port-forwarding, hostnames, or IP addresses. So setting
up a server that listens only on Tor is simple::
tahoe create-node --listen=tor
For more information about using Tahoe-LAFS with I2p and Tor see
:doc:`anonymity-configuration`

View File

@ -404,4 +404,4 @@ References
¹¹ “Performance costs for some common operations” tahoe-lafs.org (2012)
:doc:`../../performance`
https://tahoe-lafs.org/trac/tahoe-lafs/browser/trunk/docs/performance.rst

View File

@ -1,87 +0,0 @@
"""
This is a reference implementation of the lease renewal secret derivation
protocol in use by Tahoe-LAFS clients as of 1.16.0.
"""
from allmydata.util.base32 import (
a2b as b32decode,
b2a as b32encode,
)
from allmydata.util.hashutil import (
tagged_hash,
tagged_pair_hash,
)
def derive_renewal_secret(lease_secret: bytes, storage_index: bytes, tubid: bytes) -> bytes:
assert len(lease_secret) == 32
assert len(storage_index) == 16
assert len(tubid) == 20
bucket_renewal_tag = b"allmydata_bucket_renewal_secret_v1"
file_renewal_tag = b"allmydata_file_renewal_secret_v1"
client_renewal_tag = b"allmydata_client_renewal_secret_v1"
client_renewal_secret = tagged_hash(lease_secret, client_renewal_tag)
file_renewal_secret = tagged_pair_hash(
file_renewal_tag,
client_renewal_secret,
storage_index,
)
peer_id = tubid
return tagged_pair_hash(bucket_renewal_tag, file_renewal_secret, peer_id)
def demo():
secret = b32encode(derive_renewal_secret(
b"lease secretxxxxxxxxxxxxxxxxxxxx",
b"storage indexxxx",
b"tub idxxxxxxxxxxxxxx",
)).decode("ascii")
print("An example renewal secret: {}".format(secret))
def test():
# These test vectors created by intrumenting Tahoe-LAFS
# bb57fcfb50d4e01bbc4de2e23dbbf7a60c004031 to emit `self.renew_secret` in
# allmydata.immutable.upload.ServerTracker.query and then uploading a
# couple files to a couple different storage servers.
test_vector = [
dict(lease_secret=b"boity2cdh7jvl3ltaeebuiobbspjmbuopnwbde2yeh4k6x7jioga",
storage_index=b"vrttmwlicrzbt7gh5qsooogr7u",
tubid=b"v67jiisoty6ooyxlql5fuucitqiok2ic",
expected=b"osd6wmc5vz4g3ukg64sitmzlfiaaordutrez7oxdp5kkze7zp5zq",
),
dict(lease_secret=b"boity2cdh7jvl3ltaeebuiobbspjmbuopnwbde2yeh4k6x7jioga",
storage_index=b"75gmmfts772ww4beiewc234o5e",
tubid=b"v67jiisoty6ooyxlql5fuucitqiok2ic",
expected=b"35itmusj7qm2pfimh62snbyxp3imreofhx4djr7i2fweta75szda",
),
dict(lease_secret=b"boity2cdh7jvl3ltaeebuiobbspjmbuopnwbde2yeh4k6x7jioga",
storage_index=b"75gmmfts772ww4beiewc234o5e",
tubid=b"lh5fhobkjrmkqjmkxhy3yaonoociggpz",
expected=b"srrlruge47ws3lm53vgdxprgqb6bz7cdblnuovdgtfkqrygrjm4q",
),
dict(lease_secret=b"vacviff4xfqxsbp64tdr3frg3xnkcsuwt5jpyat2qxcm44bwu75a",
storage_index=b"75gmmfts772ww4beiewc234o5e",
tubid=b"lh5fhobkjrmkqjmkxhy3yaonoociggpz",
expected=b"b4jledjiqjqekbm2erekzqumqzblegxi23i5ojva7g7xmqqnl5pq",
),
]
for n, item in enumerate(test_vector):
derived = b32encode(derive_renewal_secret(
b32decode(item["lease_secret"]),
b32decode(item["storage_index"]),
b32decode(item["tubid"]),
))
assert derived == item["expected"] , \
"Test vector {} failed: {} (expected) != {} (derived)".format(
n,
item["expected"],
derived,
)
print("{} test vectors validated".format(len(test_vector)))
test()
demo()

View File

@ -8,17 +8,17 @@ As explained in the architecture docs, Tahoe-LAFS can be roughly viewed as
a collection of three layers. The lowest layer is the key-value store: it
provides operations that accept files and upload them to the grid, creating
a URI in the process which securely references the file's contents.
The middle layer is the file store, creating a structure of directories and
filenames resembling the traditional Unix or Windows filesystems. The top
layer is the application layer, which uses the lower layers to provide useful
The middle layer is the filesystem, creating a structure of directories and
filenames resembling the traditional unix/windows filesystems. The top layer
is the application layer, which uses the lower layers to provide useful
services to users, like a backup application, or a way to share files with
friends.
This document examines the middle layer, the "file store".
This document examines the middle layer, the "filesystem".
1. `Key-value Store Primitives`_
2. `File Store Goals`_
3. `Dirnode Goals`_
2. `Filesystem goals`_
3. `Dirnode goals`_
4. `Dirnode secret values`_
5. `Dirnode storage format`_
6. `Dirnode sizes, mutable-file initial read sizes`_
@ -53,10 +53,10 @@ contents of a pre-existing slot, and the third retrieves the contents::
replace(mutable_uri, new_data)
data = get(mutable_uri)
File Store Goals
Filesystem Goals
================
The main goal for the middle (file store) layer is to give users a way to
The main goal for the middle (filesystem) layer is to give users a way to
organize the data that they have uploaded into the grid. The traditional way
to do this in computer filesystems is to put this data into files, give those
files names, and collect these names into directories.
@ -102,7 +102,8 @@ just a special way of interpreting the contents of a specific mutable file.
Earlier releases used a "vdrive server": this server was abolished in the
v0.7.0 release.
For details of how mutable files work, please see :doc:`mutable`.
For details of how mutable files work, please see mutable.rst_ in this
directory.
For releases since v0.7.0, we achieve most of our desired properties. The
integrity and availability of dirnodes is equivalent to that of regular
@ -113,7 +114,7 @@ dirnodes is such that read-only access is transitive: i.e. if you grant Bob
read-only access to a parent directory, then Bob will get read-only access
(and *not* read-write access) to its children.
Relative to the previous "vdrive server"-based scheme, the current
Relative to the previous "vdrive-server" based scheme, the current
distributed dirnode approach gives better availability, but cannot guarantee
updateness quite as well, and requires far more network traffic for each
retrieval and update. Mutable files are somewhat less available than
@ -123,13 +124,15 @@ multiple versions of each mutable file, and you might have some shares of
version 1 and other shares of version 2). In extreme cases of simultaneous
update, mutable files might suffer from non-monotonicity.
.. _mutable.rst: mutable.rst
Dirnode secret values
=====================
As mentioned before, dirnodes are simply a special way to interpret the
contents of a mutable file, so the secret keys and capability strings
described in :doc:`mutable` are all the same. Each dirnode contains an RSA
described in mutable.rst_ are all the same. Each dirnode contains an RSA
public/private keypair, and the holder of the "write capability" will be able
to retrieve the private key (as well as the AES encryption key used for the
data itself). The holder of the "read capability" will be able to obtain the
@ -267,7 +270,7 @@ How well does this design meet the goals?
value, so there are no opportunities for staleness
9. monotonicity: VERY: the single point of access also protects against
retrograde motion
Confidentiality leaks in the storage servers
@ -289,7 +292,7 @@ shorter than read-caps and write-caps, the attacker can use the length of the
ciphertext to guess the number of children of each node, and might be able to
guess the length of the child names (or at least their sum). From this, the
attacker may be able to build up a graph with the same shape as the plaintext
file store, but with unlabeled edges and unknown file contents.
filesystem, but with unlabeled edges and unknown file contents.
Integrity failures in the storage servers
@ -332,19 +335,18 @@ MDMF design rules allow for efficient random-access reads from the middle of
the file, which would give the index something useful to point at.
The current SDMF design generates a new RSA public/private keypair for each
directory. This takes some time and CPU effort (around 100 milliseconds on a
relatively high-end 2021 laptop) per directory.
We have designed (but not yet built) a DSA-based
directory. This takes considerable time and CPU effort, generally one or two
seconds per directory. We have designed (but not yet built) a DSA-based
mutable file scheme which will use shared parameters to reduce the
directory-creation effort to a bare minimum (picking a random number instead
of generating two random primes).
When a backup program is run for the first time, it needs to copy a large
amount of data from a pre-existing local filesystem into reliable storage.
This means that a large and complex directory structure needs to be
duplicated in the dirnode layer. With the one-object-per-dirnode approach
described here, this requires as many operations as there are edges in the
imported filesystem graph.
amount of data from a pre-existing filesystem into reliable storage. This
means that a large and complex directory structure needs to be duplicated in
the dirnode layer. With the one-object-per-dirnode approach described here,
this requires as many operations as there are edges in the imported
filesystem graph.
Another approach would be to aggregate multiple directories into a single
storage object. This object would contain a serialized graph rather than a
@ -364,7 +366,7 @@ single child, looking up a single child) would require pulling or pushing a
lot of unrelated data, increasing network overhead (and necessitating
test-and-set semantics for the modification side, which increases the chances
that a user operation will fail, making it more challenging to provide
promises of atomicity to the user).
promises of atomicity to the user).
It would also make it much more difficult to enable the delegation
("sharing") of specific directories. Since each aggregate "realm" provides
@ -405,7 +407,7 @@ storage index, but do *not* include the readkeys or writekeys, so the
repairer does not get to read the files or directories that it is helping to
keep alive.
After each change to the user's file store, the client creates a manifest and
After each change to the user's vdrive, the client creates a manifest and
looks for differences from their previous version. Anything which was removed
prompts the client to send out lease-cancellation messages, allowing the data
to be deleted.
@ -423,29 +425,27 @@ Mounting and Sharing Directories
================================
The biggest benefit of this dirnode approach is that sharing individual
directories is almost trivial. Alice creates a subdirectory that she wants
to use to share files with Bob. This subdirectory is attached to Alice's
file store at "alice:shared-with-bob". She asks her file store for the
read-only directory URI for that new directory, and emails it to Bob. When
Bob receives the URI, he attaches the given URI into one of his own
directories, perhaps at a place named "bob:shared-with-alice". Every time
Alice writes a file into this directory, Bob will be able to read it.
(It is also possible to share read-write URIs between users, but that makes
it difficult to follow the `Prime Coordination Directive`_ .) Neither
Alice nor Bob will get access to any files above the mounted directory:
there are no 'parent directory' pointers. If Alice creates a nested set of
directories, "alice:shared-with-bob/subdir2", and gives a read-only URI to
shared-with-bob to Bob, then Bob will be unable to write to either
shared-with-bob/ or subdir2/.
.. _`Prime Coordination Directive`: ../write_coordination.rst
directories is almost trivial. Alice creates a subdirectory that she wants to
use to share files with Bob. This subdirectory is attached to Alice's
filesystem at "~alice/share-with-bob". She asks her filesystem for the
read-write directory URI for that new directory, and emails it to Bob. When
Bob receives the URI, he asks his own local vdrive to attach the given URI,
perhaps at a place named "~bob/shared-with-alice". Every time either party
writes a file into this directory, the other will be able to read it. If
Alice prefers, she can give a read-only URI to Bob instead, and then Bob will
be able to read files but not change the contents of the directory. Neither
Alice nor Bob will get access to any files above the mounted directory: there
are no 'parent directory' pointers. If Alice creates a nested set of
directories, "~alice/share-with-bob/subdir2", and gives a read-only URI to
share-with-bob to Bob, then Bob will be unable to write to either
share-with-bob/ or subdir2/.
A suitable UI needs to be created to allow users to easily perform this
sharing action: dragging a folder from their file store to an IM or email
user icon, for example. The UI will need to give the sending user an
opportunity to indicate whether they want to grant read-write or read-only
access to the recipient. The recipient then needs an interface to drag the
new folder into their file store and give it a home.
sharing action: dragging a folder their vdrive to an IM or email user icon,
for example. The UI will need to give the sending user an opportunity to
indicate whether they want to grant read-write or read-only access to the
recipient. The recipient then needs an interface to drag the new folder into
their vdrive and give it a home.
Revocation
==========
@ -470,3 +470,4 @@ Preventing delegation between communication parties is just as pointless as
asking Bob to forget previously accessed files. However, there may be value
to configuring the UI to ask Carol to not share files with Bob, or to
removing all files from Bob's view at the same time his access is revoked.

View File

@ -1,9 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
@ -13,11 +12,11 @@
height="1052.3622047"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
inkscape:version="0.45"
sodipodi:docbase="/home/warner/trees/tahoe/docs"
sodipodi:docname="file-encoding2.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
sodipodi:modified="true"
version="1.1">
sodipodi:modified="true">
<defs
id="defs4">
<marker
@ -44,17 +43,15 @@
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.87181204"
inkscape:cx="384.14974"
inkscape:cy="669.3624"
inkscape:zoom="0.51978303"
inkscape:cx="372.04724"
inkscape:cy="526.18109"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:window-width="900"
inkscape:window-height="756"
inkscape:window-x="71"
inkscape:window-y="268"
showgrid="false"
inkscape:window-maximized="0" />
inkscape:window-x="779"
inkscape:window-y="153" />
<metadata
id="metadata7">
<rdf:RDF>
@ -216,7 +213,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.923205,0,0,0.923205,-463.3983,190.6491)" />
<text
xml:space="preserve"
@ -379,7 +376,7 @@
id="g3090">
<path
transform="matrix(0.923205,0,0,0.923205,-463.3983,190.6491)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -554,7 +551,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.923205,0,0,0.923205,-463.3983,190.6491)" />
<text
xml:space="preserve"
@ -717,7 +714,7 @@
id="g3207">
<path
transform="matrix(0.923205,0,0,0.923205,-463.3983,190.6491)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -908,15 +905,15 @@
y="640.30084" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="642.25336"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
x="650.27539"
y="660.8269"
id="text3839"
sodipodi:linespacing="100%"><tspan
sodipodi:role="line"
id="tspan3841"
x="642.25336"
y="660.8269">server 4</tspan></text>
x="650.27539"
y="660.8269">peer 4</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="M 582.41071,673.68012 C 631.90411,677.13315 631.90411,677.13315 631.90411,677.13315"

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -1,9 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
@ -13,9 +12,9 @@
height="1052.3622047"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
sodipodi:docname="file-encoding3.svg"
version="1.1">
inkscape:version="0.44.1"
sodipodi:docbase="/home/warner/work/tahoe-misc"
sodipodi:docname="file-encoding3.svg">
<defs
id="defs4">
<marker
@ -42,17 +41,15 @@
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.200816"
inkscape:cx="367.45385"
inkscape:cy="768.40477"
inkscape:zoom="0.523584"
inkscape:cx="372.04724"
inkscape:cy="526.18109"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:window-width="900"
inkscape:window-height="756"
inkscape:window-x="356"
inkscape:window-y="256"
showgrid="false"
inkscape:window-maximized="0" />
inkscape:window-x="778"
inkscape:window-y="96" />
<metadata
id="metadata7">
<rdf:RDF>
@ -79,7 +76,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)" />
<text
xml:space="preserve"
@ -98,7 +95,7 @@
id="g3313">
<path
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -129,7 +126,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)" />
<text
xml:space="preserve"
@ -148,7 +145,7 @@
id="g3329">
<path
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -173,7 +170,7 @@
id="g3345">
<path
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -204,7 +201,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)" />
<text
xml:space="preserve"
@ -223,7 +220,7 @@
id="g3361">
<path
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -256,12 +253,12 @@
id="text2988"
y="71.720772"
x="84.785179"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
xml:space="preserve"><tspan
y="71.720772"
x="84.785179"
id="tspan2990"
sodipodi:role="line">block</tspan></text>
sodipodi:role="line">share</tspan></text>
<text
sodipodi:linespacing="100%"
id="text2992"
@ -283,7 +280,7 @@
ry="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
x="215.328"
y="71.720772"
id="text3130"
@ -291,7 +288,7 @@
sodipodi:role="line"
id="tspan3132"
x="215.328"
y="71.720772">block</tspan></text>
y="71.720772">share</tspan></text>
<text
xml:space="preserve"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
@ -316,12 +313,12 @@
id="text3188"
y="71.720772"
x="342.64755"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
xml:space="preserve"><tspan
y="71.720772"
x="342.64755"
id="tspan3190"
sodipodi:role="line">block</tspan></text>
sodipodi:role="line">share</tspan></text>
<text
sodipodi:linespacing="100%"
id="text3192"
@ -343,7 +340,7 @@
ry="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
x="471.5787"
y="71.720772"
id="text3247"
@ -351,7 +348,7 @@
sodipodi:role="line"
id="tspan3249"
x="471.5787"
y="71.720772">block</tspan></text>
y="71.720772">share</tspan></text>
<text
xml:space="preserve"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
@ -390,15 +387,15 @@
y="73.639648" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="612.60901"
y="95.198288"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
x="620.63104"
y="94.16571"
id="text3839"
sodipodi:linespacing="100%"><tspan
sodipodi:role="line"
id="tspan3841"
x="612.60901"
y="95.198288">server 4</tspan></text>
x="620.63104"
y="94.16571">peer 4</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1"
d="M 552.76635,107.01893 C 602.25975,110.47196 602.25975,110.47196 602.25975,110.47196"
@ -483,15 +480,5 @@
id="tspan3352"
x="321.63498"
y="405.33044">&quot;block root hash&quot;</tspan></text>
<flowRoot
xml:space="preserve"
id="flowRoot4984"
style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-family:Bitstream Vera Sans;font-style:normal;font-weight:normal;font-size:40px;line-height:125%;letter-spacing:0px;word-spacing:0px"><flowRegion
id="flowRegion4986"><rect
id="rect4988"
width="838.4519"
height="317.04559"
x="-47.747829"
y="7.6396546" /></flowRegion><flowPara
id="flowPara4990"></flowPara></flowRoot> </g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,9 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
@ -13,9 +12,9 @@
height="1052.3622047"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
sodipodi:docname="file-encoding6.svg"
version="1.1">
inkscape:version="0.44.1"
sodipodi:docbase="/home/warner/work/tahoe-misc"
sodipodi:docname="file-encoding6.svg">
<defs
id="defs4">
<marker
@ -42,17 +41,15 @@
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.56254397"
inkscape:cx="372.04724"
inkscape:cy="241.75888"
inkscape:zoom="0.60354902"
inkscape:cx="367.4898"
inkscape:cy="564.16839"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:window-width="900"
inkscape:window-height="756"
inkscape:window-x="52"
inkscape:window-y="313"
showgrid="false"
inkscape:window-maximized="0" />
inkscape:window-x="732"
inkscape:window-y="176" />
<metadata
id="metadata7">
<rdf:RDF>
@ -79,7 +76,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)" />
<text
xml:space="preserve"
@ -98,7 +95,7 @@
id="g3313">
<path
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -129,7 +126,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)" />
<text
xml:space="preserve"
@ -148,7 +145,7 @@
id="g3345">
<path
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -179,7 +176,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)" />
<text
xml:space="preserve"
@ -198,7 +195,7 @@
id="g3361">
<path
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -231,12 +228,12 @@
id="text2988"
y="71.720772"
x="84.785179"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
xml:space="preserve"><tspan
y="71.720772"
x="84.785179"
id="tspan2990"
sodipodi:role="line">block</tspan></text>
sodipodi:role="line">share</tspan></text>
<text
sodipodi:linespacing="100%"
id="text2992"
@ -258,7 +255,7 @@
ry="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
x="215.328"
y="71.720772"
id="text3130"
@ -266,7 +263,7 @@
sodipodi:role="line"
id="tspan3132"
x="215.328"
y="71.720772">block</tspan></text>
y="71.720772">share</tspan></text>
<text
xml:space="preserve"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
@ -291,12 +288,12 @@
id="text3188"
y="71.720772"
x="342.64755"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
xml:space="preserve"><tspan
y="71.720772"
x="342.64755"
id="tspan3190"
sodipodi:role="line">block</tspan></text>
sodipodi:role="line">share</tspan></text>
<text
sodipodi:linespacing="100%"
id="text3192"
@ -318,7 +315,7 @@
ry="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
x="471.5787"
y="71.720772"
id="text3247"
@ -326,7 +323,7 @@
sodipodi:role="line"
id="tspan3249"
x="471.5787"
y="71.720772">block</tspan></text>
y="71.720772">share</tspan></text>
<text
xml:space="preserve"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
@ -358,15 +355,15 @@
y="272.46359" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20px;line-height:100%;font-family:'Bitstream Charter';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="619.23645"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter"
x="627.25848"
y="292.98965"
id="text3839"
sodipodi:linespacing="100%"><tspan
sodipodi:role="line"
id="tspan3841"
x="619.23645"
y="292.98965">server 4</tspan></text>
x="627.25848"
y="292.98965">peer 4</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1"
d="M 559.39381,305.84288 C 608.88721,309.29591 608.88721,309.29591 608.88721,309.29591"
@ -477,7 +474,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)" />
<text
xml:space="preserve"
@ -496,7 +493,7 @@
transform="translate(52.10837,496.9171)">
<path
transform="matrix(0.511994,0,0,0.511994,-233.9701,54.30905)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -527,7 +524,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.511994,0,0,0.511994,-231.4293,132.056)" />
<text
xml:space="preserve"
@ -546,7 +543,7 @@
transform="translate(52.10837,489.4639)">
<path
transform="matrix(0.511994,0,0,0.511994,-229.5194,206.5426)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -577,7 +574,7 @@
sodipodi:cy="196.10106"
sodipodi:rx="34.958466"
sodipodi:ry="34.073441"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
transform="matrix(0.511994,0,0,0.511994,-229.5194,271.4796)" />
<text
xml:space="preserve"
@ -596,7 +593,7 @@
id="g3701">
<path
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -621,7 +618,7 @@
id="g3709">
<path
transform="matrix(0.511994,0,0,0.511994,289.5084,379.3664)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"
@ -739,7 +736,7 @@
id="g7322">
<path
transform="matrix(0.511994,0,0,0.511994,-229.5194,271.4796)"
d="m 642.52774,196.10106 a 34.958466,34.073441 0 0 1 -34.95847,34.07344 34.958466,34.073441 0 0 1 -34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95846,-34.07344 34.958466,34.073441 0 0 1 34.95847,34.07344 z"
d="M 642.52774 196.10106 A 34.958466 34.073441 0 1 1 572.61081,196.10106 A 34.958466 34.073441 0 1 1 642.52774 196.10106 z"
sodipodi:ry="34.073441"
sodipodi:rx="34.958466"
sodipodi:cy="196.10106"

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -1,19 +0,0 @@
Specifications
==============
This section contains various attempts at writing detailed specifications of
the data formats used by Tahoe.
.. toctree::
:maxdepth: 2
outline
url
uri
file-encoding
URI-extension
mutable
dirnodes
lease
servers-of-happiness
backends/raic

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