Compare commits
1 Commits
master
...
test-twist
Author | SHA1 | Date |
---|---|---|
Daira Hopwood | 1f2574b9a2 |
|
@ -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}"
|
|
@ -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}"
|
|
@ -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}"
|
|
@ -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"
|
|
@ -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}"
|
|
@ -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.
|
|
@ -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>>"
|
|
@ -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"
|
|
@ -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}"
|
148
.circleci/lib.sh
148
.circleci/lib.sh
|
@ -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)"
|
||||
}
|
|
@ -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]
|
|
@ -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}"
|
|
@ -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}}'
|
|
@ -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
|
|
@ -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
|
|
@ -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}
|
27
.coveragerc
27
.coveragerc
|
@ -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/
|
|
@ -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>`__
|
|
@ -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-*-*.*
|
|
@ -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
|
|
@ -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
|
|
@ -1,10 +0,0 @@
|
|||
version: 2
|
||||
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.10"
|
||||
|
||||
python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
18
.ruff.toml
18
.ruff.toml
|
@ -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",
|
||||
]
|
|
@ -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}"
|
|
@ -1,42 +0,0 @@
|
|||
Contributor Checklist
|
||||
=====================
|
||||
|
||||
|
||||
* Create a ``Trac`` ticket, fill it out and assign it to yourself (contact exarkun if you don't have an account):
|
||||
|
||||
``https://tahoe-lafs.org/trac/tahoe-lafs/newticket``
|
||||
|
||||
* Use the ticket number to name your branch (example):
|
||||
|
||||
``3003.contributor-guide``
|
||||
|
||||
* Good idea to add tests at the same time you write your code.
|
||||
|
||||
* Add a file to the ``/newsfragments`` folder, named with the ticket number and the type of patch (example):
|
||||
|
||||
``newsfragments/3651.minor``
|
||||
|
||||
* ``towncrier`` recognizes the following types:
|
||||
|
||||
``incompat``, ``feature``, ``bugfix``, ``installation``, ``configuration``, ``documentation``, ``removed``, ``other``, ``minor``
|
||||
* Add one sentence to ``newsfragments/<ticket-number>.<towncrier-type>`` describing the change (example):
|
||||
|
||||
``The integration test suite has been updated to use pytest-twisted instead of deprecated pytest APIs.``
|
||||
|
||||
* Run the test suite with ``tox``, ``tox -e codechecks`` and ``tox -e typechecks``
|
||||
|
||||
* Push your branch to Github with your ticket number in the merge commit message (example):
|
||||
|
||||
``Fixes ticket:3003``
|
||||
|
||||
This makes the ``Trac`` ticket close when your PR gets approved.
|
||||
|
||||
* Request appropriate review - we suggest asking `Tahoe Committers <https://github.com/orgs/tahoe-lafs/teams/tahoe-committers>`__
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
This checklist is a summary of `this page on contributing Patches <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/Patches>`__
|
||||
|
||||
Before authoring or reviewing a patch, please familiarize yourself with the `Coding Standard <https://tahoe-lafs.org/trac/tahoe-lafs/wiki/CodingStandards>`__
|
||||
and the `Contributor Code of Conduct <docs/CODE_OF_CONDUCT.md>`__.
|
74
CREDITS
74
CREDITS
|
@ -113,8 +113,6 @@ E: jacob@appelbaum.com
|
|||
W: http://www.appelbaum.net/
|
||||
P: 12E4 04FF D3C9 31F9 3405 2D06 B884 1A91 9D0F ACE4
|
||||
D: Debian packaging including init scripts
|
||||
D: Note that contributions from Jacob Appelbaum (ioerror) are no longer welcome
|
||||
D: due to behavior unacceptable to community standards in Tor and other projects
|
||||
|
||||
N: Jeremy Visser
|
||||
D: Ubuntu packaging, usability testing
|
||||
|
@ -185,7 +183,7 @@ D: documentation
|
|||
|
||||
N: Ramakrishnan Muthukrishnan
|
||||
E: ram@rkrishnan.org
|
||||
D: Mac OS X packaging, Debian package maintainer
|
||||
D: Mac OS X packaging
|
||||
|
||||
N: Loose Cannon
|
||||
E: lcstyle@gmail.com
|
||||
|
@ -194,73 +192,3 @@ D: fix the Download! button on the Welcome page
|
|||
N: Jean-Paul Calderone
|
||||
E: exarkun@twistedmatrix.com
|
||||
D: support SFTP public key authentication.
|
||||
|
||||
N: David Stainton
|
||||
E: dstainton415@gmail.com
|
||||
D: various bug-fixes and features
|
||||
|
||||
N: meejah
|
||||
E: meejah@meejah.ca
|
||||
P: 0xC2602803128069A7, 9D5A 2BD5 688E CB88 9DEB CD3F C260 2803 1280 69A7
|
||||
D: various bug-fixes and features
|
||||
|
||||
N: Chad Whitacre
|
||||
E: chad@zetaweb.com
|
||||
D: Python3 porting
|
||||
|
||||
N: Itamar Turner-Trauring
|
||||
E: itamar@pythonspeed.com
|
||||
D: Python3 porting
|
||||
|
||||
N: Jason R. Coombs
|
||||
E: jaraco@jaraco.com
|
||||
D: Python3 porting
|
||||
|
||||
N: Maciej Fijalkowski
|
||||
E: fijall@gmail.com
|
||||
D: Python3 porting
|
||||
|
||||
N: Ross Patterson
|
||||
E: me@rpatterson.net
|
||||
D: Python3 porting
|
||||
|
||||
N: Sajith Sasidharan
|
||||
E: sajith@hcoop.net
|
||||
D: Python3 porting
|
||||
|
||||
N: Pete Fein
|
||||
E: pete@snake.dev
|
||||
D: Python3 porting
|
||||
|
||||
N: Viktoriia Savchuk
|
||||
W: https://twitter.com/viktoriiasvchk
|
||||
D: Developer community focused improvements on the README file.
|
||||
|
||||
N: Lukas Pirl
|
||||
E: tahoe@lukas-pirl.de
|
||||
W: http://lukas-pirl.de
|
||||
D: Buildslaves (Debian, Fedora, CentOS; 2016-2021)
|
||||
|
||||
N: Anxhelo Lushka
|
||||
E: anxhelo1995@gmail.com
|
||||
D: Web site design and updates
|
||||
|
||||
N: Fon E. Noel
|
||||
E: fenn25.fn@gmail.com
|
||||
D: bug-fixes and refactoring
|
||||
|
||||
N: Jehad Baeth
|
||||
E: jehad@leastauthority.com
|
||||
D: Documentation improvement
|
||||
|
||||
N: May-Lee Sia
|
||||
E: mayleesia@gmail.com
|
||||
D: Community-manager and documentation improvements
|
||||
|
||||
N: Yash Nayani
|
||||
E: yashaswi.nram@gmail.com
|
||||
D: Installation Guide improvements
|
||||
|
||||
N: Florian Sesser
|
||||
E: florian@private.storage
|
||||
D: OpenMetrics support
|
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 362 B |
|
@ -0,0 +1,10 @@
|
|||
FROM python:2.7
|
||||
|
||||
ADD . /tahoe-lafs
|
||||
RUN \
|
||||
cd /tahoe-lafs && \
|
||||
git pull --depth=100 && \
|
||||
make && \
|
||||
ln -vs /tahoe-lafs/bin/tahoe /usr/local/bin/tahoe
|
||||
|
||||
WORKDIR /root
|
|
@ -1,13 +1,13 @@
|
|||
include README.rst
|
||||
include COPYING.GPL COPYING.TGPPL.rst CREDITS Makefile NEWS.rst Tahoe.home
|
||||
include relnotes.txt
|
||||
include bin/tahoe-script.template
|
||||
include Dockerfile
|
||||
include tox.ini .appveyor.yml .travis.yml
|
||||
include .coveragerc
|
||||
recursive-include src *.xhtml *.js *.png *.css *.svg *.txt *.yaml
|
||||
recursive-include src *.xhtml *.js *.png *.css *.svg *.txt
|
||||
graft docs
|
||||
graft misc
|
||||
graft static
|
||||
graft integration
|
||||
graft Contents
|
||||
|
||||
graft setuptools-0.6c16dev6.egg
|
||||
global-exclude *~ *.pyc
|
||||
|
|
329
Makefile
329
Makefile
|
@ -1,57 +1,17 @@
|
|||
# Tahoe LFS Development and maintenance tasks
|
||||
#
|
||||
|
||||
# NOTE: this Makefile requires GNU make
|
||||
|
||||
### Defensive settings for make:
|
||||
# https://tech.davis-hansson.com/p/make/
|
||||
SHELL := bash
|
||||
.ONESHELL:
|
||||
.SHELLFLAGS := -xeu -o pipefail -c
|
||||
.SILENT:
|
||||
.DELETE_ON_ERROR:
|
||||
MAKEFLAGS += --warn-undefined-variables
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
default: build
|
||||
|
||||
# Local target variables
|
||||
PYTHON=python
|
||||
export PYTHON
|
||||
PYFLAKES=flake8
|
||||
export PYFLAKES
|
||||
VIRTUAL_ENV=./.tox/py37
|
||||
SOURCES=src/allmydata static misc setup.py
|
||||
APPNAME=tahoe-lafs
|
||||
TEST_SUITE=allmydata
|
||||
|
||||
# setup.py will extend sys.path to include our support/lib/... directory
|
||||
# itself. It will also create it in the beginning of the 'develop' command.
|
||||
|
||||
# Top-level, phony targets
|
||||
|
||||
.PHONY: default
|
||||
default:
|
||||
@echo "no default target"
|
||||
|
||||
.PHONY: test
|
||||
## Run all tests and code reports
|
||||
test: .tox/create-venvs.log
|
||||
# Run codechecks first since it takes the least time to report issues early.
|
||||
tox --develop -e codechecks
|
||||
# Run all the test environments in parallel to reduce run-time
|
||||
tox --develop -p auto -e 'py37'
|
||||
.PHONY: test-venv-coverage
|
||||
## Run all tests with coverage collection and reporting.
|
||||
test-venv-coverage:
|
||||
# Special handling for reporting coverage even when the test run fails
|
||||
rm -f ./.coverage.*
|
||||
test_exit=
|
||||
$(VIRTUAL_ENV)/bin/coverage run -m twisted.trial --rterrors --reporter=timing \
|
||||
$(TEST_SUITE) || test_exit="$$?"
|
||||
$(VIRTUAL_ENV)/bin/coverage combine
|
||||
$(VIRTUAL_ENV)/bin/coverage xml || true
|
||||
$(VIRTUAL_ENV)/bin/coverage report
|
||||
if [ ! -z "$$test_exit" ]; then exit "$$test_exit"; fi
|
||||
.PHONY: test-py3-all
|
||||
## Run all tests under Python 3
|
||||
test-py3-all: .tox/create-venvs.log
|
||||
tox --develop -e py37 allmydata
|
||||
TAHOE=$(PYTHON) bin/tahoe
|
||||
SOURCES=src/allmydata src/buildtest static misc bin/tahoe-script.template setup.py
|
||||
APPNAME=allmydata-tahoe
|
||||
|
||||
# This is necessary only if you want to automatically produce a new
|
||||
# _version.py file from the current git history (without doing a build).
|
||||
|
@ -59,38 +19,110 @@ test-py3-all: .tox/create-venvs.log
|
|||
make-version:
|
||||
$(PYTHON) ./setup.py update_version
|
||||
|
||||
.built:
|
||||
$(MAKE) build
|
||||
|
||||
src/allmydata/_version.py:
|
||||
$(MAKE) make-version
|
||||
|
||||
# It is unnecessary to have this depend on build or src/allmydata/_version.py,
|
||||
# since 'setup.py build' always updates the version.
|
||||
.PHONY: build
|
||||
build:
|
||||
$(PYTHON) setup.py build
|
||||
touch .built
|
||||
|
||||
# Build OS X pkg packages.
|
||||
.PHONY: build-osx-pkg
|
||||
build-osx-pkg:
|
||||
.PHONY: build-osx-pkg test-osx-pkg upload-osx-pkg
|
||||
build-osx-pkg: build
|
||||
misc/build_helpers/build-osx-pkg.sh $(APPNAME)
|
||||
|
||||
.PHONY: test-osx-pkg
|
||||
test-osx-pkg:
|
||||
$(PYTHON) misc/build_helpers/test-osx-pkg.py
|
||||
|
||||
.PHONY: upload-osx-pkg
|
||||
upload-osx-pkg:
|
||||
# [Failure instance: Traceback: <class 'OpenSSL.SSL.Error'>: [('SSL routines', 'ssl3_read_bytes', 'tlsv1 alert unknown ca'), ('SSL routines', 'ssl3_write_bytes', 'ssl handshake failure')]
|
||||
#
|
||||
# @echo "uploading to ~tahoe-tarballs/OS-X-packages/ via flappserver"
|
||||
# @if [ "X${BB_BRANCH}" = "Xmaster" ] || [ "X${BB_BRANCH}" = "X" ]; then \
|
||||
# flappclient --furlfile ~/.tahoe-osx-pkg-upload.furl upload-file tahoe-lafs-*-osx.pkg; \
|
||||
# else \
|
||||
# echo not uploading tahoe-lafs-osx-pkg because this is not trunk but is branch \"${BB_BRANCH}\" ; \
|
||||
# fi
|
||||
@echo "uploading to ~tahoe-tarballs/OS-X-packages/ via flappserver"
|
||||
@if [ "X${BB_BRANCH}" = "Xmaster" ] || [ "X${BB_BRANCH}" = "X" ]; then \
|
||||
flappclient --furlfile ~/.tahoe-osx-pkg-upload.furl upload-file tahoe-lafs-*-osx.pkg; \
|
||||
else \
|
||||
echo not uploading tahoe-lafs-osx-pkg because this is not trunk but is branch \"${BB_BRANCH}\" ; \
|
||||
fi
|
||||
|
||||
# TESTING
|
||||
|
||||
# you can use 'make test TEST=allmydata.test.test_introducer' to run just
|
||||
# test_introducer. TEST=allmydata.test.test_client.Basic.test_permute works
|
||||
# too.
|
||||
TEST=allmydata
|
||||
|
||||
# It is unnecessary to have this depend on build or src/allmydata/_version.py,
|
||||
# since 'setup.py test' always updates the version and builds before testing.
|
||||
.PHONY: test
|
||||
test:
|
||||
$(PYTHON) setup.py test $(TRIALARGS) -s $(TEST)
|
||||
touch .built
|
||||
|
||||
.PHONY: check
|
||||
check: test
|
||||
|
||||
.PHONY: quicktest
|
||||
quicktest: make-version
|
||||
$(TAHOE) debug trial $(TRIALARGS) $(TEST)
|
||||
|
||||
# "make tmpfstest" may be a faster way of running tests on Linux. It works best when you have
|
||||
# at least 330 MiB of free physical memory (to run the whole test suite). Since it uses sudo
|
||||
# to mount/unmount the tmpfs filesystem, it might prompt for your password.
|
||||
.PHONY: tmpfstest
|
||||
tmpfstest:
|
||||
time make _tmpfstest 'TMPDIR=$(shell mktemp -d --tmpdir=.)'
|
||||
|
||||
.PHONY: _tmpfstest
|
||||
_tmpfstest: make-version
|
||||
sudo mount -t tmpfs -o size=400m tmpfs '$(TMPDIR)'
|
||||
-$(TAHOE) debug trial --rterrors '--temp-directory=$(TMPDIR)/_trial_temp' $(TRIALARGS) $(TEST)
|
||||
sudo umount '$(TMPDIR)'
|
||||
rmdir '$(TMPDIR)'
|
||||
|
||||
|
||||
# code coverage: install the "coverage" package from PyPI, do "make test-coverage" to
|
||||
# do a unit test run with coverage-gathering enabled, then use "make coverage-output" to
|
||||
# generate an HTML report. Also see "make .coverage.el" and misc/coding_tools/coverage.el
|
||||
# for Emacs integration.
|
||||
|
||||
# This might need to be python-coverage on Debian-based distros.
|
||||
COVERAGE=coverage
|
||||
|
||||
COVERAGEARGS=--branch --source=src/allmydata
|
||||
|
||||
# --include appeared in coverage-3.4
|
||||
COVERAGE_OMIT=--include '$(CURDIR)/src/allmydata/*' --omit '$(CURDIR)/src/allmydata/test/*'
|
||||
|
||||
.PHONY: test-coverage
|
||||
test-coverage: build
|
||||
rm -f .coverage
|
||||
$(TAHOE) '@$(COVERAGE)' run $(COVERAGEARGS) @tahoe debug trial $(TRIALARGS) $(TEST)
|
||||
|
||||
.PHONY: coverage-output
|
||||
coverage-output:
|
||||
rm -rf coverage-html
|
||||
coverage html -i -d coverage-html $(COVERAGE_OMIT)
|
||||
cp .coverage coverage-html/coverage.data
|
||||
@echo "now point your browser at coverage-html/index.html"
|
||||
|
||||
.coverage.el: .coverage
|
||||
$(PYTHON) misc/coding_tools/coverage2el.py
|
||||
|
||||
|
||||
.PHONY: code-checks
|
||||
#code-checks: build version-and-path check-interfaces check-miscaptures -find-trailing-spaces -check-umids pyflakes
|
||||
code-checks: check-interfaces check-debugging check-miscaptures -find-trailing-spaces -check-umids pyflakes
|
||||
code-checks: build version-and-path check-interfaces check-miscaptures -find-trailing-spaces -check-umids pyflakes
|
||||
|
||||
.PHONY: version-and-path
|
||||
version-and-path:
|
||||
$(TAHOE) --version-and-path
|
||||
|
||||
.PHONY: check-interfaces
|
||||
check-interfaces:
|
||||
$(PYTHON) misc/coding_tools/check-interfaces.py 2>&1 |tee violations.txt
|
||||
@echo
|
||||
|
||||
.PHONY: check-debugging
|
||||
check-debugging:
|
||||
$(PYTHON) misc/coding_tools/check-debugging.py
|
||||
$(TAHOE) @misc/coding_tools/check-interfaces.py 2>&1 |tee violations.txt
|
||||
@echo
|
||||
|
||||
.PHONY: check-miscaptures
|
||||
|
@ -100,7 +132,7 @@ check-miscaptures:
|
|||
|
||||
.PHONY: pyflakes
|
||||
pyflakes:
|
||||
$(PYFLAKES) $(SOURCES) |sort |uniq
|
||||
@$(PYTHON) -OOu `which pyflakes` $(SOURCES) |sort |uniq
|
||||
@echo
|
||||
|
||||
.PHONY: check-umids
|
||||
|
@ -132,23 +164,65 @@ count-lines:
|
|||
@echo -n "XXX: "
|
||||
@grep XXX `find src -name '*.py' |grep -v /build/` | wc -l
|
||||
|
||||
.PHONY: check-memory
|
||||
check-memory: .built
|
||||
rm -rf _test_memory
|
||||
$(TAHOE) @src/allmydata/test/check_memory.py upload
|
||||
$(TAHOE) @src/allmydata/test/check_memory.py upload-self
|
||||
$(TAHOE) @src/allmydata/test/check_memory.py upload-POST
|
||||
$(TAHOE) @src/allmydata/test/check_memory.py download
|
||||
$(TAHOE) @src/allmydata/test/check_memory.py download-GET
|
||||
$(TAHOE) @src/allmydata/test/check_memory.py download-GET-slow
|
||||
$(TAHOE) @src/allmydata/test/check_memory.py receive
|
||||
|
||||
# Here is a list of testing tools that can be run with 'python' from a
|
||||
# virtualenv in which Tahoe has been installed. There used to be Makefile
|
||||
# targets for each, but the exact path to a suitable python is now up to the
|
||||
# developer. But as a hint, after running 'tox', ./.tox/py37/bin/python will
|
||||
# probably work.
|
||||
.PHONY: check-memory-once
|
||||
check-memory-once: .built
|
||||
rm -rf _test_memory
|
||||
$(TAHOE) @src/allmydata/test/check_memory.py $(MODE)
|
||||
|
||||
# src/allmydata/test/bench_dirnode.py
|
||||
# The check-speed target uses a pre-established client node to run a canned
|
||||
# set of performance tests against a test network that is also
|
||||
# pre-established (probably on a remote machine). Provide it with the path to
|
||||
# a local directory where this client node has been created (and populated
|
||||
# with the necessary FURLs of the test network). This target will start that
|
||||
# client with the current code and then run the tests. Afterwards it will
|
||||
# stop the client.
|
||||
#
|
||||
# The 'sleep 5' is in there to give the new client a chance to connect to its
|
||||
# storageservers, since check_speed.py has no good way of doing that itself.
|
||||
|
||||
.PHONY: check-speed
|
||||
check-speed: .built
|
||||
if [ -z '$(TESTCLIENTDIR)' ]; then exit 1; fi
|
||||
@echo "stopping any leftover client code"
|
||||
-$(TAHOE) stop $(TESTCLIENTDIR)
|
||||
$(TAHOE) start $(TESTCLIENTDIR)
|
||||
sleep 5
|
||||
$(TAHOE) @src/allmydata/test/check_speed.py $(TESTCLIENTDIR)
|
||||
$(TAHOE) stop $(TESTCLIENTDIR)
|
||||
|
||||
# The check-grid target also uses a pre-established client node, along with a
|
||||
# long-term directory that contains some well-known files. See the docstring
|
||||
# in src/allmydata/test/check_grid.py to see how to set this up.
|
||||
##.PHONY: check-grid
|
||||
##check-grid: .built
|
||||
## if [ -z '$(TESTCLIENTDIR)' ]; then exit 1; fi
|
||||
## $(TAHOE) @src/allmydata/test/check_grid.py $(TESTCLIENTDIR) bin/tahoe
|
||||
.PHONY: check-grid
|
||||
check-grid: .built
|
||||
if [ -z '$(TESTCLIENTDIR)' ]; then exit 1; fi
|
||||
$(TAHOE) @src/allmydata/test/check_grid.py $(TESTCLIENTDIR) bin/tahoe
|
||||
|
||||
.PHONY: bench-dirnode
|
||||
bench-dirnode: .built
|
||||
$(TAHOE) @src/allmydata/test/bench_dirnode.py
|
||||
|
||||
# the provisioning tool runs as a stand-alone webapp server
|
||||
.PHONY: run-provisioning-tool
|
||||
run-provisioning-tool: .built
|
||||
$(TAHOE) @misc/operations_helpers/provisioning/run.py
|
||||
|
||||
# 'make repl' is a simple-to-type command to get a Python interpreter loop
|
||||
# from which you can type 'import allmydata'
|
||||
.PHONY: repl
|
||||
repl:
|
||||
$(TAHOE) debug repl
|
||||
|
||||
.PHONY: test-get-ignore
|
||||
test-git-ignore:
|
||||
|
@ -170,19 +244,21 @@ test-clean:
|
|||
# Use 'make distclean' instead to delete all generated files.
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf build _trial_temp .built
|
||||
rm -rf build _trial_temp _test_memory .built
|
||||
rm -f `find src *.egg -name '*.so' -or -name '*.pyc'`
|
||||
rm -rf support dist
|
||||
rm -rf `ls -d *.egg | grep -vEe"setuptools-|setuptools_darcs-|darcsver-"`
|
||||
rm -rf *.pyc
|
||||
rm -rf misc/dependencies/build misc/dependencies/temp
|
||||
rm -rf misc/dependencies/tahoe_deps.egg-info
|
||||
rm -f bin/tahoe bin/tahoe.pyscript
|
||||
rm -f *.pkg
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
rm -rf src/*.egg-info
|
||||
rm -rf src/allmydata_tahoe.egg-info
|
||||
rm -f src/allmydata/_version.py
|
||||
rm -f src/allmydata/_appname.py
|
||||
rm -rf ./.tox/
|
||||
|
||||
|
||||
.PHONY: find-trailing-spaces
|
||||
|
@ -195,91 +271,34 @@ find-trailing-spaces:
|
|||
-$(PYTHON) misc/coding_tools/find-trailing-spaces.py -r $(SOURCES)
|
||||
@echo
|
||||
|
||||
# The test-desert-island target grabs the tahoe-deps tarball, unpacks it,
|
||||
# does a build, then asserts that the build did not try to download anything
|
||||
# as it ran. Invoke this on a new tree, or after a 'clean', to make sure the
|
||||
# support/lib/ directory is gone.
|
||||
|
||||
.PHONY: fetch-and-unpack-deps
|
||||
fetch-and-unpack-deps:
|
||||
@echo "test-and-unpack-deps is obsolete"
|
||||
test -f tahoe-deps.tar.gz || wget https://tahoe-lafs.org/source/tahoe-lafs/deps/tahoe-lafs-deps.tar.gz
|
||||
rm -rf tahoe-deps
|
||||
tar xzf tahoe-lafs-deps.tar.gz
|
||||
|
||||
.PHONY: test-desert-island
|
||||
test-desert-island:
|
||||
@echo "test-desert-island is obsolete"
|
||||
$(MAKE) fetch-and-unpack-deps
|
||||
$(MAKE) 2>&1 | tee make.out
|
||||
$(PYTHON) misc/build_helpers/check-build.py make.out no-downloads
|
||||
|
||||
.PHONY: test-pip-install
|
||||
test-pip-install:
|
||||
@echo "test-pip-install is obsolete"
|
||||
$(PYTHON) misc/build_helpers/test-pip-install.py
|
||||
|
||||
# TARBALL GENERATION
|
||||
.PHONY: tarballs
|
||||
tarballs: # delegated to tox, so setup.py can update setuptools if needed
|
||||
tox -e tarballs
|
||||
tarballs:
|
||||
$(MAKE) make-version
|
||||
$(PYTHON) setup.py sdist --formats=bztar,gztar,zip
|
||||
$(PYTHON) setup.py sdist --sumo --formats=bztar,gztar,zip
|
||||
|
||||
.PHONY: upload-tarballs
|
||||
upload-tarballs:
|
||||
@if [ "X${BB_BRANCH}" = "Xmaster" ] || [ "X${BB_BRANCH}" = "X" ]; then for f in dist/*; do flappclient --furlfile ~/.tahoe-tarball-upload.furl upload-file $$f; done ; else echo not uploading tarballs because this is not trunk but is branch \"${BB_BRANCH}\" ; fi
|
||||
|
||||
|
||||
# Real targets
|
||||
|
||||
src/allmydata/_version.py:
|
||||
$(MAKE) make-version
|
||||
|
||||
.tox/create-venvs.log: tox.ini setup.py
|
||||
tox --notest -p all | tee -a "$(@)"
|
||||
|
||||
|
||||
# to make a new release:
|
||||
# - create a ticket for the release in Trac
|
||||
# - ensure local copy is up-to-date
|
||||
# - create a branch like "XXXX.release" from up-to-date master
|
||||
# - in the branch, run "make release"
|
||||
# - run "make release-test"
|
||||
# - perform any other sanity-checks on the release
|
||||
# - run "make release-upload"
|
||||
# Note that several commands below hard-code "meejah"; if you are
|
||||
# someone else please adjust them.
|
||||
release:
|
||||
@echo "Is checkout clean?"
|
||||
git diff-files --quiet
|
||||
git diff-index --quiet --cached HEAD --
|
||||
|
||||
@echo "Clean docs build area"
|
||||
rm -rf docs/_build/
|
||||
|
||||
@echo "Install required build software"
|
||||
python3 -m pip install --editable .[build]
|
||||
|
||||
@echo "Test README"
|
||||
python3 setup.py check -r -s
|
||||
|
||||
@echo "Update NEWS"
|
||||
python3 -m towncrier build --yes --version `python3 misc/build_helpers/update-version.py --no-tag`
|
||||
git add -u
|
||||
git commit -m "update NEWS for release"
|
||||
|
||||
# note that this always bumps the "middle" number, e.g. from 1.17.1 -> 1.18.0
|
||||
# and produces a tag into the Git repository
|
||||
@echo "Bump version and create tag"
|
||||
python3 misc/build_helpers/update-version.py
|
||||
|
||||
@echo "Build and sign wheel"
|
||||
python3 setup.py bdist_wheel
|
||||
gpg --pinentry=loopback -u meejah@meejah.ca --armor --detach-sign dist/tahoe_lafs-`git describe | cut -b 12-`-py3-none-any.whl
|
||||
ls dist/*`git describe | cut -b 12-`*
|
||||
|
||||
@echo "Build and sign source-dist"
|
||||
python3 setup.py sdist
|
||||
gpg --pinentry=loopback -u meejah@meejah.ca --armor --detach-sign dist/tahoe-lafs-`git describe | cut -b 12-`.tar.gz
|
||||
ls dist/*`git describe | cut -b 12-`*
|
||||
|
||||
# basically just a bare-minimum smoke-test that it installs and runs
|
||||
release-test:
|
||||
gpg --verify dist/tahoe-lafs-`git describe | cut -b 12-`.tar.gz.asc
|
||||
gpg --verify dist/tahoe_lafs-`git describe | cut -b 12-`-py3-none-any.whl.asc
|
||||
virtualenv testmf_venv
|
||||
testmf_venv/bin/pip install dist/tahoe_lafs-`git describe | cut -b 12-`-py3-none-any.whl
|
||||
testmf_venv/bin/tahoe --version
|
||||
rm -rf testmf_venv
|
||||
|
||||
release-upload:
|
||||
scp dist/*`git describe | cut -b 12-`* meejah@tahoe-lafs.org:/home/source/downloads
|
||||
git push origin_push tahoe-lafs-`git describe | cut -b 12-`
|
||||
twine upload dist/tahoe_lafs-`git describe | cut -b 12-`-py3-none-any.whl dist/tahoe_lafs-`git describe | cut -b 12-`-py3-none-any.whl.asc dist/tahoe-lafs-`git describe | cut -b 12-`.tar.gz dist/tahoe-lafs-`git describe | cut -b 12-`.tar.gz.asc
|
||||
@if [ "X${BB_BRANCH}" = "Xmaster" ] || [ "X${BB_BRANCH}" = "X" ]; then for f in dist/$(APPNAME)-*; do flappclient --furlfile ~/.tahoe-tarball-upload.furl upload-file $$f; done ; else echo not uploading tarballs because this is not trunk but is branch \"${BB_BRANCH}\" ; fi
|
||||
|
|
167
README.rst
167
README.rst
|
@ -1,149 +1,38 @@
|
|||
======================================
|
||||
Free and Open Decentralized Data Store
|
||||
======================================
|
||||
==========
|
||||
Tahoe-LAFS
|
||||
==========
|
||||
|
||||
|image0|
|
||||
Tahoe-LAFS is a Free and Open decentralized cloud storage system. It distributes
|
||||
your data across multiple servers. Even if some of the servers fail or are taken
|
||||
over by an attacker, the entire file store continues to function correctly,
|
||||
preserving your privacy and security.
|
||||
|
||||
`Tahoe-LAFS <https://www.tahoe-lafs.org>`__ (Tahoe Least-Authority File Store) is the first free software / open-source storage technology that distributes your data across multiple servers. Even if some servers fail or are taken over by an attacker, the entire file store continues to function correctly, preserving your privacy and security.
|
||||
To get started please see `quickstart.rst`_ in the docs directory.
|
||||
|
||||
|Contributor Covenant| |readthedocs| |circleci| |githubactions| |coveralls|
|
||||
LICENCE
|
||||
=======
|
||||
|
||||
Copyright 2006-2015 The Tahoe-LAFS Software Foundation
|
||||
|
||||
Table of contents
|
||||
You may use this package under the GNU General Public License, version 2 or, at
|
||||
your option, any later version. You may use this package under the Transitive
|
||||
Grace Period Public Licence, version 1.0, or at your option, any later
|
||||
version. (You may choose to use this package under the terms of either licence,
|
||||
at your option.) See the file `COPYING.GPL`_ for the terms of the GNU General
|
||||
Public License, version 2. See the file `COPYING.TGPPL.rst`_ for the terms of
|
||||
the Transitive Grace Period Public Licence, version 1.0.
|
||||
|
||||
- `About Tahoe-LAFS <#about-tahoe-lafs>`__
|
||||
See `TGPPL.PDF`_ for why the TGPPL exists, graphically illustrated on three slides.
|
||||
|
||||
- `Installation <#installation>`__
|
||||
.. _quickstart.rst: https://github.com/tahoe-lafs/tahoe-lafs/blob/master/docs/quickstart.rst
|
||||
.. _COPYING.GPL: https://github.com/tahoe-lafs/tahoe-lafs/blob/master/COPYING.GPL
|
||||
.. _COPYING.TGPPL.rst: https://github.com/tahoe-lafs/tahoe-lafs/blob/master/COPYING.TGPPL.rst
|
||||
.. _TGPPL.PDF: https://tahoe-lafs.org/~zooko/tgppl.pdf
|
||||
|
||||
- `Issues <#issues>`__
|
||||
----
|
||||
|
||||
- `Documentation <#documentation>`__
|
||||
.. image:: https://travis-ci.org/tahoe-lafs/tahoe-lafs.png?branch=master
|
||||
:target: https://travis-ci.org/tahoe-lafs/tahoe-lafs
|
||||
|
||||
- `Community <#community>`__
|
||||
|
||||
- `Contributing <#contributing>`__
|
||||
|
||||
- `FAQ <#faq>`__
|
||||
|
||||
- `License <#license>`__
|
||||
|
||||
💡 About Tahoe-LAFS
|
||||
-------------------
|
||||
|
||||
Tahoe-LAFS helps you to store files while granting confidentiality, integrity, and availability of your data.
|
||||
|
||||
How does it work? You run a client program on your computer, which talks to one or more storage servers on other computers. When you tell your client to store a file, it will encrypt that file, encode it into multiple pieces, then spread those pieces out among various servers. The pieces are all encrypted and protected against modifications. Later, when you ask your client to retrieve the file, it will find the necessary pieces, make sure they haven’t 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 aren’t 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
|
||||
|
|
|
@ -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.
|
||||
"""
|
|
@ -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()
|
|
@ -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
|
|
@ -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)
|
13
default.nix
13
default.nix
|
@ -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
|
|
@ -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/
|
|
@ -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.
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
@ -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.
|
|
@ -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.
|
229
docs/Makefile
229
docs/Makefile
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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.
|
Binary file not shown.
Before Width: | Height: | Size: 111 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.6 KiB |
|
@ -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
|
|
@ -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/
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -64,9 +64,3 @@ Peter Secor
|
|||
Shawn Willden
|
||||
|
||||
Terrell Russell
|
||||
|
||||
Jean-Paul Calderone
|
||||
|
||||
meejah
|
||||
|
||||
Sajith Sasidharan
|
||||
|
|
|
@ -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
|
||||
==============
|
||||
|
|
|
@ -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")))
|
280
docs/conf.py
280
docs/conf.py
|
@ -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
|
|
@ -4,19 +4,16 @@
|
|||
Configuring a Tahoe-LAFS node
|
||||
=============================
|
||||
|
||||
#. `Node Types`_
|
||||
#. `Overall Node Configuration`_
|
||||
#. `Connection Management`_
|
||||
#. `Client Configuration`_
|
||||
#. `Storage Server Configuration`_
|
||||
#. `Storage Server Plugin Configuration`_
|
||||
#. `Frontend Configuration`_
|
||||
#. `Running A Helper`_
|
||||
#. `Running An Introducer`_
|
||||
#. `Other Files in BASEDIR`_
|
||||
#. `Static Server Definitions`_
|
||||
#. `Other files`_
|
||||
#. `Example`_
|
||||
1. `Node Types`_
|
||||
2. `Overall Node Configuration`_
|
||||
3. `Client Configuration`_
|
||||
4. `Storage Server Configuration`_
|
||||
5. `Frontend Configuration`_
|
||||
6. `Running A Helper`_
|
||||
7. `Running An Introducer`_
|
||||
8. `Other Files in BASEDIR`_
|
||||
9. `Other files`_
|
||||
10. `Example`_
|
||||
|
||||
A Tahoe-LAFS node is configured by writing to files in its base directory.
|
||||
These files are read by the node when it starts, so each time you change
|
||||
|
@ -29,9 +26,9 @@ This document contains a complete list of the config files that are examined
|
|||
by the client node, as well as the state files that you'll observe in its
|
||||
base directory.
|
||||
|
||||
The main file is named "``tahoe.cfg``", and is an "`.INI`_"-style configuration
|
||||
file (parsed by the Python stdlib `ConfigParser`_ module: "``[name]``" section
|
||||
markers, lines with "``key.subkey: value``", `RFC822-style`_
|
||||
The main file is named "``tahoe.cfg``", and is an ".INI"-style configuration
|
||||
file (parsed by the Python stdlib 'ConfigParser' module: "``[name]``" section
|
||||
markers, lines with "``key.subkey: value``", rfc822-style
|
||||
continuations). There are also other files containing information that does
|
||||
not easily fit into this format. The "``tahoe create-node``" or "``tahoe
|
||||
create-client``" command will create an initial ``tahoe.cfg`` file for
|
||||
|
@ -52,35 +49,26 @@ The item descriptions below use the following types:
|
|||
not specified, Tahoe-LAFS will attempt to bind the port specified on all
|
||||
interfaces.
|
||||
|
||||
``endpoint specification string``
|
||||
|
||||
a Twisted Endpoint specification string, like "``tcp:80``" or
|
||||
"``tcp:3456:interface=127.0.0.1``". These are replacing strports strings.
|
||||
For a full description of the format, see `the Twisted Endpoints
|
||||
documentation`_. Please note, if interface= is not specified, Tahoe-LAFS
|
||||
will attempt to bind the port specified on all interfaces. Also note that
|
||||
``tub.port`` only works with TCP endpoints right now.
|
||||
|
||||
``FURL string``
|
||||
|
||||
a Foolscap endpoint identifier, like
|
||||
``pb://soklj4y7eok5c3xkmjeqpw@192.168.69.247:44801/eqpwqtzm``
|
||||
|
||||
.. _.INI: https://en.wikipedia.org/wiki/INI_file
|
||||
.. _ConfigParser: https://docs.python.org/2/library/configparser.html
|
||||
.. _RFC822-style: https://www.ietf.org/rfc/rfc0822
|
||||
.. _the Twisted strports documentation: https://twistedmatrix.com/documents/current/api/twisted.application.strports.html
|
||||
.. _the Twisted Endpoints documentation: http://twistedmatrix.com/documents/current/core/howto/endpoints.html#endpoint-types-included-with-twisted
|
||||
|
||||
|
||||
Node Types
|
||||
==========
|
||||
|
||||
A node can be a client/server or an introducer.
|
||||
A node can be a client/server, an introducer, a statistics gatherer, or a
|
||||
key generator.
|
||||
|
||||
Client/server nodes provide one or more of the following services:
|
||||
|
||||
* web-API service
|
||||
* SFTP service
|
||||
* FTP service
|
||||
* drop-upload service
|
||||
* helper service
|
||||
* storage service.
|
||||
|
||||
|
@ -116,7 +104,7 @@ set the ``tub.location`` option described below.
|
|||
|
||||
This controls where the node's web server should listen, providing node
|
||||
status and, if the node is a client/server, providing web-API service as
|
||||
defined in :doc:`frontends/webapi`.
|
||||
defined in webapi.rst_.
|
||||
|
||||
This file contains a Twisted "strports" specification such as "``3456``"
|
||||
or "``tcp:3456:interface=127.0.0.1``". The "``tahoe create-node``" or
|
||||
|
@ -140,126 +128,71 @@ set the ``tub.location`` option described below.
|
|||
``http://127.0.0.1:3456/static/foo.html`` will serve the contents of
|
||||
``BASEDIR/public_html/foo.html`` .
|
||||
|
||||
``tub.port = (endpoint specification strings or "disabled", optional)``
|
||||
``tub.port = (integer, optional)``
|
||||
|
||||
This controls which port the node uses to accept Foolscap connections
|
||||
from other nodes. It is parsed as a comma-separated list of Twisted
|
||||
"server endpoint descriptor" strings, each of which is a value like
|
||||
``tcp:12345`` and ``tcp:23456:interface=127.0.0.1``.
|
||||
from other nodes. If not provided, the node will ask the kernel for any
|
||||
available port. The port will be written to a separate file (named
|
||||
``client.port`` or ``introducer.port``), so that subsequent runs will
|
||||
re-use the same port.
|
||||
|
||||
To listen on multiple ports at once (e.g. both TCP-on-IPv4 and TCP-on-IPv6),
|
||||
use something like ``tcp6:interface=2600\:3c01\:f03c\:91ff\:fe93\:d272:3456,tcp:interface=8.8.8.8:3456``.
|
||||
Lists of endpoint descriptor strings like the following ``tcp:12345,tcp6:12345``
|
||||
are known to not work because an ``Address already in use.`` error.
|
||||
``tub.location = (string, optional)``
|
||||
|
||||
If any descriptor begins with ``listen:tor``, or ``listen:i2p``, the
|
||||
corresponding tor/i2p Provider object will construct additional endpoints
|
||||
for the Tub to listen on. This allows the ``[tor]`` or ``[i2p]`` sections
|
||||
in ``tahoe.cfg`` to customize the endpoint; e.g. to add I2CP control
|
||||
options. If you use ``listen:i2p``, you should not also have an
|
||||
``i2p:..`` endpoint in ``tub.port``, as that would result in multiple
|
||||
I2P-based listeners.
|
||||
|
||||
If ``tub.port`` is the string ``disabled``, the node will not listen at
|
||||
all, and thus cannot accept connections from other nodes. If ``[storage]
|
||||
enabled = true``, or ``[helper] enabled = true``, or the node is an
|
||||
Introducer, then it is an error to have ``tub.port`` be empty. If
|
||||
``tub.port`` is disabled, then ``tub.location`` must also be disabled,
|
||||
and vice versa.
|
||||
|
||||
For backwards compatibility, if this contains a simple integer, it will
|
||||
be used as a TCP port number, like ``tcp:%d`` (which will accept
|
||||
connections on all interfaces). However ``tub.port`` cannot be ``0`` or
|
||||
``tcp:0`` (older versions accepted this, but the node is no longer
|
||||
willing to ask Twisted to allocate port numbers in this way). If
|
||||
``tub.port`` is present, it may not be empty.
|
||||
|
||||
If the ``tub.port`` config key is not provided (e.g. ``tub.port`` appears
|
||||
nowhere in the ``[node]`` section, or is commented out), the node will
|
||||
look in ``BASEDIR/client.port`` (or ``BASEDIR/introducer.port``, for
|
||||
introducers) for the descriptor that was used last time.
|
||||
|
||||
If neither ``tub.port`` nor the port file is available, the node will ask
|
||||
the kernel to allocate any available port (the moral equivalent of
|
||||
``tcp:0``). The allocated port number will be written into a descriptor
|
||||
string in ``BASEDIR/client.port`` (or ``introducer.port``), so that
|
||||
subsequent runs will re-use the same port.
|
||||
|
||||
``tub.location = (hint string or "disabled", optional)``
|
||||
|
||||
In addition to running as a client, each Tahoe-LAFS node can also run as
|
||||
a server, listening for connections from other Tahoe-LAFS clients. The
|
||||
node announces its location by publishing a "FURL" (a string with some
|
||||
In addition to running as a client, each Tahoe-LAFS node also runs as a
|
||||
server, listening for connections from other Tahoe-LAFS clients. The node
|
||||
announces its location by publishing a "FURL" (a string with some
|
||||
connection hints) to the Introducer. The string it publishes can be found
|
||||
in ``BASEDIR/private/storage.furl`` . The ``tub.location`` configuration
|
||||
controls what location is published in this announcement.
|
||||
|
||||
If your node is meant to run as a server, you should fill this in, using
|
||||
a hostname or IP address that is reachable from your intended clients.
|
||||
|
||||
If ``tub.port`` is set to ``disabled``, then ``tub.location`` must also
|
||||
be ``disabled``.
|
||||
|
||||
If you don't provide ``tub.location``, the node will try to figure out a
|
||||
useful one by itself, by using tools like "``ifconfig``" to determine the
|
||||
set of IP addresses on which it can be reached from nodes both near and
|
||||
far. It will also include the TCP port number on which it is listening
|
||||
far. It will also include the TCP port number on which it is listening
|
||||
(either the one specified by ``tub.port``, or whichever port was assigned
|
||||
by the kernel when ``tub.port`` is left unspecified). However this
|
||||
automatic address-detection is discouraged, and will probably be removed
|
||||
from a future release. It will include the ``127.0.0.1`` "localhost"
|
||||
address (which is only useful to clients running on the same computer),
|
||||
and RFC1918 private-network addresses like ``10.*.*.*`` and
|
||||
``192.168.*.*`` (which are only useful to clients on the local LAN). In
|
||||
general, the automatically-detected IP addresses will only be useful if
|
||||
the node has a public IP address, such as a VPS or colo-hosted server.
|
||||
by the kernel when ``tub.port`` is left unspecified).
|
||||
|
||||
You will certainly need to set ``tub.location`` if your node lives behind
|
||||
a firewall that is doing inbound port forwarding, or if you are using
|
||||
other proxies such that the local IP address or port number is not the
|
||||
same one that remote clients should use to connect. You might also want
|
||||
to control this when using a Tor proxy to avoid revealing your actual IP
|
||||
address through the Introducer announcement.
|
||||
You might want to override this value if your node lives behind a
|
||||
firewall that is doing inbound port forwarding, or if you are using other
|
||||
proxies such that the local IP address or port number is not the same one
|
||||
that remote clients should use to connect. You might also want to control
|
||||
this when using a Tor proxy to avoid revealing your actual IP address
|
||||
through the Introducer announcement.
|
||||
|
||||
If ``tub.location`` is specified, by default it entirely replaces the
|
||||
automatically determined set of IP addresses. To include the automatically
|
||||
determined addresses as well as the specified ones, include the uppercase
|
||||
string "``AUTO``" in the list.
|
||||
|
||||
The value is a comma-separated string of method:host:port location hints,
|
||||
like this::
|
||||
The value is a comma-separated string of host:port location hints, like
|
||||
this::
|
||||
|
||||
tcp:123.45.67.89:8098,tcp:tahoe.example.com:8098,tcp:127.0.0.1:8098
|
||||
123.45.67.89:8098,tahoe.example.com:8098,127.0.0.1:8098
|
||||
|
||||
A few examples:
|
||||
|
||||
* Don't listen at all (client-only mode)::
|
||||
* Emulate default behavior, assuming your host has IP address
|
||||
123.45.67.89 and the kernel-allocated port number was 8098::
|
||||
|
||||
tub.port = disabled
|
||||
tub.location = disabled
|
||||
tub.port = 8098
|
||||
tub.location = 123.45.67.89:8098,127.0.0.1:8098
|
||||
|
||||
* Use a DNS name so you can change the IP address more easily::
|
||||
|
||||
tub.port = tcp:8098
|
||||
tub.location = tcp:tahoe.example.com:8098
|
||||
|
||||
* Run a node behind a firewall (which has an external IP address) that
|
||||
has been configured to forward external port 7912 to our internal
|
||||
node's port 8098::
|
||||
|
||||
tub.port = tcp:8098
|
||||
tub.location = tcp:external-firewall.example.com:7912
|
||||
|
||||
* Emulate default behavior, assuming your host has public IP address of
|
||||
123.45.67.89, and the kernel-allocated port number was 8098::
|
||||
|
||||
tub.port = tcp:8098
|
||||
tub.location = tcp:123.45.67.89:8098,tcp:127.0.0.1:8098
|
||||
tub.port = 8098
|
||||
tub.location = tahoe.example.com:8098
|
||||
|
||||
* Use a DNS name but also include the default set of addresses::
|
||||
|
||||
tub.port = tcp:8098
|
||||
tub.location = tcp:tahoe.example.com:8098,AUTO
|
||||
tub.port = 8098
|
||||
tub.location = tahoe.example.com:8098,AUTO
|
||||
|
||||
* Run a node behind a firewall (which has an external IP address) that
|
||||
has been configured to forward port 7912 to our internal node's port
|
||||
8098::
|
||||
|
||||
tub.port = 8098
|
||||
tub.location = external-firewall.example.com:7912
|
||||
|
||||
* Run a node behind a Tor proxy (perhaps via ``torsocks``), in
|
||||
client-only mode (i.e. we can make outbound connections, but other
|
||||
|
@ -268,8 +201,8 @@ set the ``tub.location`` option described below.
|
|||
reminder to human observers that this node cannot be reached. "Don't
|
||||
call us.. we'll call you"::
|
||||
|
||||
tub.port = tcp:8098
|
||||
tub.location = tcp:unreachable.example.org:0
|
||||
tub.port = 8098
|
||||
tub.location = unreachable.example.org:0
|
||||
|
||||
* Run a node behind a Tor proxy, and make the server available as a Tor
|
||||
"hidden service". (This assumes that other clients are running their
|
||||
|
@ -285,8 +218,10 @@ set the ``tub.location`` option described below.
|
|||
``/var/lib/tor/hidden_services/tahoe/hostname``. Then set up your
|
||||
``tahoe.cfg`` like::
|
||||
|
||||
tub.port = tcp:8098
|
||||
tub.location = tor:ualhejtq2p7ohfbb.onion:29212
|
||||
tub.port = 8098
|
||||
tub.location = ualhejtq2p7ohfbb.onion:29212
|
||||
|
||||
Most users will not need to set ``tub.location``.
|
||||
|
||||
``log_gatherer.furl = (FURL, optional)``
|
||||
|
||||
|
@ -337,6 +272,19 @@ set the ``tub.location`` option described below.
|
|||
|
||||
.. _`#521`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/521
|
||||
|
||||
``ssh.port = (strports string, optional)``
|
||||
|
||||
``ssh.authorized_keys_file = (filename, optional)``
|
||||
|
||||
This enables an SSH-based interactive Python shell, which can be used to
|
||||
inspect the internal state of the node, for debugging. To cause the node
|
||||
to accept SSH connections on port 8022 from the same keys as the rest of
|
||||
your account, use::
|
||||
|
||||
[tub]
|
||||
ssh.port = 8022
|
||||
ssh.authorized_keys_file = ~/.ssh/authorized_keys
|
||||
|
||||
``tempdir = (string, optional)``
|
||||
|
||||
This specifies a temporary directory for the web-API server to use, for
|
||||
|
@ -349,228 +297,8 @@ set the ``tub.location`` option described below.
|
|||
used for files that usually (on a Unix system) go into ``/tmp``. The
|
||||
string will be interpreted relative to the node's base directory.
|
||||
|
||||
``reveal-IP-address = (boolean, optional, defaults to True)``
|
||||
.. _webapi.rst: frontends/webapi.rst
|
||||
|
||||
This is a safety flag. When set to False (aka "private mode"), the node
|
||||
will refuse to start if any of the other configuration options would
|
||||
reveal the node's IP address to servers or the external network. This
|
||||
flag does not directly affect the node's behavior: its only power is to
|
||||
veto node startup when something looks unsafe.
|
||||
|
||||
The default is True (non-private mode), because setting it to False
|
||||
requires the installation of additional libraries (use ``pip install
|
||||
tahoe-lafs[tor]`` and/or ``pip install tahoe-lafs[i2p]`` to get them) as
|
||||
well as additional non-python software (Tor/I2P daemons). Performance is
|
||||
also generally reduced when operating in private mode.
|
||||
|
||||
When False, any of the following configuration problems will cause
|
||||
``tahoe run`` to throw a PrivacyError instead of starting the node:
|
||||
|
||||
* ``[node] tub.location`` contains any ``tcp:`` hints
|
||||
|
||||
* ``[node] tub.location`` uses ``AUTO``, or is missing/empty (because
|
||||
that defaults to AUTO)
|
||||
|
||||
* ``[connections] tcp =`` is set to ``tcp`` (or left as the default),
|
||||
rather than being set to ``tor`` or ``disabled``
|
||||
|
||||
|
||||
.. _Connection Management:
|
||||
|
||||
Connection Management
|
||||
=====================
|
||||
|
||||
Three sections (``[tor]``, ``[i2p]``, and ``[connections]``) control how the
|
||||
Tahoe node makes outbound connections. Tor and I2P are configured here. This
|
||||
also controls when Tor and I2P are used: for all TCP connections (to hide
|
||||
your IP address), or only when necessary (just for servers which declare that
|
||||
they need Tor, because they use ``.onion`` addresses).
|
||||
|
||||
Note that if you want to protect your node's IP address, you should set
|
||||
``[node] reveal-IP-address = False``, which will refuse to launch the node if
|
||||
any of the other configuration settings might violate this privacy property.
|
||||
|
||||
``[connections]``
|
||||
-----------------
|
||||
|
||||
This section controls *when* Tor and I2P are used. The ``[tor]`` and
|
||||
``[i2p]`` sections (described later) control *how* Tor/I2P connections are
|
||||
managed.
|
||||
|
||||
All Tahoe nodes need to make a connection to the Introducer; the
|
||||
``private/introducers.yaml`` file (described below) configures where one or more
|
||||
Introducers live. Tahoe client nodes must also make connections to storage
|
||||
servers: these targets are specified in announcements that come from the
|
||||
Introducer. Both are expressed as FURLs (a Foolscap URL), which include a
|
||||
list of "connection hints". Each connection hint describes one (of perhaps
|
||||
many) network endpoints where the service might live.
|
||||
|
||||
Connection hints include a type, and look like:
|
||||
|
||||
* ``tcp:tahoe.example.org:12345``
|
||||
* ``tor:u33m4y7klhz3b.onion:1000``
|
||||
* ``i2p:c2ng2pbrmxmlwpijn``
|
||||
|
||||
``tor`` hints are always handled by the ``tor`` handler (configured in the
|
||||
``[tor]`` section, described below). Likewise, ``i2p`` hints are always
|
||||
routed to the ``i2p`` handler. But either will be ignored if Tahoe was not
|
||||
installed with the necessary Tor/I2P support libraries, or if the Tor/I2P
|
||||
daemon is unreachable.
|
||||
|
||||
The ``[connections]`` section lets you control how ``tcp`` hints are handled.
|
||||
By default, they use the normal TCP handler, which just makes direct
|
||||
connections (revealing your node's IP address to both the target server and
|
||||
the intermediate network). The node behaves this way if the ``[connections]``
|
||||
section is missing entirely, or if it looks like this::
|
||||
|
||||
[connections]
|
||||
tcp = tcp
|
||||
|
||||
To hide the Tahoe node's IP address from the servers that it uses, set the
|
||||
``[connections]`` section to use Tor for TCP hints::
|
||||
|
||||
[connections]
|
||||
tcp = tor
|
||||
|
||||
You can also disable TCP hints entirely, which would be appropriate when
|
||||
running an I2P-only node::
|
||||
|
||||
[connections]
|
||||
tcp = disabled
|
||||
|
||||
(Note that I2P does not support connections to normal TCP ports, so
|
||||
``[connections] tcp = i2p`` is invalid)
|
||||
|
||||
In the future, Tahoe services may be changed to live on HTTP/HTTPS URLs
|
||||
instead of Foolscap. In that case, connections will be made using whatever
|
||||
handler is configured for ``tcp`` hints. So the same ``tcp = tor``
|
||||
configuration will work.
|
||||
|
||||
``[tor]``
|
||||
---------
|
||||
|
||||
This controls how Tor connections are made. The defaults (all empty) mean
|
||||
that, when Tor is needed, the node will try to connect to a Tor daemon's
|
||||
SOCKS proxy on localhost port 9050 or 9150. Port 9050 is the default Tor
|
||||
SOCKS port, so it should be available under any system Tor instance (e.g. the
|
||||
one launched at boot time when the standard Debian ``tor`` package is
|
||||
installed). Port 9150 is the SOCKS port for the Tor Browser Bundle, so it
|
||||
will be available any time the TBB is running.
|
||||
|
||||
You can set ``launch = True`` to cause the Tahoe node to launch a new Tor
|
||||
daemon when it starts up (and kill it at shutdown), if you don't have a
|
||||
system-wide instance available. Note that it takes 30-60 seconds for Tor to
|
||||
get running, so using a long-running Tor process may enable a faster startup.
|
||||
If your Tor executable doesn't live on ``$PATH``, use ``tor.executable=`` to
|
||||
specify it.
|
||||
|
||||
``[tor]``
|
||||
|
||||
``enabled = (boolean, optional, defaults to True)``
|
||||
|
||||
If False, this will disable the use of Tor entirely. The default of True
|
||||
means the node will use Tor, if necessary, and if possible.
|
||||
|
||||
``socks.port = (string, optional, endpoint specification string, defaults to empty)``
|
||||
|
||||
This tells the node that Tor connections should be routed to a SOCKS
|
||||
proxy listening on the given endpoint. The default (of an empty value)
|
||||
will cause the node to first try localhost port 9050, then if that fails,
|
||||
try localhost port 9150. These are the default listening ports of the
|
||||
standard Tor daemon, and the Tor Browser Bundle, respectively.
|
||||
|
||||
While this nominally accepts an arbitrary endpoint string, internal
|
||||
limitations prevent it from accepting anything but ``tcp:HOST:PORT``
|
||||
(unfortunately, unix-domain sockets are not yet supported). See ticket
|
||||
#2813 for details. Also note that using a HOST of anything other than
|
||||
localhost is discouraged, because you would be revealing your IP address
|
||||
to external (and possibly hostile) machines.
|
||||
|
||||
``control.port = (string, optional, endpoint specification string)``
|
||||
|
||||
This tells the node to connect to a pre-existing Tor daemon on the given
|
||||
control port (which is typically ``unix://var/run/tor/control`` or
|
||||
``tcp:localhost:9051``). The node will then ask Tor what SOCKS port it is
|
||||
using, and route Tor connections to that.
|
||||
|
||||
``launch = (bool, optional, defaults to False)``
|
||||
|
||||
If True, the node will spawn a new (private) copy of Tor at startup, and
|
||||
will kill it at shutdown. The new Tor will be given a persistent state
|
||||
directory under ``NODEDIR/private/``, where Tor's microdescriptors will
|
||||
be cached, to speed up subsequent startup.
|
||||
|
||||
``tor.executable = (string, optional, defaults to empty)``
|
||||
|
||||
This controls which Tor executable is used when ``launch = True``. If
|
||||
empty, the first executable program named ``tor`` found on ``$PATH`` will
|
||||
be used.
|
||||
|
||||
There are 5 valid combinations of these configuration settings:
|
||||
|
||||
* 1: ``(empty)``: use SOCKS on port 9050/9150
|
||||
* 2: ``launch = true``: launch a new Tor
|
||||
* 3: ``socks.port = tcp:HOST:PORT``: use an existing Tor on the given SOCKS port
|
||||
* 4: ``control.port = ENDPOINT``: use an existing Tor at the given control port
|
||||
* 5: ``enabled = false``: no Tor at all
|
||||
|
||||
1 is the default, and should work for any Linux host with the system Tor
|
||||
package installed. 2 should work on any box with Tor installed into $PATH,
|
||||
but will take an extra 30-60 seconds at startup. 3 and 4 can be used for
|
||||
specialized installations, where Tor is already running, but not listening on
|
||||
the default port. 5 should be used in environments where Tor is installed,
|
||||
but should not be used (perhaps due to a site-wide policy).
|
||||
|
||||
Note that Tor support depends upon some additional Python libraries. To
|
||||
install Tahoe with Tor support, use ``pip install tahoe-lafs[tor]``.
|
||||
|
||||
``[i2p]``
|
||||
---------
|
||||
|
||||
This controls how I2P connections are made. Like with Tor, the all-empty
|
||||
defaults will cause I2P connections to be routed to a pre-existing I2P daemon
|
||||
on port 7656. This is the default SAM port for the ``i2p`` daemon.
|
||||
|
||||
|
||||
``[i2p]``
|
||||
|
||||
``enabled = (boolean, optional, defaults to True)``
|
||||
|
||||
If False, this will disable the use of I2P entirely. The default of True
|
||||
means the node will use I2P, if necessary, and if possible.
|
||||
|
||||
``sam.port = (string, optional, endpoint descriptor, defaults to empty)``
|
||||
|
||||
This tells the node that I2P connections should be made via the SAM
|
||||
protocol on the given port. The default (of an empty value) will cause
|
||||
the node to try localhost port 7656. This is the default listening port
|
||||
of the standard I2P daemon.
|
||||
|
||||
``launch = (bool, optional, defaults to False)``
|
||||
|
||||
If True, the node will spawn a new (private) copy of I2P at startup, and
|
||||
will kill it at shutdown. The new I2P will be given a persistent state
|
||||
directory under ``NODEDIR/private/``, where I2P's microdescriptors will
|
||||
be cached, to speed up subsequent startup. The daemon will allocate its
|
||||
own SAM port, which will be queried from the config directory.
|
||||
|
||||
``i2p.configdir = (string, optional, directory)``
|
||||
|
||||
This tells the node to parse an I2P config file in the given directory,
|
||||
and use the SAM port it finds there. If ``launch = True``, the new I2P
|
||||
daemon will be told to use the given directory (which can be
|
||||
pre-populated with a suitable config file). If ``launch = False``, we
|
||||
assume there is a pre-running I2P daemon running from this directory, and
|
||||
can again parse the config file for the SAM port.
|
||||
|
||||
``i2p.executable = (string, optional, defaults to empty)``
|
||||
|
||||
This controls which I2P executable is used when ``launch = True``. If
|
||||
empty, the first executable program named ``i2p`` found on ``$PATH`` will
|
||||
be used.
|
||||
|
||||
|
||||
.. _Client Configuration:
|
||||
|
||||
Client Configuration
|
||||
====================
|
||||
|
@ -579,8 +307,6 @@ Client Configuration
|
|||
|
||||
``introducer.furl = (FURL string, mandatory)``
|
||||
|
||||
DEPRECATED. See :ref:`introducer-definitions`.
|
||||
|
||||
This FURL tells the client how to connect to the introducer. Each
|
||||
Tahoe-LAFS grid is defined by an introducer. The introducer's FURL is
|
||||
created by the introducer node and written into its private base
|
||||
|
@ -590,7 +316,18 @@ Client Configuration
|
|||
``helper.furl = (FURL string, optional)``
|
||||
|
||||
If provided, the node will attempt to connect to and use the given helper
|
||||
for uploads. See :doc:`helper` for details.
|
||||
for uploads. See helper.rst_ for details.
|
||||
|
||||
``key_generator.furl = (FURL string, optional)``
|
||||
|
||||
If provided, the node will attempt to connect to and use the given
|
||||
key-generator service, using RSA keys from the external process rather
|
||||
than generating its own.
|
||||
|
||||
``stats_gatherer.furl = (FURL string, optional)``
|
||||
|
||||
If provided, the node will connect to the given stats gatherer and
|
||||
provide it with operational statistics.
|
||||
|
||||
``shares.needed = (int, optional) aka "k", default 3``
|
||||
|
||||
|
@ -615,7 +352,7 @@ Client Configuration
|
|||
ratios are more reliable, and small ``N``/``k`` ratios use less disk
|
||||
space. ``N`` cannot be larger than 256, because of the 8-bit
|
||||
erasure-coding algorithm that Tahoe-LAFS uses. ``k`` can not be greater
|
||||
than ``N``. See :doc:`performance` for more details.
|
||||
than ``N``. See performance.rst_ for more details.
|
||||
|
||||
``shares.happy`` allows you control over how well to "spread out" the
|
||||
shares of an immutable file. For a successful upload, shares are
|
||||
|
@ -653,49 +390,19 @@ Client Configuration
|
|||
controlled by this parameter and will always use SDMF. We may revisit
|
||||
this decision in future versions of Tahoe-LAFS.
|
||||
|
||||
See :doc:`specifications/mutable` for details about mutable file formats.
|
||||
See mutable.rst_ for details about mutable file formats.
|
||||
|
||||
``peers.preferred = (string, optional)``
|
||||
|
||||
This is an optional comma-separated list of Node IDs of servers that will
|
||||
be tried first when selecting storage servers for reading or writing.
|
||||
|
||||
Servers should be identified here by their Node ID as it appears in the web
|
||||
ui, underneath the server's nickname. For storage servers running tahoe
|
||||
versions >=1.10 (if the introducer is also running tahoe >=1.10) this will
|
||||
be a "Node Key" (which is prefixed with 'v0-'). For older nodes, it will be
|
||||
a TubID instead. When a preferred server (and/or the introducer) is
|
||||
upgraded to 1.10 or later, clients must adjust their configs accordingly.
|
||||
|
||||
Every node selected for upload, whether preferred or not, will still
|
||||
receive the same number of shares (one, if there are ``N`` or more servers
|
||||
accepting uploads). Preferred nodes are simply moved to the front of the
|
||||
server selection lists computed for each file.
|
||||
|
||||
This is useful if a subset of your nodes have different availability or
|
||||
connectivity characteristics than the rest of the grid. For instance, if
|
||||
there are more than ``N`` servers on the grid, and ``K`` or more of them
|
||||
are at a single physical location, it would make sense for clients at that
|
||||
location to prefer their local servers so that they can maintain access to
|
||||
all of their uploads without using the internet.
|
||||
|
||||
``force_foolscap = (boolean, optional)``
|
||||
|
||||
If this is ``True``, the client will only connect to storage servers via
|
||||
Foolscap, regardless of whether they support HTTPS. If this is ``False``,
|
||||
the client will prefer HTTPS when it is available on the server. The default
|
||||
value is ``False``.
|
||||
|
||||
In addition,
|
||||
see :doc:`accepting-donations` for a convention for donating to storage server operators.
|
||||
.. _helper.rst: helper.rst
|
||||
.. _performance.rst: performance.rst
|
||||
.. _mutable.rst: specifications/mutable.rst
|
||||
|
||||
Frontend Configuration
|
||||
======================
|
||||
|
||||
The Tahoe-LAFS client process can run a variety of frontend file access
|
||||
protocols. You will use these to create and retrieve files from the
|
||||
Tahoe-LAFS file store. Configuration details for each are documented in
|
||||
the following protocol-specific guides:
|
||||
The Tahoe client process can run a variety of frontend file-access protocols.
|
||||
You will use these to create and retrieve files from the virtual filesystem.
|
||||
Configuration details for each are documented in the following
|
||||
protocol-specific guides:
|
||||
|
||||
HTTP
|
||||
|
||||
|
@ -704,22 +411,33 @@ HTTP
|
|||
directories and files, as well as a number of pages to check on the
|
||||
status of your Tahoe node. It also provides a machine-oriented "WAPI",
|
||||
with a REST-ful HTTP interface that can be used by other programs
|
||||
(including the CLI tools). Please see :doc:`frontends/webapi` for full
|
||||
details, and the ``web.port`` and ``web.static`` config variables above.
|
||||
:doc:`frontends/download-status` also describes a few WUI status pages.
|
||||
(including the CLI tools). Please see webapi.rst_ for full details, and
|
||||
the ``web.port`` and ``web.static`` config variables above. The
|
||||
`download-status.rst`_ document also describes a few WUI status pages.
|
||||
|
||||
CLI
|
||||
|
||||
The main ``tahoe`` executable includes subcommands for manipulating the
|
||||
file store, uploading/downloading files, and creating/running Tahoe
|
||||
nodes. See :doc:`frontends/CLI` for details.
|
||||
The main "bin/tahoe" executable includes subcommands for manipulating the
|
||||
filesystem, uploading/downloading files, and creating/running Tahoe
|
||||
nodes. See CLI.rst_ for details.
|
||||
|
||||
SFTP
|
||||
SFTP, FTP
|
||||
|
||||
Tahoe can also run SFTP servers, and map a username/password
|
||||
pair to a top-level Tahoe directory. See :doc:`frontends/FTP-and-SFTP`
|
||||
for instructions on configuring this service, and the ``[sftpd]``
|
||||
section of ``tahoe.cfg``.
|
||||
Tahoe can also run both SFTP and FTP servers, and map a username/password
|
||||
pair to a top-level Tahoe directory. See FTP-and-SFTP.rst_ for
|
||||
instructions on configuring these services, and the ``[sftpd]`` and
|
||||
``[ftpd]`` sections of ``tahoe.cfg``.
|
||||
|
||||
Drop-Upload
|
||||
|
||||
As of Tahoe-LAFS v1.9.0, a node running on Linux can be configured to
|
||||
automatically upload files that are created or changed in a specified
|
||||
local directory. See drop-upload.rst_ for details.
|
||||
|
||||
.. _download-status.rst: frontends/download-status.rst
|
||||
.. _CLI.rst: frontends/CLI.rst
|
||||
.. _FTP-and-SFTP.rst: frontends/FTP-and-SFTP.rst
|
||||
.. _drop-upload.rst: frontends/drop-upload.rst
|
||||
|
||||
|
||||
Storage Server Configuration
|
||||
|
@ -735,17 +453,6 @@ Storage Server Configuration
|
|||
for clients who do not wish to provide storage service. The default value
|
||||
is ``True``.
|
||||
|
||||
``anonymous = (boolean, optional)``
|
||||
|
||||
If this is ``True``, the node will expose the storage server via Foolscap
|
||||
without any additional authentication or authorization. The capability to
|
||||
use all storage services is conferred by knowledge of the Foolscap fURL
|
||||
for the storage server which will be included in the storage server's
|
||||
announcement. If it is ``False``, the node will not expose this and
|
||||
storage must be exposed using the storage server plugin system (see
|
||||
`Storage Server Plugin Configuration`_ for details). The default value is
|
||||
``True``.
|
||||
|
||||
``readonly = (boolean, optional)``
|
||||
|
||||
If ``True``, the node will run a storage server but will not accept any
|
||||
|
@ -790,54 +497,10 @@ Storage Server Configuration
|
|||
|
||||
These settings control garbage collection, in which the server will
|
||||
delete shares that no longer have an up-to-date lease on them. Please see
|
||||
:doc:`garbage-collection` for full details.
|
||||
garbage-collection.rst_ for full details.
|
||||
|
||||
.. _#390: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/390
|
||||
|
||||
``storage_dir = (string, optional)``
|
||||
|
||||
This specifies a directory where share files and other state pertaining to
|
||||
storage servers will be kept.
|
||||
|
||||
The default value is the ``storage`` directory in the node's base directory
|
||||
(i.e. ``BASEDIR/storage``), but it can be placed elsewhere. Relative paths
|
||||
will be interpreted relative to the node's base directory.
|
||||
|
||||
``force_foolscap = (boolean, optional)``
|
||||
|
||||
If this is ``True``, the node will expose the storage server via Foolscap
|
||||
only, with no support for HTTPS. If this is ``False``, the server will
|
||||
support both Foolscap and HTTPS on the same port. The default value is
|
||||
``False``.
|
||||
|
||||
In addition,
|
||||
see :doc:`accepting-donations` for a convention encouraging donations to storage server operators.
|
||||
|
||||
|
||||
Storage Server Plugin Configuration
|
||||
===================================
|
||||
|
||||
In addition to the built-in storage server,
|
||||
it is also possible to load and configure storage server plugins into Tahoe-LAFS.
|
||||
|
||||
Plugins to load are specified in the ``[storage]`` section.
|
||||
|
||||
``plugins = (string, optional)``
|
||||
|
||||
This gives a comma-separated list of plugin names.
|
||||
Plugins named here will be loaded and offered to clients.
|
||||
The default is for no such plugins to be loaded.
|
||||
|
||||
Each plugin can also be configured in a dedicated section.
|
||||
The section for each plugin is named after the plugin itself::
|
||||
|
||||
[storageserver.plugins.<plugin name>]
|
||||
|
||||
For example,
|
||||
the configuration section for a plugin named ``acme-foo-v1`` is ``[storageserver.plugins.acme-foo-v1]``.
|
||||
|
||||
The contents of such sections are defined by the plugins themselves.
|
||||
Refer to the documentation provided with those plugins.
|
||||
.. _garbage-collection.rst: garbage-collection.rst
|
||||
|
||||
|
||||
Running A Helper
|
||||
|
@ -850,12 +513,12 @@ service.
|
|||
|
||||
``enabled = (boolean, optional)``
|
||||
|
||||
If ``True``, the node will run a helper (see :doc:`helper` for details).
|
||||
If ``True``, the node will run a helper (see helper.rst_ for details).
|
||||
The helper's contact FURL will be placed in ``private/helper.furl``, from
|
||||
which it can be copied to any clients that wish to use it. Clearly nodes
|
||||
should not both run a helper and attempt to use one: do not create
|
||||
``helper.furl`` and also define ``[helper]enabled`` in the same node. The
|
||||
default is ``False``.
|
||||
``helper.furl`` and also define ``[helper]enabled`` in the same node.
|
||||
The default is ``False``.
|
||||
|
||||
|
||||
Running An Introducer
|
||||
|
@ -880,8 +543,6 @@ Other Files in BASEDIR
|
|||
|
||||
Some configuration is not kept in ``tahoe.cfg``, for the following reasons:
|
||||
|
||||
* it doesn't fit into the INI format of ``tahoe.cfg`` (e.g.
|
||||
``private/servers.yaml``)
|
||||
* it is generated by the node at startup, e.g. encryption keys. The node
|
||||
never writes to ``tahoe.cfg``.
|
||||
* it is generated by user action, e.g. the "``tahoe create-alias``" command.
|
||||
|
@ -904,7 +565,7 @@ This section describes these other files.
|
|||
files on behalf of other clients. There will be a directory underneath it
|
||||
for each StorageIndex for which this node is holding shares. There is also
|
||||
an "incoming" directory where partially-completed shares are held while
|
||||
they are being received. This location may be overridden in ``tahoe.cfg``.
|
||||
they are being received.
|
||||
|
||||
``tahoe-client.tac``
|
||||
|
||||
|
@ -919,6 +580,16 @@ This section describes these other files.
|
|||
This file is used to construct an introducer, and is created by the
|
||||
"``tahoe create-introducer``" command.
|
||||
|
||||
``tahoe-key-generator.tac``
|
||||
|
||||
This file is used to construct a key generator, and is created by the
|
||||
"``tahoe create-key-gernerator``" command.
|
||||
|
||||
``tahoe-stats-gatherer.tac``
|
||||
|
||||
This file is used to construct a statistics gatherer, and is created by the
|
||||
"``tahoe create-stats-gatherer``" command.
|
||||
|
||||
``private/control.furl``
|
||||
|
||||
This file contains a FURL that provides access to a control port on the
|
||||
|
@ -938,7 +609,7 @@ This section describes these other files.
|
|||
``private/helper.furl``
|
||||
|
||||
If the node is running a helper (for use by other clients), its contact
|
||||
FURL will be placed here. See :doc:`helper` for more details.
|
||||
FURL will be placed here. See helper.rst_ for more details.
|
||||
|
||||
``private/root_dir.cap`` (optional)
|
||||
|
||||
|
@ -970,142 +641,6 @@ This section describes these other files.
|
|||
with as many people as possible, put the empty string (so that
|
||||
``private/convergence`` is a zero-length file).
|
||||
|
||||
.. _introducer-definitions:
|
||||
|
||||
Introducer Definitions
|
||||
======================
|
||||
|
||||
The ``private/introducers.yaml`` file defines Introducers.
|
||||
Choose a locally-unique "petname" for each one then define their FURLs in ``private/introducers.yaml`` like this::
|
||||
|
||||
introducers:
|
||||
petname2:
|
||||
furl: "FURL2"
|
||||
petname3:
|
||||
furl: "FURL3"
|
||||
|
||||
Servers will announce themselves to all configured introducers. Clients will
|
||||
merge the announcements they receive from all introducers. Nothing will
|
||||
re-broadcast an announcement (i.e. telling introducer 2 about something you
|
||||
heard from introducer 1).
|
||||
|
||||
If you omit the introducer definitions from ``introducers.yaml``,
|
||||
the node will not use an Introducer at all.
|
||||
Such "introducerless" clients must be configured with static servers (described
|
||||
below), or they will not be able to upload and download files.
|
||||
|
||||
|
||||
.. _server_list:
|
||||
|
||||
Static Server Definitions
|
||||
=========================
|
||||
|
||||
The ``private/servers.yaml`` file defines "static servers": those which are
|
||||
not announced through the Introducer. This can also control how we connect to
|
||||
those servers.
|
||||
|
||||
Most clients do not need this file. It is only necessary if you want to use
|
||||
servers which are (for some specialized reason) not announced through the
|
||||
Introducer, or to connect to those servers in different ways. You might do
|
||||
this to "freeze" the server list: use the Introducer for a while, then copy
|
||||
all announcements into ``servers.yaml``, then stop using the Introducer
|
||||
entirely. Or you might have a private server that you don't want other users
|
||||
to learn about (via the Introducer). Or you might run a local server which is
|
||||
announced to everyone else as a Tor onion address, but which you can connect
|
||||
to directly (via TCP).
|
||||
|
||||
The file syntax is `YAML`_, with a top-level dictionary named ``storage``.
|
||||
Other items may be added in the future.
|
||||
|
||||
The ``storage`` dictionary takes keys which are server-ids, and values which
|
||||
are dictionaries with two keys: ``ann`` and ``connections``. The ``ann``
|
||||
value is a dictionary which will be used in lieu of the introducer
|
||||
announcement, so it can be populated by copying the ``ann`` dictionary from
|
||||
``NODEDIR/introducer_cache.yaml``.
|
||||
|
||||
The server-id can be any string, but ideally you should use the public key as
|
||||
published by the server. Each server displays this as "Node ID:" in the
|
||||
top-right corner of its "WUI" web welcome page. It can also be obtained from
|
||||
other client nodes, which record it as ``key_s:`` in their
|
||||
``introducer_cache.yaml`` file. The format is "v0-" followed by 52 base32
|
||||
characters like so::
|
||||
|
||||
v0-c2ng2pbrmxmlwpijn3mr72ckk5fmzk6uxf6nhowyosaubrt6y5mq
|
||||
|
||||
The ``ann`` dictionary really only needs one key:
|
||||
|
||||
* ``anonymous-storage-FURL``: how we connect to the server
|
||||
|
||||
(note that other important keys may be added in the future, as Accounting and
|
||||
HTTP-based servers are implemented)
|
||||
|
||||
Optional keys include:
|
||||
|
||||
* ``nickname``: the name of this server, as displayed on the Welcome page
|
||||
server list
|
||||
* ``permutation-seed-base32``: this controls how shares are mapped to
|
||||
servers. This is normally computed from the server-ID, but can be
|
||||
overridden to maintain the mapping for older servers which used to use
|
||||
Foolscap TubIDs as server-IDs. If your selected server-ID cannot be parsed
|
||||
as a public key, it will be hashed to compute the permutation seed. This is
|
||||
fine as long as all clients use the same thing, but if they don't, then
|
||||
your client will disagree with the other clients about which servers should
|
||||
hold each share. This will slow downloads for everybody, and may cause
|
||||
additional work or consume extra storage when repair operations don't
|
||||
converge.
|
||||
* anything else from the ``introducer_cache.yaml`` announcement, like
|
||||
``my-version``, which is displayed on the Welcome page server list
|
||||
|
||||
For example, a private static server could be defined with a
|
||||
``private/servers.yaml`` file like this::
|
||||
|
||||
storage:
|
||||
v0-4uazse3xb6uu5qpkb7tel2bm6bpea4jhuigdhqcuvvse7hugtsia:
|
||||
ann:
|
||||
nickname: my-server-1
|
||||
anonymous-storage-FURL: pb://u33m4y7klhz3bypswqkozwetvabelhxt@tcp:8.8.8.8:51298/eiu2i7p6d6mm4ihmss7ieou5hac3wn6b
|
||||
|
||||
Or, if you're feeling really lazy::
|
||||
|
||||
storage:
|
||||
my-serverid-1:
|
||||
ann:
|
||||
anonymous-storage-FURL: pb://u33m4y7klhz3bypswqkozwetvabelhxt@tcp:8.8.8.8:51298/eiu2i7p6d6mm4ihmss7ieou5hac3wn6b
|
||||
|
||||
.. _YAML: http://yaml.org/
|
||||
|
||||
Overriding Connection-Handlers for Static Servers
|
||||
-------------------------------------------------
|
||||
|
||||
A ``connections`` entry will override the default connection-handler mapping
|
||||
(as established by ``tahoe.cfg [connections]``). This can be used to build a
|
||||
"Tor-mostly client": one which is restricted to use Tor for all connections,
|
||||
except for a few private servers to which normal TCP connections will be
|
||||
made. To override the published announcement (and thus avoid connecting twice
|
||||
to the same server), the server ID must exactly match.
|
||||
|
||||
``tahoe.cfg``::
|
||||
|
||||
[connections]
|
||||
# this forces the use of Tor for all "tcp" hints
|
||||
tcp = tor
|
||||
|
||||
``private/servers.yaml``::
|
||||
|
||||
storage:
|
||||
v0-c2ng2pbrmxmlwpijn3mr72ckk5fmzk6uxf6nhowyosaubrt6y5mq:
|
||||
ann:
|
||||
nickname: my-server-1
|
||||
anonymous-storage-FURL: pb://u33m4y7klhz3bypswqkozwetvabelhxt@tcp:10.1.2.3:51298/eiu2i7p6d6mm4ihmss7ieou5hac3wn6b
|
||||
connections:
|
||||
# this overrides the tcp=tor from tahoe.cfg, for just this server
|
||||
tcp: tcp
|
||||
|
||||
The ``connections`` table is needed to override the ``tcp = tor`` mapping
|
||||
that comes from ``tahoe.cfg``. Without it, the client would attempt to use
|
||||
Tor to connect to ``10.1.2.3``, which would fail because it is a
|
||||
local/non-routeable (RFC1918) address.
|
||||
|
||||
|
||||
Other files
|
||||
===========
|
||||
|
@ -1136,7 +671,7 @@ Other files
|
|||
files. The web-API has a facility to block access to filecaps by their
|
||||
storage index, returning a 403 "Forbidden" error instead of the original
|
||||
file. For more details, see the "Access Blacklist" section of
|
||||
:doc:`frontends/webapi`.
|
||||
webapi.rst_.
|
||||
|
||||
|
||||
Example
|
||||
|
@ -1151,15 +686,18 @@ a legal one.
|
|||
|
||||
[node]
|
||||
nickname = Bob's Tahoe-LAFS Node
|
||||
tub.port = tcp:34912
|
||||
tub.location = tcp:123.45.67.89:8098,tcp:44.55.66.77:8098
|
||||
web.port = tcp:3456
|
||||
tub.port = 34912
|
||||
tub.location = 123.45.67.89:8098,44.55.66.77:8098
|
||||
web.port = 3456
|
||||
log_gatherer.furl = pb://soklj4y7eok5c3xkmjeqpw@192.168.69.247:44801/eqpwqtzm
|
||||
timeout.keepalive = 240
|
||||
timeout.disconnect = 1800
|
||||
ssh.port = 8022
|
||||
ssh.authorized_keys_file = ~/.ssh/authorized_keys
|
||||
|
||||
[client]
|
||||
helper.furl = pb://ggti5ssoklj4y7eok5c3xkmj@tcp:helper.tahoe.example:7054/kk8lhr
|
||||
introducer.furl = pb://ok45ssoklj4y7eok5c3xkmj@tahoe.example:44801/ii3uumo
|
||||
helper.furl = pb://ggti5ssoklj4y7eok5c3xkmj@helper.tahoe.example:7054/kk8lhr
|
||||
|
||||
[storage]
|
||||
enabled = True
|
||||
|
@ -1169,11 +707,6 @@ a legal one.
|
|||
[helper]
|
||||
enabled = True
|
||||
|
||||
To be introduced to storage servers, here is a sample ``private/introducers.yaml`` which can be used in conjunction::
|
||||
|
||||
introducers:
|
||||
examplegrid:
|
||||
furl: "pb://ok45ssoklj4y7eok5c3xkmj@tcp:tahoe.example:44801/ii3uumo"
|
||||
|
||||
Old Configuration Files
|
||||
=======================
|
||||
|
@ -1181,4 +714,6 @@ Old Configuration Files
|
|||
Tahoe-LAFS releases before v1.3.0 had no ``tahoe.cfg`` file, and used
|
||||
distinct files for each item. This is no longer supported and if you have
|
||||
configuration in the old format you must manually convert it to the new
|
||||
format for Tahoe-LAFS to detect it. See :doc:`historical/configuration`.
|
||||
format for Tahoe-LAFS to detect it. See `historical/configuration.rst`_.
|
||||
|
||||
.. _historical/configuration.rst: historical/configuration.rst
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
.. include:: ../.github/CONTRIBUTING.rst
|
|
@ -1,9 +1,5 @@
|
|||
.. -*- coding: utf-8-with-signature -*-
|
||||
|
||||
**********************
|
||||
The Convergence Secret
|
||||
**********************
|
||||
|
||||
What Is It?
|
||||
-----------
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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-----
|
|
@ -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-----
|
|
@ -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)
|
|
@ -10,7 +10,7 @@ The Tahoe-LAFS CLI commands
|
|||
1. `Unicode Support`_
|
||||
|
||||
3. `Node Management`_
|
||||
4. `File Store Manipulation`_
|
||||
4. `Filesystem Manipulation`_
|
||||
|
||||
1. `Starting Directories`_
|
||||
2. `Command Syntax Summary`_
|
||||
|
@ -23,10 +23,21 @@ The Tahoe-LAFS CLI commands
|
|||
Overview
|
||||
========
|
||||
|
||||
Tahoe-LAFS provides a single executable named "``tahoe``", which can be used
|
||||
to create and manage client/server nodes, manipulate the file store, and
|
||||
perform several debugging/maintenance tasks. This executable is installed
|
||||
into your virtualenv when you run ``pip install tahoe-lafs``.
|
||||
Tahoe-LAFS provides a single executable named "``tahoe``", which can be used to
|
||||
create and manage client/server nodes, manipulate the filesystem, and perform
|
||||
several debugging/maintenance tasks.
|
||||
|
||||
This executable lives in the source tree at "``bin/tahoe``". Once you've done a
|
||||
build (by running "``make``" or "``python setup.py build``"), ``bin/tahoe`` can
|
||||
be run in-place: if it discovers that it is being run from within a Tahoe-LAFS
|
||||
source tree, it will modify ``sys.path`` as necessary to use all the source code
|
||||
and dependent libraries contained in that tree.
|
||||
|
||||
If you've installed Tahoe-LAFS (using "``make install``" or
|
||||
"``python setup.py install``", or by installing a binary package), then the
|
||||
``tahoe`` executable will be available somewhere else, perhaps in
|
||||
``/usr/bin/tahoe``. In this case, it will use your platform's normal
|
||||
PYTHONPATH search path to find the Tahoe-LAFS code and other libraries.
|
||||
|
||||
|
||||
CLI Command Overview
|
||||
|
@ -35,7 +46,7 @@ CLI Command Overview
|
|||
The "``tahoe``" tool provides access to three categories of commands.
|
||||
|
||||
* node management: create a client/server node, start/stop/restart it
|
||||
* file store manipulation: list files, upload, download, unlink, rename
|
||||
* filesystem manipulation: list files, upload, download, unlink, rename
|
||||
* debugging: unpack cap-strings, examine share files
|
||||
|
||||
To get a list of all commands, just run "``tahoe``" with no additional
|
||||
|
@ -44,7 +55,7 @@ arguments. "``tahoe --help``" might also provide something useful.
|
|||
Running "``tahoe --version``" will display a list of version strings, starting
|
||||
with the "allmydata" module (which contains the majority of the Tahoe-LAFS
|
||||
functionality) and including versions for a number of dependent libraries,
|
||||
like Twisted, Foolscap, cryptography, and zfec. "``tahoe --version-and-path``"
|
||||
like Twisted, Foolscap, pycryptopp, and zfec. "``tahoe --version-and-path``"
|
||||
will also show the path from which each library was imported.
|
||||
|
||||
On Unix systems, the shell expands filename wildcards (``'*'`` and ``'?'``)
|
||||
|
@ -83,18 +94,18 @@ the command line.
|
|||
Node Management
|
||||
===============
|
||||
|
||||
"``tahoe create-node [NODEDIR]``" is the basic make-a-new-node
|
||||
command. It creates a new directory and populates it with files that
|
||||
will allow the "``tahoe run``" and related commands to use it later
|
||||
on. ``tahoe create-node`` creates nodes that have client functionality
|
||||
(upload/download files), web API services (controlled by the
|
||||
'[node]web.port' configuration), and storage services (unless
|
||||
``--no-storage`` is specified).
|
||||
"``tahoe create-node [NODEDIR]``" is the basic make-a-new-node command. It
|
||||
creates a new directory and populates it with files that will allow the
|
||||
"``tahoe start``" command to use it later on. This command creates nodes that
|
||||
have client functionality (upload/download files), web API services
|
||||
(controlled by the '[node]web.port' configuration), and storage services
|
||||
(unless ``--no-storage`` is specified).
|
||||
|
||||
NODEDIR defaults to ``~/.tahoe/`` , and newly-created nodes default to
|
||||
publishing a web server on port 3456 (limited to the loopback interface, at
|
||||
127.0.0.1, to restrict access to other programs on the same host). All of the
|
||||
other "``tahoe``" subcommands use corresponding defaults.
|
||||
other "``tahoe``" subcommands use corresponding defaults (with the exception
|
||||
that "``tahoe run``" defaults to running a node in the current directory).
|
||||
|
||||
"``tahoe create-client [NODEDIR]``" creates a node with no storage service.
|
||||
That is, it behaves like "``tahoe create-node --no-storage [NODEDIR]``".
|
||||
|
@ -105,26 +116,38 @@ This node provides introduction services and nothing else. When started, this
|
|||
node will produce a ``private/introducer.furl`` file, which should be
|
||||
published to all clients.
|
||||
|
||||
"``tahoe create-key-generator [NODEDIR]``" is used to create a special
|
||||
"key-generation" service, which allows a client to offload their RSA key
|
||||
generation to a separate process. Since RSA key generation takes several
|
||||
seconds, and must be done each time a directory is created, moving it to a
|
||||
separate process allows the first process (perhaps a busy web-API server) to
|
||||
continue servicing other requests. The key generator exports a FURL that can
|
||||
be copied into a node to enable this functionality.
|
||||
|
||||
Running Nodes
|
||||
-------------
|
||||
"``tahoe run [NODEDIR]``" will start a previously-created node in the foreground.
|
||||
|
||||
No matter what kind of node you created, the correct way to run it is
|
||||
to use the ``tahoe run`` command. "``tahoe run [NODEDIR]``" will start
|
||||
a previously-created node in the foreground. This command functions
|
||||
the same way on all platforms and logs to stdout. If you want to run
|
||||
the process as a daemon, it is recommended that you use your favourite
|
||||
daemonization tool.
|
||||
"``tahoe start [NODEDIR]``" will launch a previously-created node. It will
|
||||
launch the node into the background, using the standard Twisted "``twistd``"
|
||||
daemon-launching tool. On some platforms (including Windows) this command is
|
||||
unable to run a daemon in the background; in that case it behaves in the
|
||||
same way as "``tahoe run``".
|
||||
|
||||
File Store Manipulation
|
||||
"``tahoe stop [NODEDIR]``" will shut down a running node.
|
||||
|
||||
"``tahoe restart [NODEDIR]``" will stop and then restart a running node. This
|
||||
is most often used by developers who have just modified the code and want to
|
||||
start using their changes.
|
||||
|
||||
|
||||
Filesystem Manipulation
|
||||
=======================
|
||||
|
||||
These commands let you exmaine a Tahoe-LAFS file store, providing basic
|
||||
These commands let you exmaine a Tahoe-LAFS filesystem, providing basic
|
||||
list/upload/download/unlink/rename/mkdir functionality. They can be used as
|
||||
primitives by other scripts. Most of these commands are fairly thin wrappers
|
||||
around web-API calls, which are described in :doc:`webapi`.
|
||||
around web-API calls, which are described in `<webapi.rst>`__.
|
||||
|
||||
By default, all file store manipulation commands look in ``~/.tahoe/`` to
|
||||
By default, all filesystem-manipulation commands look in ``~/.tahoe/`` to
|
||||
figure out which Tahoe-LAFS node they should use. When the CLI command makes
|
||||
web-API calls, it will use ``~/.tahoe/node.url`` for this purpose: a running
|
||||
Tahoe-LAFS node that provides a web-API port will write its URL into this
|
||||
|
@ -138,12 +161,13 @@ they ought to use a starting point. This is explained in more detail below.
|
|||
Starting Directories
|
||||
--------------------
|
||||
|
||||
As described in :doc:`../architecture`, the Tahoe-LAFS distributed file store
|
||||
consists of a collection of directories and files, each of which has a
|
||||
"read-cap" or a "write-cap" (also known as a URI). Each directory is simply a
|
||||
table that maps a name to a child file or directory, and this table is turned
|
||||
into a string and stored in a mutable file. The whole set of directory and
|
||||
file "nodes" are connected together into a directed graph.
|
||||
As described in `docs/architecture.rst <../architecture.rst>`__, the
|
||||
Tahoe-LAFS distributed filesystem consists of a collection of directories
|
||||
and files, each of which has a "read-cap" or a "write-cap" (also known as
|
||||
a URI). Each directory is simply a table that maps a name to a child file
|
||||
or directory, and this table is turned into a string and stored in a
|
||||
mutable file. The whole set of directory and file "nodes" are connected
|
||||
together into a directed graph.
|
||||
|
||||
To use this collection of files and directories, you need to choose a
|
||||
starting point: some specific directory that we will refer to as a
|
||||
|
@ -175,14 +199,12 @@ and later will use it if necessary. However, once you've set a ``tahoe:``
|
|||
alias with "``tahoe set-alias``", that will override anything in the old
|
||||
``root_dir.cap`` file.
|
||||
|
||||
The Tahoe-LAFS CLI commands use a similar path syntax to ``scp`` and
|
||||
The Tahoe-LAFS CLI commands use the same path syntax as ``scp`` and
|
||||
``rsync`` -- an optional ``ALIAS:`` prefix, followed by the pathname or
|
||||
filename. Some commands (like "``tahoe cp``") use the lack of an alias to
|
||||
mean that you want to refer to a local file, instead of something from the
|
||||
Tahoe-LAFS file store. Another way to indicate this is to start the
|
||||
pathname with "./", "~/", "~username/", or "/". On Windows, aliases
|
||||
cannot be a single character, so that it is possible to distinguish a
|
||||
path relative to an alias from a path starting with a local drive specifier.
|
||||
Tahoe-LAFS filesystem. Another way to indicate this is to start the
|
||||
pathname with "./", "~/", "~username/", or "/".
|
||||
|
||||
When you're dealing a single starting directory, the ``tahoe:`` alias is
|
||||
all you need. But when you want to refer to something that isn't yet
|
||||
|
@ -331,7 +353,7 @@ Command Examples
|
|||
|
||||
``tahoe ls subdir``
|
||||
|
||||
This lists a subdirectory of your file store.
|
||||
This lists a subdirectory of your filesystem.
|
||||
|
||||
``tahoe webopen``
|
||||
|
||||
|
@ -514,10 +536,10 @@ Command Examples
|
|||
the pattern will be matched against any level of the directory tree;
|
||||
it's still impossible to specify absolute path exclusions.
|
||||
|
||||
``tahoe backup --exclude-from-utf-8=/path/to/filename ~ work:backups``
|
||||
``tahoe backup --exclude-from=/path/to/filename ~ work:backups``
|
||||
|
||||
``--exclude-from-utf-8`` is similar to ``--exclude``, but reads exclusion
|
||||
patterns from a UTF-8-encoded ``/path/to/filename``, one per line.
|
||||
``--exclude-from`` is similar to ``--exclude``, but reads exclusion
|
||||
patterns from ``/path/to/filename``, one per line.
|
||||
|
||||
``tahoe backup --exclude-vcs ~ work:backups``
|
||||
|
||||
|
@ -608,6 +630,14 @@ into separate pieces. The most useful aspect of this command is to reveal the
|
|||
storage index for any given URI. This can be used to locate the share files
|
||||
that are holding the encoded+encrypted data for this file.
|
||||
|
||||
"``tahoe debug repl``" will launch an interactive Python interpreter in which
|
||||
the Tahoe-LAFS packages and modules are available on ``sys.path`` (e.g. by using
|
||||
'``import allmydata``'). This is most useful from a source tree: it simply sets
|
||||
the PYTHONPATH correctly and runs the Python executable.
|
||||
|
||||
"``tahoe debug corrupt-share SHAREFILE``" will flip a bit in the given
|
||||
sharefile. This can be used to test the client-side verification/repair code.
|
||||
Obviously, this command should not be used during normal operation.
|
||||
|
||||
"``tahoe debug trial [OPTIONS] [TESTSUITE]``" will run the tests specified by
|
||||
TESTSUITE (defaulting to the whole Tahoe test suite), using Twisted Trial.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -71,8 +71,8 @@ port 3456, on the loopback (127.0.0.1) interface.
|
|||
Basic Concepts: GET, PUT, DELETE, POST
|
||||
======================================
|
||||
|
||||
As described in :doc:`../architecture`, each file and directory in a
|
||||
Tahoe-LAFS file store is referenced by an identifier that combines the
|
||||
As described in `docs/architecture.rst`_, each file and directory in a Tahoe
|
||||
virtual filesystem is referenced by an identifier that combines the
|
||||
designation of the object with the authority to do something with it (such as
|
||||
read or modify the contents). This identifier is called a "read-cap" or
|
||||
"write-cap", depending upon whether it enables read-only or read-write
|
||||
|
@ -93,7 +93,7 @@ Other variations (generally implemented by adding query parameters to the
|
|||
URL) will return information about the object, such as metadata. GET
|
||||
operations are required to have no side-effects.
|
||||
|
||||
PUT is used to upload new objects into the file store, or to replace an
|
||||
PUT is used to upload new objects into the filesystem, or to replace an
|
||||
existing link or the contents of a mutable file. DELETE is used to unlink
|
||||
objects from directories. Both PUT and DELETE are required to be idempotent:
|
||||
performing the same operation multiple times must have the same side-effects
|
||||
|
@ -107,12 +107,12 @@ unlinking), because otherwise a regular web browser has no way to accomplish
|
|||
these tasks. In general, everything that can be done with a PUT or DELETE can
|
||||
also be done with a POST.
|
||||
|
||||
Tahoe-LAFS' web API is designed for two different kinds of consumer. The
|
||||
first is a program that needs to manipulate the file store. Such programs are
|
||||
Tahoe's web API is designed for two different kinds of consumer. The first is
|
||||
a program that needs to manipulate the virtual file system. Such programs are
|
||||
expected to use the RESTful interface described above. The second is a human
|
||||
using a standard web browser to work with the file store. This user is
|
||||
presented with a series of HTML pages with links to download files, and forms
|
||||
that use POST actions to upload, rename, and unlink files.
|
||||
using a standard web browser to work with the filesystem. This user is given
|
||||
a series of HTML pages with links to download files, and forms that use POST
|
||||
actions to upload, rename, and unlink files.
|
||||
|
||||
When an error occurs, the HTTP response code will be set to an appropriate
|
||||
400-series code (like 404 Not Found for an unknown childname, or 400 Bad Request
|
||||
|
@ -128,6 +128,7 @@ a plain text stack trace instead. If the Accept header contains ``*/*``, or
|
|||
be generated.
|
||||
|
||||
.. _RFC3986: https://tools.ietf.org/html/rfc3986
|
||||
.. _docs/architecture.rst: ../architecture.rst
|
||||
|
||||
|
||||
URLs
|
||||
|
@ -192,12 +193,12 @@ servers is required, /uri should be used.
|
|||
Child Lookup
|
||||
------------
|
||||
|
||||
Tahoe directories contain named child entries, just like directories in a
|
||||
regular local filesystem. These child entries, called "dirnodes", consist of
|
||||
a name, metadata, a write slot, and a read slot. The write and read slots
|
||||
normally contain a write-cap and read-cap referring to the same object, which
|
||||
can be either a file or a subdirectory. The write slot may be empty
|
||||
(actually, both may be empty, but that is unusual).
|
||||
Tahoe directories contain named child entries, just like directories in a regular
|
||||
local filesystem. These child entries, called "dirnodes", consist of a name,
|
||||
metadata, a write slot, and a read slot. The write and read slots normally contain
|
||||
a write-cap and read-cap referring to the same object, which can be either a file
|
||||
or a subdirectory. The write slot may be empty (actually, both may be empty,
|
||||
but that is unusual).
|
||||
|
||||
If you have a Tahoe URL that refers to a directory, and want to reference a
|
||||
named child inside it, just append the child name to the URL. For example, if
|
||||
|
@ -332,7 +333,7 @@ Programmatic Operations
|
|||
=======================
|
||||
|
||||
Now that we know how to build URLs that refer to files and directories in a
|
||||
Tahoe-LAFS file store, what sorts of operations can we do with those URLs?
|
||||
Tahoe virtual filesystem, what sorts of operations can we do with those URLs?
|
||||
This section contains a catalog of GET, PUT, DELETE, and POST operations that
|
||||
can be performed on these URLs. This set of operations are aimed at programs
|
||||
that use HTTP to communicate with a Tahoe node. A later section describes
|
||||
|
@ -351,11 +352,11 @@ Reading a File
|
|||
|
||||
The "Range:" header can be used to restrict which portions of the file are
|
||||
returned (see RFC 2616 section 14.35.1 "Byte Ranges"), however Tahoe only
|
||||
supports a single "bytes" range and never provides a
|
||||
``multipart/byteranges`` response. An attempt to begin a read past the end
|
||||
of the file will provoke a 416 Requested Range Not Satisfiable error, but
|
||||
normal overruns (reads which start at the beginning or middle and go beyond
|
||||
the end) are simply truncated.
|
||||
supports a single "bytes" range and never provides a `multipart/byteranges`
|
||||
response. An attempt to begin a read past the end of the file will provoke a
|
||||
416 Requested Range Not Satisfiable error, but normal overruns (reads which
|
||||
start at the beginning or middle and go beyond the end) are simply
|
||||
truncated.
|
||||
|
||||
To view files in a web browser, you may want more control over the
|
||||
Content-Type and Content-Disposition headers. Please see the next section
|
||||
|
@ -419,7 +420,7 @@ Writing/Uploading a File
|
|||
``PUT /uri``
|
||||
|
||||
This uploads a file, and produces a file-cap for the contents, but does not
|
||||
attach the file into the file store. No directories will be modified by
|
||||
attach the file into the filesystem. No directories will be modified by
|
||||
this operation. The file-cap is returned as the body of the HTTP response.
|
||||
|
||||
This method accepts format= and mutable=true as query string arguments, and
|
||||
|
@ -435,7 +436,7 @@ Creating a New Directory
|
|||
|
||||
Create a new empty directory and return its write-cap as the HTTP response
|
||||
body. This does not make the newly created directory visible from the
|
||||
file store. The "PUT" operation is provided for backwards compatibility:
|
||||
filesystem. The "PUT" operation is provided for backwards compatibility:
|
||||
new code should use POST.
|
||||
|
||||
This supports a format= argument in the query string. The format=
|
||||
|
@ -511,7 +512,7 @@ Creating a New Directory
|
|||
|
||||
The metadata may have a "no-write" field. If this is set to true in the
|
||||
metadata of a link, it will not be possible to open that link for writing
|
||||
via the SFTP frontend; see :doc:`FTP-and-SFTP` for details. Also, if the
|
||||
via the SFTP frontend; see FTP-and-SFTP.rst_ for details. Also, if the
|
||||
"no-write" field is set to true in the metadata of a link to a mutable
|
||||
child, it will cause the link to be diminished to read-only.
|
||||
|
||||
|
@ -670,6 +671,8 @@ Creating a New Directory
|
|||
This operation will return an error if the parent directory is immutable,
|
||||
or already has a child named NAME.
|
||||
|
||||
.. _FTP-and-SFTP.rst: FTP-and-SFTP.rst
|
||||
|
||||
|
||||
Getting Information About a File Or Directory (as JSON)
|
||||
-------------------------------------------------------
|
||||
|
@ -807,8 +810,8 @@ child is set. The value of the 'tahoe':'linkcrtime' key is updated whenever
|
|||
a link to a child is created -- i.e. when there was not previously a link
|
||||
under that name.
|
||||
|
||||
Note however, that if the edge in the Tahoe-LAFS file store points to a
|
||||
mutable file and the contents of that mutable file is changed, then the
|
||||
Note however, that if the edge in the Tahoe filesystem points to a mutable
|
||||
file and the contents of that mutable file is changed, then the
|
||||
'tahoe':'linkmotime' value on that edge will *not* be updated, since the
|
||||
edge itself wasn't updated -- only the mutable file was.
|
||||
|
||||
|
@ -835,8 +838,8 @@ The reason we added the new fields in Tahoe v1.4.0 is that there is a
|
|||
values of the 'mtime'/'ctime' pair, and this API is used by the
|
||||
"tahoe backup" command (in Tahoe v1.3.0 and later) to set the 'mtime' and
|
||||
'ctime' values when backing up files from a local filesystem into the
|
||||
Tahoe-LAFS file store. As of Tahoe v1.4.0, the set_children API cannot be
|
||||
used to set anything under the 'tahoe' key of the metadata dict -- if you
|
||||
Tahoe filesystem. As of Tahoe v1.4.0, the set_children API cannot be used
|
||||
to set anything under the 'tahoe' key of the metadata dict -- if you
|
||||
include 'tahoe' keys in your 'metadata' arguments then it will silently
|
||||
ignore those keys.
|
||||
|
||||
|
@ -864,8 +867,8 @@ When an edge is created or updated by "tahoe backup", the 'mtime' and
|
|||
There are several ways that the 'ctime' field could be confusing:
|
||||
|
||||
1. You might be confused about whether it reflects the time of the creation
|
||||
of a link in the Tahoe-LAFS file store (by a version of Tahoe < v1.7.0)
|
||||
or a timestamp copied in by "tahoe backup" from a local filesystem.
|
||||
of a link in the Tahoe filesystem (by a version of Tahoe < v1.7.0) or a
|
||||
timestamp copied in by "tahoe backup" from a local filesystem.
|
||||
|
||||
2. You might be confused about whether it is a copy of the file creation
|
||||
time (if "tahoe backup" was run on a Windows system) or of the last
|
||||
|
@ -895,7 +898,7 @@ Attaching an Existing File or Directory by its read- or write-cap
|
|||
``PUT /uri/$DIRCAP/[SUBDIRS../]CHILDNAME?t=uri``
|
||||
|
||||
This attaches a child object (either a file or directory) to a specified
|
||||
location in the Tahoe-LAFS file store. The child object is referenced by its
|
||||
location in the virtual filesystem. The child object is referenced by its
|
||||
read- or write- cap, as provided in the HTTP request body. This will create
|
||||
intermediate directories as necessary.
|
||||
|
||||
|
@ -1008,9 +1011,9 @@ Browser Operations: Human-oriented interfaces
|
|||
|
||||
This section describes the HTTP operations that provide support for humans
|
||||
running a web browser. Most of these operations use HTML forms that use POST
|
||||
to drive the Tahoe-LAFS node. This section is intended for HTML authors who
|
||||
want to write web pages containing user interfaces for manipulating the
|
||||
Tahoe-LAFS file store.
|
||||
to drive the Tahoe node. This section is intended for HTML authors who want
|
||||
to write web pages that contain forms and buttons which manipulate the Tahoe
|
||||
filesystem.
|
||||
|
||||
Note that for all POST operations, the arguments listed can be provided
|
||||
either as URL query arguments or as form body fields. URL query arguments are
|
||||
|
@ -1040,30 +1043,15 @@ Viewing/Downloading a File
|
|||
|
||||
``GET /uri/$DIRCAP/[SUBDIRS../]FILENAME``
|
||||
|
||||
``GET /named/$FILECAP/FILENAME``
|
||||
|
||||
These will retrieve the contents of the given file. The HTTP response body
|
||||
This will retrieve the contents of the given file. The HTTP response body
|
||||
will contain the sequence of bytes that make up the file.
|
||||
|
||||
The ``/named/`` form is an alternative to ``/uri/$FILECAP`` which makes it
|
||||
easier to get the correct filename. The Tahoe server will provide the
|
||||
contents of the given file, with a Content-Type header derived from the
|
||||
given filename. This form is used to get browsers to use the "Save Link As"
|
||||
feature correctly, and also helps command-line tools like "wget" and "curl"
|
||||
use the right filename. Note that this form can *only* be used with file
|
||||
caps; it is an error to use a directory cap after the /named/ prefix.
|
||||
|
||||
URLs may also use /file/$FILECAP/FILENAME as a synonym for
|
||||
/named/$FILECAP/FILENAME. The use of "/file/" is deprecated in favor of
|
||||
"/named/" and support for "/file/" will be removed in a future release of
|
||||
Tahoe-LAFS.
|
||||
|
||||
If you use the first form (``/uri/$FILECAP``) and want the HTTP response to
|
||||
include a useful Content-Type header, add a "filename=foo" query argument,
|
||||
like "GET /uri/$FILECAP?filename=foo.jpg". The bare "GET /uri/$FILECAP" does
|
||||
not give the Tahoe node enough information to determine a Content-Type
|
||||
(since LAFS immutable files are merely sequences of bytes, not typed and
|
||||
named file objects).
|
||||
If you want the HTTP response to include a useful Content-Type header,
|
||||
either use the second form (which starts with a $DIRCAP), or add a
|
||||
"filename=foo" query argument, like "GET /uri/$FILECAP?filename=foo.jpg".
|
||||
The bare "GET /uri/$FILECAP" does not give the Tahoe node enough information
|
||||
to determine a Content-Type (since Tahoe immutable files are merely
|
||||
sequences of bytes, not typed+named file objects).
|
||||
|
||||
If the URL has both filename= and "save=true" in the query arguments, then
|
||||
the server to add a "Content-Disposition: attachment" header, along with a
|
||||
|
@ -1072,12 +1060,25 @@ Viewing/Downloading a File
|
|||
most browsers will refuse to display it inline). "true", "t", "1", and other
|
||||
case-insensitive equivalents are all treated the same.
|
||||
|
||||
Character-set handling in URLs and HTTP headers is a :ref:`dubious
|
||||
art<urls-and-utf8>`. For maximum compatibility, Tahoe simply copies the
|
||||
bytes from the filename= argument into the Content-Disposition header's
|
||||
filename= parameter, without trying to interpret them in any particular way.
|
||||
Character-set handling in URLs and HTTP headers is a dubious art [1]_. For
|
||||
maximum compatibility, Tahoe simply copies the bytes from the filename=
|
||||
argument into the Content-Disposition header's filename= parameter, without
|
||||
trying to interpret them in any particular way.
|
||||
|
||||
|
||||
``GET /named/$FILECAP/FILENAME``
|
||||
|
||||
This is an alternate download form which makes it easier to get the correct
|
||||
filename. The Tahoe server will provide the contents of the given file, with
|
||||
a Content-Type header derived from the given filename. This form is used to
|
||||
get browsers to use the "Save Link As" feature correctly, and also helps
|
||||
command-line tools like "wget" and "curl" use the right filename. Note that
|
||||
this form can *only* be used with file caps; it is an error to use a
|
||||
directory cap after the /named/ prefix.
|
||||
|
||||
URLs may also use /file/$FILECAP/FILENAME as a synonym for
|
||||
/named/$FILECAP/FILENAME.
|
||||
|
||||
Getting Information About a File Or Directory (as HTML)
|
||||
-------------------------------------------------------
|
||||
|
||||
|
@ -1107,8 +1108,8 @@ Creating a Directory
|
|||
|
||||
``POST /uri?t=mkdir``
|
||||
|
||||
This creates a new empty directory, but does not attach it to any other
|
||||
directory in the Tahoe-LAFS file store.
|
||||
This creates a new empty directory, but does not attach it to the virtual
|
||||
filesystem.
|
||||
|
||||
If a "redirect_to_result=true" argument is provided, then the HTTP response
|
||||
will cause the web browser to be redirected to a /uri/$DIRCAP page that
|
||||
|
@ -1150,8 +1151,8 @@ Uploading a File
|
|||
``POST /uri?t=upload``
|
||||
|
||||
This uploads a file, and produces a file-cap for the contents, but does not
|
||||
attach the file to any directory in the Tahoe-LAFS file store. That is, no
|
||||
directories will be modified by this operation.
|
||||
attach the file into the filesystem. No directories will be modified by
|
||||
this operation.
|
||||
|
||||
The file must be provided as the "file" field of an HTML encoded form body,
|
||||
produced in response to an HTML form like this::
|
||||
|
@ -1312,9 +1313,9 @@ Relinking ("Moving") a Child
|
|||
is still reachable through any path from which it was formerly reachable,
|
||||
and the storage space occupied by its ciphertext is not affected.
|
||||
|
||||
The source and destination directories must be writeable. If ``to_dir`` is
|
||||
The source and destination directories must be writeable. If {{{to_dir}}} is
|
||||
not present, the child link is renamed within the same directory. If
|
||||
``to_name`` is not present then it defaults to ``from_name``. If the
|
||||
{{{to_name}}} is not present then it defaults to {{{from_name}}}. If the
|
||||
destination link (directory and name) is the same as the source link, the
|
||||
operation has no effect.
|
||||
|
||||
|
@ -1423,7 +1424,7 @@ mainly intended for developers.
|
|||
True. For distributed files, this dictionary has the following
|
||||
keys:
|
||||
count-happiness: the servers-of-happiness level of the file, as
|
||||
defined in doc/specifications/servers-of-happiness.
|
||||
defined in `docs/specifications/servers-of-happiness.rst`_.
|
||||
count-shares-good: the number of good shares that were found
|
||||
count-shares-needed: 'k', the number of shares required for recovery
|
||||
count-shares-expected: 'N', the number of total shares generated
|
||||
|
@ -1469,9 +1470,10 @@ mainly intended for developers.
|
|||
'seq%d-%s-sh%d', containing the sequence number, the
|
||||
roothash, and the share number.
|
||||
|
||||
Before Tahoe-LAFS v1.11, the ``results`` dictionary also had a
|
||||
``needs-rebalancing`` field, but that has been removed since it was computed
|
||||
incorrectly.
|
||||
Before Tahoe-LAFS v1.11, the `results` dictionary also had a `needs-rebalancing`
|
||||
field, but that has been removed since it was computed incorrectly.
|
||||
|
||||
.. _`docs/specifications/servers-of-happiness.rst`: ../specifications/servers-of-happiness.rst
|
||||
|
||||
|
||||
``POST $URL?t=start-deep-check`` (must add &ophandle=XYZ)
|
||||
|
@ -1699,7 +1701,7 @@ incorrectly.
|
|||
for debugging. This is a table of (path, filecap/dircap), for every object
|
||||
reachable from the starting directory. The path will be slash-joined, and
|
||||
the filecap/dircap will contain a link to the object in question. This page
|
||||
gives immediate access to every object in the file store subtree.
|
||||
gives immediate access to every object in the virtual filesystem subtree.
|
||||
|
||||
This operation uses the same ophandle= mechanism as deep-check. The
|
||||
corresponding /operations/$HANDLE page has three different forms. The
|
||||
|
@ -1751,9 +1753,6 @@ incorrectly.
|
|||
keys may be missing until 'finished' is True)::
|
||||
|
||||
finished: (bool) True if the operation has finished, else False
|
||||
api-version: (int), number of deep-stats API version. Will be increased every
|
||||
time backwards-incompatible change is introduced.
|
||||
Current version is 1.
|
||||
count-immutable-files: count of how many CHK files are in the set
|
||||
count-mutable-files: same, for mutable files (does not include directories)
|
||||
count-literal-files: same, for LIT files (data contained inside the URI)
|
||||
|
@ -1833,9 +1832,9 @@ Other Useful Pages
|
|||
==================
|
||||
|
||||
The portion of the web namespace that begins with "/uri" (and "/named") is
|
||||
dedicated to giving users (both humans and programs) access to the Tahoe-LAFS
|
||||
file store. The rest of the namespace provides status information about the
|
||||
state of the Tahoe-LAFS node.
|
||||
dedicated to giving users (both humans and programs) access to the Tahoe
|
||||
virtual filesystem. The rest of the namespace provides status information
|
||||
about the state of the Tahoe node.
|
||||
|
||||
``GET /`` (the root page)
|
||||
|
||||
|
@ -1843,47 +1842,13 @@ This is the "Welcome Page", and contains a few distinct sections::
|
|||
|
||||
Node information: library versions, local nodeid, services being provided.
|
||||
|
||||
File store access forms: create a new directory, view a file/directory by
|
||||
Filesystem Access Forms: create a new directory, view a file/directory by
|
||||
URI, upload a file (unlinked), download a file by
|
||||
URI.
|
||||
|
||||
Grid status: introducer information, helper information, connected storage
|
||||
Grid Status: introducer information, helper information, connected storage
|
||||
servers.
|
||||
|
||||
``GET /?t=json`` (the json welcome page)
|
||||
|
||||
This is the "json Welcome Page", and contains connectivity status
|
||||
of the introducer(s) and storage server(s), here's an example::
|
||||
|
||||
{
|
||||
"introducers": {
|
||||
"statuses": []
|
||||
},
|
||||
"servers": [{
|
||||
"nodeid": "other_nodeid",
|
||||
"available_space": 123456,
|
||||
"nickname": "George \u263b",
|
||||
"version": "1.0",
|
||||
"connection_status": "summary",
|
||||
"last_received_data": 1487811257
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
The above json ``introducers`` section includes a list of
|
||||
introducer connectivity status messages.
|
||||
|
||||
The above json ``servers`` section is an array with map elements. Each map
|
||||
has the following properties:
|
||||
|
||||
1. ``nodeid`` - an identifier derived from the node's public key
|
||||
2. ``available_space`` - the available space in bytes expressed as an integer
|
||||
3. ``nickname`` - the storage server nickname
|
||||
4. ``version`` - the storage server Tahoe-LAFS version
|
||||
5. ``connection_status`` - connectivity status
|
||||
6. ``last_received_data`` - the time when data was last received,
|
||||
expressed in seconds since epoch
|
||||
|
||||
``GET /status/``
|
||||
|
||||
This page lists all active uploads and downloads, and contains a short list
|
||||
|
@ -2028,25 +1993,23 @@ Safety and Security Issues -- Names vs. URIs
|
|||
============================================
|
||||
|
||||
Summary: use explicit file- and dir- caps whenever possible, to reduce the
|
||||
potential for surprises when the file store structure is changed.
|
||||
potential for surprises when the filesystem structure is changed.
|
||||
|
||||
Tahoe-LAFS provides a mutable file store, but the ways that the store can
|
||||
change are limited. The only things that can change are:
|
||||
Tahoe provides a mutable filesystem, but the ways that the filesystem can
|
||||
change are limited. The only thing that can change is that the mapping from
|
||||
child names to child objects that each directory contains can be changed by
|
||||
adding a new child name pointing to an object, removing an existing child name,
|
||||
or changing an existing child name to point to a different object.
|
||||
|
||||
* the mapping from child names to child objects inside mutable directories
|
||||
(by adding a new child, removing an existing child, or changing an
|
||||
existing child to point to a different object)
|
||||
* the contents of mutable files
|
||||
|
||||
Obviously if you query for information about the file store and then act
|
||||
to change it (such as by getting a listing of the contents of a mutable
|
||||
directory and then adding a file to the directory), then the store might
|
||||
have been changed after you queried it and before you acted upon it.
|
||||
However, if you use the URI instead of the pathname of an object when you
|
||||
act upon the object, then it will be the same object; only its contents
|
||||
can change (if it is mutable). If, on the other hand, you act upon the
|
||||
object using its pathname, then a different object might be in that place,
|
||||
which can result in more kinds of surprises.
|
||||
Obviously if you query Tahoe for information about the filesystem and then act
|
||||
to change the filesystem (such as by getting a listing of the contents of a
|
||||
directory and then adding a file to the directory), then the filesystem might
|
||||
have been changed after you queried it and before you acted upon it. However,
|
||||
if you use the URI instead of the pathname of an object when you act upon the
|
||||
object, then the only change that can happen is if the object is a directory
|
||||
then the set of child names it has might be different. If, on the other hand,
|
||||
you act upon the object using its pathname, then a different object might be in
|
||||
that place, which can result in more kinds of surprises.
|
||||
|
||||
For example, suppose you are writing code which recursively downloads the
|
||||
contents of a directory. The first thing your code does is fetch the listing
|
||||
|
@ -2054,14 +2017,15 @@ of the contents of the directory. For each child that it fetched, if that
|
|||
child is a file then it downloads the file, and if that child is a directory
|
||||
then it recurses into that directory. Now, if the download and the recurse
|
||||
actions are performed using the child's name, then the results might be
|
||||
wrong, because for example a child name that pointed to a subdirectory when
|
||||
wrong, because for example a child name that pointed to a sub-directory when
|
||||
you listed the directory might have been changed to point to a file (in which
|
||||
case your attempt to recurse into it would result in an error), or a child
|
||||
name that pointed to a file when you listed the directory might now point to
|
||||
a subdirectory (in which case your attempt to download the child would result
|
||||
in a file containing HTML text describing the subdirectory!).
|
||||
case your attempt to recurse into it would result in an error and the file
|
||||
would be skipped), or a child name that pointed to a file when you listed the
|
||||
directory might now point to a sub-directory (in which case your attempt to
|
||||
download the child would result in a file containing HTML text describing the
|
||||
sub-directory!).
|
||||
|
||||
If your recursive algorithm uses the URI of the child instead of the name of
|
||||
If your recursive algorithm uses the uri of the child instead of the name of
|
||||
the child, then those kinds of mistakes just can't happen. Note that both the
|
||||
child's name and the child's URI are included in the results of listing the
|
||||
parent directory, so it isn't any harder to use the URI for this purpose.
|
||||
|
@ -2121,7 +2085,9 @@ Tahoe-1.1; back with Tahoe-1.0 the web client was responsible for serializing
|
|||
web requests themselves).
|
||||
|
||||
For more details, please see the "Consistency vs Availability" and "The Prime
|
||||
Coordination Directive" sections of :doc:`../specifications/mutable`.
|
||||
Coordination Directive" sections of mutable.rst_.
|
||||
|
||||
.. _mutable.rst: ../specifications/mutable.rst
|
||||
|
||||
|
||||
Access Blacklist
|
||||
|
@ -2146,7 +2112,7 @@ you could do the following::
|
|||
tahoe debug dump-cap URI:CHK:n7r3m6wmomelk4sep3kw5cvduq:os7ijw5c3maek7pg65e5254k2fzjflavtpejjyhshpsxuqzhcwwq:3:20:14861
|
||||
-> storage index: whpepioyrnff7orecjolvbudeu
|
||||
echo "whpepioyrnff7orecjolvbudeu my puppy told me to" >>$NODEDIR/access.blacklist
|
||||
# ... restart the node to re-read configuration ...
|
||||
tahoe restart $NODEDIR
|
||||
tahoe get URI:CHK:n7r3m6wmomelk4sep3kw5cvduq:os7ijw5c3maek7pg65e5254k2fzjflavtpejjyhshpsxuqzhcwwq:3:20:14861
|
||||
-> error, 403 Access Prohibited: my puppy told me to
|
||||
|
||||
|
@ -2158,7 +2124,7 @@ When modifying the file, be careful to update it atomically, otherwise a
|
|||
request may arrive while the file is only halfway written, and the partial
|
||||
file may be incorrectly parsed.
|
||||
|
||||
The blacklist is applied to all access paths (including SFTP and CLI
|
||||
The blacklist is applied to all access paths (including SFTP, FTP, and CLI
|
||||
operations), not just the web-API. The blacklist also applies to directories.
|
||||
If a directory is blacklisted, the gateway will refuse access to both that
|
||||
directory and any child files/directories underneath it, when accessed via
|
||||
|
@ -2168,10 +2134,8 @@ file/dir will bypass the blacklist.
|
|||
The node will log the SI of the file being blocked, and the reason code, into
|
||||
the ``logs/twistd.log`` file.
|
||||
|
||||
URLs and HTTP and UTF-8
|
||||
=======================
|
||||
|
||||
.. _urls-and-utf8:
|
||||
.. [1] URLs and HTTP and UTF-8, Oh My
|
||||
|
||||
HTTP does not provide a mechanism to specify the character set used to
|
||||
encode non-ASCII names in URLs (`RFC3986#2.1`_). We prefer the convention
|
||||
|
@ -2230,3 +2194,4 @@ URLs and HTTP and UTF-8
|
|||
.. _RFC2231#4: https://tools.ietf.org/html/rfc2231#section-4
|
||||
.. _some developers have reported: http://markmail.org/message/dsjyokgl7hv64ig3
|
||||
.. _RFC2616#19.5.1: https://tools.ietf.org/html/rfc2616#section-19.5.1
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/>`__
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
* Tahoe Release Checklist [0/19]
|
||||
- [ ] NEWS.rst: summarize user-visible changes, aim for one page of text
|
||||
- [ ] update doc files
|
||||
- NEWS.rst: Add final release name and date to top-most item in NEWS.
|
||||
- relnotes.txt
|
||||
- CREDITS
|
||||
- docs/known_issues.rst
|
||||
- [ ] change docs/quickstart.rst to point to just the current
|
||||
allmydata-tahoe-X.Y.Z.zip source code file, or else to point to a
|
||||
directory which contains only allmydata-tahoe-X.Y.Z.* source code files
|
||||
- [ ] git pull
|
||||
- [ ] git tag -s -u 68666A7A allmydata-tahoe-X.Y.Z
|
||||
- produces a "signed tag"
|
||||
- tag body: allmydata-tahoe-X.Y.Z
|
||||
- [ ] build locally to make sure the release is reporting itself as the
|
||||
intended version
|
||||
- [ ] make sure buildbot is green
|
||||
- [ ] make sure other people aren't committing at that moment
|
||||
- [ ] push tag to trigger buildslaves. Making a code change is no longer
|
||||
necessary
|
||||
- git push official master TAGNAME
|
||||
- that will build tarballs
|
||||
- [ ] make sure buildbot is green
|
||||
- [ ] make sure a sumo sdist tarball got built and uploaded properly
|
||||
- [ ] download tarballs, sign with "gpg -ba -u 68666a7a TAR", upload *.asc
|
||||
- [ ] symlink the release tarball on tahoe-lafs.org:
|
||||
/var/www/source/tahoe-lafs/releases/
|
||||
- [ ] update Wiki: front page news, news, old news, parade of release
|
||||
notes ("Doc"), Installation
|
||||
- [ ] send out relnotes.txt:
|
||||
- modify to include hashes of tarballs, git revision
|
||||
- GPG-sign the email
|
||||
- send to tahoe-announce@tahoe-lafs.org and tahoe-dev@tahoe-lafs.org
|
||||
- [ ] update https://tahoe-lafs.org/hacktahoelafs/
|
||||
- [ ] update pypi:
|
||||
- python setup.py register
|
||||
- login to pypi
|
||||
- manually upload .tar.gz tarball and .asc signature (so they match the
|
||||
ones on tahoe-lafs.org), or use https://pypi.python.org/pypi/twine and
|
||||
run "twine upload *.tar.gz *.asc"
|
||||
- [ ] close the Milestone on the trac Roadmap
|
||||
- [ ] make an "announcement of new release" on freshmeat
|
||||
- [ ] make an "announcement of new release" on launchpad
|
||||
- [ ] send out relnotes.txt to:
|
||||
- p2p-hackers@lists.zooko.com
|
||||
- lwn@lwn.net
|
||||
- a Google+ page
|
||||
- cap-talk@mail.eros-os.org
|
||||
- cryptography@metzdown.com
|
||||
- cryptography@randombit.net
|
||||
- twisted-python@twistedmatrix.com
|
||||
- owncloud@kde.org
|
||||
- liberationtech@lists.stanford.edu
|
||||
- the "decentralization" group on groups.yahoo.com
|
||||
- pycrypto mailing list
|
||||
- fuse-devel@lists.sourceforge.net
|
||||
- fuse-sshfs@lists.sourceforge.net
|
||||
- duplicity-talk@nongnu.org
|
||||
- news@phoronix.com
|
||||
- python-list@python.org
|
||||
- cygwin@cygwin.com
|
||||
- The Boulder Linux Users' Group
|
||||
- The Boulder Hackerspace mailing list
|
||||
- cryptopp-users@googlegroups.com
|
||||
- tiddlywiki
|
||||
- hdfs-dev@hadoop.apache.org
|
||||
- bzr
|
||||
- mercurial
|
||||
- http://listcultures.org/pipermail/p2presearch_listcultures.org/
|
||||
- deltacloud
|
||||
- libcloud
|
||||
- swift@lists.launchpad.net
|
||||
- stephen@fosketts.net
|
||||
- Chris Mellor of The Register
|
||||
- nosql@mypopescu.com
|
||||
- The H Open
|
||||
- fans/customers of cleversafe
|
||||
- fans/customers of bitcasa
|
||||
- fans/customers of wuala
|
||||
- fans/customers of spideroak
|
|
@ -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`
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
.. -*- coding: utf-8-with-signature -*-
|
||||
|
||||
See also :doc:`cautions.rst<cautions>`.
|
||||
See also `cautions.rst`_.
|
||||
|
||||
.. _cautions.rst: cautions.rst
|
||||
|
||||
============
|
||||
Known Issues
|
||||
|
@ -8,22 +10,23 @@ Known Issues
|
|||
|
||||
Below is a list of known issues in recent releases of Tahoe-LAFS, and how to
|
||||
manage them. The current version of this file can be found at
|
||||
https://github.com/tahoe-lafs/tahoe-lafs/blob/master/docs/known_issues.rst .
|
||||
https://tahoe-lafs.org/source/tahoe-lafs/trunk/docs/known_issues.rst .
|
||||
|
||||
If you've been using Tahoe-LAFS since v1.1 (released 2008-06-11) or if you're
|
||||
just curious about what sort of mistakes we've made in the past, then you
|
||||
might want to read the "historical known issues" document in
|
||||
``docs/historical/historical_known_issues.txt``.
|
||||
just curious about what sort of mistakes we've made in the past, then you might
|
||||
want to read `the "historical known issues" document`_.
|
||||
|
||||
.. _the "historical known issues" document: historical/historical_known_issues.txt
|
||||
|
||||
|
||||
Known Issues in Tahoe-LAFS v1.10.3, released 30-Mar-2016
|
||||
Known Issues in Tahoe-LAFS v1.10.1, released 15-Jun-2015
|
||||
========================================================
|
||||
|
||||
* `Unauthorized access by JavaScript in unrelated files`_
|
||||
* `Disclosure of file through embedded hyperlinks or JavaScript in that file`_
|
||||
* `Command-line arguments are leaked to other local users`_
|
||||
* `Capabilities may be leaked to web browser phishing filter / "safe browsing" servers`_
|
||||
* `Known issues in the SFTP frontend`_
|
||||
* `Known issues in the FTP and SFTP frontends`_
|
||||
* `Traffic analysis based on sizes of files/directories, storage indices, and timing`_
|
||||
* `Privacy leak via Google Chart API link in map-update timing web page`_
|
||||
|
||||
|
@ -213,12 +216,12 @@ To disable the filter in Chrome:
|
|||
|
||||
----
|
||||
|
||||
Known issues in the SFTP frontend
|
||||
---------------------------------
|
||||
Known issues in the FTP and SFTP frontends
|
||||
------------------------------------------
|
||||
|
||||
These are documented in :doc:`frontends/FTP-and-SFTP` and on `the
|
||||
SftpFrontend page`_ on the wiki.
|
||||
These are documented in `docs/frontends/FTP-and-SFTP.rst`_ and on `the SftpFrontend page`_ on the wiki.
|
||||
|
||||
.. _docs/frontends/FTP-and-SFTP.rst: frontends/FTP-and-SFTP.rst
|
||||
.. _the SftpFrontend page: https://tahoe-lafs.org/trac/tahoe-lafs/wiki/SftpFrontend
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
===================
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
Magic Folder local filesystem integration design
|
||||
================================================
|
||||
|
||||
*Scope*
|
||||
|
||||
This document describes how to integrate the local filesystem with Magic
|
||||
Folder in an efficient and reliable manner. For now we ignore Remote to
|
||||
Local synchronization; the design and implementation of this is scheduled
|
||||
for a later time. We also ignore multiple writers for the same Magic
|
||||
Folder, which may or may not be supported in future. The design here will
|
||||
be updated to account for those features in later Objectives. Objective 3
|
||||
may require modifying the database schema or operation, and Objective 5
|
||||
may modify the User interface.
|
||||
|
||||
Tickets on the Tahoe-LAFS trac with the `otf-magic-folder-objective2`_
|
||||
keyword are within the scope of the local filesystem integration for
|
||||
Objective 2.
|
||||
|
||||
.. _otf-magic-folder-objective2: https://tahoe-lafs.org/trac/tahoe-lafs/query?status=!closed&keywords=~otf-magic-folder-objective2
|
||||
|
||||
*Local scanning and database*
|
||||
|
||||
When a Magic-Folder-enabled node starts up, it scans all directories
|
||||
under the local directory and adds every file to a first-in first-out
|
||||
"scan queue". When processing the scan queue, redundant uploads are
|
||||
avoided by using the same mechanism the Tahoe backup command uses: we
|
||||
keep track of previous uploads by recording each file's metadata such as
|
||||
size, ``ctime`` and ``mtime``. This information is stored in a database,
|
||||
referred to from now on as the magic folder db. Using this recorded
|
||||
state, we ensure that when Magic Folder is subsequently started, the
|
||||
local directory tree can be scanned quickly by comparing current
|
||||
filesystem metadata with the previously recorded metadata. Each file
|
||||
referenced in the scan queue is uploaded only if its metadata differs at
|
||||
the time it is processed. If a change event is detected for a file that
|
||||
is already queued (and therefore will be processed later), the redundant
|
||||
event is ignored.
|
||||
|
||||
To implement the magic folder db, we will use an SQLite schema that
|
||||
initially is the existing Tahoe-LAFS backup schema. This schema may
|
||||
change in later objectives; this will cause no backward compatibility
|
||||
problems, because this new feature will be developed on a branch that
|
||||
makes no compatibility guarantees. However we will have a separate SQLite
|
||||
database file and separate mutex lock just for Magic Folder. This avoids
|
||||
usability problems related to mutual exclusion. (If a single file and
|
||||
lock were used, a backup would block Magic Folder updates for a long
|
||||
time, and a user would not be able to tell when backups are possible
|
||||
because Magic Folder would acquire a lock at arbitrary times.)
|
||||
|
||||
|
||||
*Eventual consistency property*
|
||||
|
||||
During the process of reading a file in order to upload it, it is not
|
||||
possible to prevent further local writes. Such writes will result in
|
||||
temporary inconsistency (that is, the uploaded file will not reflect
|
||||
what the contents of the local file were at any specific time). Eventual
|
||||
consistency is reached when the queue of pending uploads is empty. That
|
||||
is, a consistent snapshot will be achieved eventually when local writes
|
||||
to the target folder cease for a sufficiently long period of time.
|
||||
|
||||
|
||||
*Detecting filesystem changes*
|
||||
|
||||
For the Linux implementation, we will use the inotify Linux kernel
|
||||
subsystem to gather events on the local Magic Folder directory tree. This
|
||||
implementation was already present in Tahoe-LAFS 1.9.0, but needs to be
|
||||
changed to gather directory creation and move events, in addition to the
|
||||
events indicating that a file has been written that are gathered by the
|
||||
current code.
|
||||
|
||||
For the Windows implementation, we will use the ``ReadDirectoryChangesW``
|
||||
Win32 API. The prototype implementation simulates a Python interface to
|
||||
the inotify API in terms of ``ReadDirectoryChangesW``, allowing most of
|
||||
the code to be shared across platforms.
|
||||
|
||||
The alternative of using `NTFS Change Journals`_ for Windows was
|
||||
considered, but appears to be more complicated and does not provide any
|
||||
additional functionality over the scanning approach described above.
|
||||
The Change Journal mechanism is also only available for NTFS filesystems,
|
||||
but FAT32 filesystems are still common in user installations of Windows.
|
||||
|
||||
.. _`NTFS Change Journals`: https://msdn.microsoft.com/en-us/library/aa363803%28VS.85%29.aspx
|
||||
|
||||
When we detect the creation of a new directory below the local Magic
|
||||
Folder directory, we create it in the Tahoe-LAFS filesystem, and also
|
||||
scan the new local directory for new files. This scan is necessary to
|
||||
avoid missing events for creation of files in a new directory before it
|
||||
can be watched, and to correctly handle cases where an existing directory
|
||||
is moved to be under the local Magic Folder directory.
|
||||
|
||||
|
||||
*User interface*
|
||||
|
||||
The Magic Folder local filesystem integration will initially have a
|
||||
provisional configuration file-based interface that may not be ideal from
|
||||
a usability perspective. Creating our local filesystem integration in
|
||||
this manner will allow us to use and test it independently of the rest of
|
||||
the Magic Folder software components. We will focus greater attention on
|
||||
user interface design as a later milestone in our development roadmap.
|
||||
|
||||
The configuration file, ``tahoe.cfg``, must define a target local
|
||||
directory to be synchronized. Provisionally, this configuration will
|
||||
replace the current ``[drop_upload]`` section::
|
||||
|
||||
[magic_folder]
|
||||
enabled = true
|
||||
local.directory = "/home/human"
|
||||
|
||||
When a filesystem directory is first configured for Magic Folder, the user
|
||||
needs to create the remote Tahoe-LAFS directory using ``tahoe mkdir``,
|
||||
and configure the Magic-Folder-enabled node with its URI (e.g. by putting
|
||||
it in a file ``private/magic_folder_dircap``). If there are existing
|
||||
files in the local directory, they will be uploaded as a result of the
|
||||
initial scan described earlier.
|
||||
|
|
@ -0,0 +1,898 @@
|
|||
Magic Folder design for remote-to-local sync
|
||||
============================================
|
||||
|
||||
Scope
|
||||
-----
|
||||
|
||||
In this Objective we will design remote-to-local synchronization:
|
||||
|
||||
* How to efficiently determine which objects (files and directories) have
|
||||
to be downloaded in order to bring the current local filesystem into sync
|
||||
with the newly-discovered version of the remote filesystem.
|
||||
* How to distinguish overwrites, in which the remote side was aware of
|
||||
your most recent version and overwrote it with a new version, from
|
||||
conflicts, in which the remote side was unaware of your most recent
|
||||
version when it published its new version. The latter needs to be raised
|
||||
to the user as an issue the user will have to resolve and the former must
|
||||
not bother the user.
|
||||
* How to overwrite the (stale) local versions of those objects with the
|
||||
newly acquired objects, while preserving backed-up versions of those
|
||||
overwritten objects in case the user didn't want this overwrite and wants
|
||||
to recover the old version.
|
||||
|
||||
Tickets on the Tahoe-LAFS trac with the `otf-magic-folder-objective4`_
|
||||
keyword are within the scope of the remote-to-local synchronization
|
||||
design.
|
||||
|
||||
.. _otf-magic-folder-objective4: https://tahoe-lafs.org/trac/tahoe-lafs/query?status=!closed&keywords=~otf-magic-folder-objective4
|
||||
|
||||
|
||||
Glossary
|
||||
''''''''
|
||||
|
||||
Object: a file or directory
|
||||
|
||||
DMD: distributed mutable directory
|
||||
|
||||
Folder: an abstract directory that is synchronized between clients.
|
||||
(A folder is not the same as the directory corresponding to it on
|
||||
any particular client, nor is it the same as a DMD.)
|
||||
|
||||
Collective: the set of clients subscribed to a given Magic Folder.
|
||||
|
||||
Descendant: a direct or indirect child in a directory or folder tree
|
||||
|
||||
Subfolder: a folder that is a descendant of a magic folder
|
||||
|
||||
Subpath: the path from a magic folder to one of its descendants
|
||||
|
||||
Write: a modification to a local filesystem object by a client
|
||||
|
||||
Read: a read from a local filesystem object by a client
|
||||
|
||||
Upload: an upload of a local object to the Tahoe-LAFS file store
|
||||
|
||||
Download: a download from the Tahoe-LAFS file store to a local object
|
||||
|
||||
Pending notification: a local filesystem change that has been detected
|
||||
but not yet processed.
|
||||
|
||||
|
||||
Representing the Magic Folder in Tahoe-LAFS
|
||||
-------------------------------------------
|
||||
|
||||
Unlike the local case where we use inotify or ReadDirectoryChangesW to
|
||||
detect filesystem changes, we have no mechanism to register a monitor for
|
||||
changes to a Tahoe-LAFS directory. Therefore, we must periodically poll
|
||||
for changes.
|
||||
|
||||
An important constraint on the solution is Tahoe-LAFS' "`write
|
||||
coordination directive`_", which prohibits concurrent writes by different
|
||||
storage clients to the same mutable object:
|
||||
|
||||
Tahoe does not provide locking of mutable files and directories. If
|
||||
there is more than one simultaneous attempt to change a mutable file
|
||||
or directory, then an UncoordinatedWriteError may result. This might,
|
||||
in rare cases, cause the file or directory contents to be accidentally
|
||||
deleted. The user is expected to ensure that there is at most one
|
||||
outstanding write or update request for a given file or directory at
|
||||
a time. One convenient way to accomplish this is to make a different
|
||||
file or directory for each person or process that wants to write.
|
||||
|
||||
.. _`write coordination directive`: ../../write_coordination.rst
|
||||
|
||||
Since it is a goal to allow multiple users to write to a Magic Folder,
|
||||
if the write coordination directive remains the same as above, then we
|
||||
will not be able to implement the Magic Folder as a single Tahoe-LAFS
|
||||
DMD. In general therefore, we will have multiple DMDs —spread across
|
||||
clients— that together represent the Magic Folder. Each client in a
|
||||
Magic Folder collective polls the other clients' DMDs in order to detect
|
||||
remote changes.
|
||||
|
||||
Six possible designs were considered for the representation of subfolders
|
||||
of the Magic Folder:
|
||||
|
||||
1. All subfolders written by a given Magic Folder client are collapsed
|
||||
into a single client DMD, containing immutable files. The child name of
|
||||
each file encodes the full subpath of that file relative to the Magic
|
||||
Folder.
|
||||
|
||||
2. The DMD tree under a client DMD is a direct copy of the folder tree
|
||||
written by that client to the Magic Folder. Not all subfolders have
|
||||
corresponding DMDs; only those to which that client has written files or
|
||||
child subfolders.
|
||||
|
||||
3. The directory tree under a client DMD is a ``tahoe backup`` structure
|
||||
containing immutable snapshots of the folder tree written by that client
|
||||
to the Magic Folder. As in design 2, only objects written by that client
|
||||
are present.
|
||||
|
||||
4. *Each* client DMD contains an eventually consistent mirror of all
|
||||
files and folders written by *any* Magic Folder client. Thus each client
|
||||
must also copy changes made by other Magic Folder clients to its own
|
||||
client DMD.
|
||||
|
||||
5. *Each* client DMD contains a ``tahoe backup`` structure containing
|
||||
immutable snapshots of all files and folders written by *any* Magic
|
||||
Folder client. Thus each client must also create another snapshot in its
|
||||
own client DMD when changes are made by another client. (It can potentially
|
||||
batch changes, subject to latency requirements.)
|
||||
|
||||
6. The write coordination problem is solved by implementing `two-phase
|
||||
commit`_. Then, the representation consists of a single DMD tree which is
|
||||
written by all clients.
|
||||
|
||||
.. _`two-phase commit`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1755
|
||||
|
||||
Here is a summary of advantages and disadvantages of each design:
|
||||
|
||||
+----------------------------+
|
||||
| Key |
|
||||
+=======+====================+
|
||||
| \+\+ | major advantage |
|
||||
+-------+--------------------+
|
||||
| \+ | minor advantage |
|
||||
+-------+--------------------+
|
||||
| ‒ | minor disadvantage |
|
||||
+-------+--------------------+
|
||||
| ‒ ‒ | major disadvantage |
|
||||
+-------+--------------------+
|
||||
| ‒ ‒ ‒ | showstopper |
|
||||
+-------+--------------------+
|
||||
|
||||
|
||||
123456+: All designs have the property that a recursive add-lease
|
||||
operation starting from a *collective directory* containing all of
|
||||
the client DMDs, will find all of the files and directories used in
|
||||
the Magic Folder representation. Therefore the representation is
|
||||
compatible with `garbage collection`_, even when a pre-Magic-Folder
|
||||
client does the lease marking.
|
||||
|
||||
.. _`garbage collection`: https://tahoe-lafs.org/trac/tahoe-lafs/browser/trunk/docs/garbage-collection.rst
|
||||
|
||||
123456+: All designs avoid "breaking" pre-Magic-Folder clients that read
|
||||
a directory or file that is part of the representation.
|
||||
|
||||
456++: Only these designs allow a readcap to one of the client
|
||||
directories —or one of their subdirectories— to be directly shared
|
||||
with other Tahoe-LAFS clients (not necessarily Magic Folder clients),
|
||||
so that such a client sees all of the contents of the Magic Folder.
|
||||
Note that this was not a requirement of the OTF proposal, although it
|
||||
is useful.
|
||||
|
||||
135+: A Magic Folder client has only one mutable Tahoe-LAFS object to
|
||||
monitor per other client. This minimizes communication bandwidth for
|
||||
polling, or alternatively the latency possible for a given polling
|
||||
bandwidth.
|
||||
|
||||
1236+: A client does not need to make changes to its own DMD that repeat
|
||||
changes that another Magic Folder client had previously made. This reduces
|
||||
write bandwidth and complexity.
|
||||
|
||||
1‒: If the Magic Folder has many subfolders, their files will all be
|
||||
collapsed into the same DMD, which could get quite large. In practice a
|
||||
single DMD can easily handle the number of files expected to be written
|
||||
by a client, so this is unlikely to be a significant issue.
|
||||
|
||||
123‒ ‒ ‒: In these designs, the set of files in a Magic Folder is
|
||||
represented as the union of the files in all client DMDs. However,
|
||||
when a file is modified by more than one client, it will be linked
|
||||
from multiple client DMDs. We therefore need a mechanism, such as a
|
||||
version number or a monotonically increasing timestamp, to determine
|
||||
which copy takes priority.
|
||||
|
||||
35‒ ‒: When a Magic Folder client detects a remote change, it must
|
||||
traverse an immutable directory structure to see what has changed.
|
||||
Completely unchanged subtrees will have the same URI, allowing some of
|
||||
this traversal to be shortcutted.
|
||||
|
||||
24‒ ‒ ‒: When a Magic Folder client detects a remote change, it must
|
||||
traverse a mutable directory structure to see what has changed. This is
|
||||
more complex and less efficient than traversing an immutable structure,
|
||||
because shortcutting is not possible (each DMD retains the same URI even
|
||||
if a descendant object has changed), and because the structure may change
|
||||
while it is being traversed. Also the traversal needs to be robust
|
||||
against cycles, which can only occur in mutable structures.
|
||||
|
||||
45‒ ‒: When a change occurs in one Magic Folder client, it will propagate
|
||||
to all the other clients. Each client will therefore see multiple
|
||||
representation changes for a single logical change to the Magic Folder
|
||||
contents, and must suppress the duplicates. This is particularly
|
||||
problematic for design 4 where it interacts with the preceding issue.
|
||||
|
||||
4‒ ‒ ‒, 5‒ ‒: There is the potential for client DMDs to get "out of sync"
|
||||
with each other, potentially for long periods if errors occur. Thus each
|
||||
client must be able to "repair" its client directory (and its
|
||||
subdirectory structure) concurrently with performing its own writes. This
|
||||
is a significant complexity burden and may introduce failure modes that
|
||||
could not otherwise happen.
|
||||
|
||||
6‒ ‒ ‒: While two-phase commit is a well-established protocol, its
|
||||
application to Tahoe-LAFS requires significant design work, and may still
|
||||
leave some corner cases of the write coordination problem unsolved.
|
||||
|
||||
|
||||
+------------------------------------------------+-----------------------------------------+
|
||||
| Design Property | Designs Proposed |
|
||||
+================================================+======+======+======+======+======+======+
|
||||
| **advantages** | *1* | *2* | *3* | *4* | *5* | *6* |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| Compatible with garbage collection |\+ |\+ |\+ |\+ |\+ |\+ |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| Does not break old clients |\+ |\+ |\+ |\+ |\+ |\+ |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| Allows direct sharing | | | |\+\+ |\+\+ |\+\+ |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| Efficient use of bandwidth |\+ | |\+ | |\+ | |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| No repeated changes |\+ |\+ |\+ | | |\+ |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| **disadvantages** | *1* | *2* | *3* | *4* | *5* | *6* |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| Can result in large DMDs |‒ | | | | | |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| Need version number to determine priority |‒ |‒ |‒ | | | |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| Must traverse immutable directory structure | | |‒ ‒ | |‒ ‒ | |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| Must traverse mutable directory structure | |‒ ‒ | |‒ ‒ | | |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| Must suppress duplicate representation changes | | | |‒ ‒ |‒ ‒ | |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| "Out of sync" problem | | | |‒ ‒ ‒ |‒ ‒ | |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
| Unsolved design problems | | | | | |‒ ‒ ‒ |
|
||||
+------------------------------------------------+------+------+------+------+------+------+
|
||||
|
||||
|
||||
Evaluation of designs
|
||||
'''''''''''''''''''''
|
||||
|
||||
Designs 2 and 3 have no significant advantages over design 1, while
|
||||
requiring higher polling bandwidth and greater complexity due to the need
|
||||
to create subdirectories. These designs were therefore rejected.
|
||||
|
||||
Design 4 was rejected due to the out-of-sync problem, which is severe
|
||||
and possibly unsolvable for mutable structures.
|
||||
|
||||
For design 5, the out-of-sync problem is still present but possibly
|
||||
solvable. However, design 5 is substantially more complex, less efficient
|
||||
in bandwidth/latency, and less scalable in number of clients and
|
||||
subfolders than design 1. It only gains over design 1 on the ability to
|
||||
share directory readcaps to the Magic Folder (or subfolders), which was
|
||||
not a requirement. It would be possible to implement this feature in
|
||||
future by switching to design 6.
|
||||
|
||||
For the time being, however, design 6 was considered out-of-scope for
|
||||
this project.
|
||||
|
||||
Therefore, design 1 was chosen. That is:
|
||||
|
||||
All subfolders written by a given Magic Folder client are collapsed
|
||||
into a single client DMD, containing immutable files. The child name
|
||||
of each file encodes the full subpath of that file relative to the
|
||||
Magic Folder.
|
||||
|
||||
Each directory entry in a DMD also stores a version number, so that the
|
||||
latest version of a file is well-defined when it has been modified by
|
||||
multiple clients.
|
||||
|
||||
To enable representing empty directories, a client that creates a
|
||||
directory should link a corresponding zero-length file in its DMD,
|
||||
at a name that ends with the encoded directory separator character.
|
||||
|
||||
We want to enable dynamic configuration of the membership of a Magic
|
||||
Folder collective, without having to reconfigure or restart each client
|
||||
when another client joins. To support this, we have a single collective
|
||||
directory that links to all of the client DMDs, named by their client
|
||||
nicknames. If the collective directory is mutable, then it is possible
|
||||
to change its contents in order to add clients. Note that a client DMD
|
||||
should not be unlinked from the collective directory unless all of its
|
||||
files are first copied to some other client DMD.
|
||||
|
||||
A client needs to be able to write to its own DMD, and read from other DMDs.
|
||||
To be consistent with the `Principle of Least Authority`_, each client's
|
||||
reference to its own DMD is a write capability, whereas its reference
|
||||
to the collective directory is a read capability. The latter transitively
|
||||
grants read access to all of the other client DMDs and the files linked
|
||||
from them, as required.
|
||||
|
||||
.. _`Principle of Least Authority`: http://www.eros-os.org/papers/secnotsep.pdf
|
||||
|
||||
Design and implementation of the user interface for maintaining this
|
||||
DMD structure and configuration will be addressed in Objectives 5 and 6.
|
||||
|
||||
During operation, each client will poll for changes on other clients
|
||||
at a predetermined frequency. On each poll, it will reread the collective
|
||||
directory (to allow for added or removed clients), and then read each
|
||||
client DMD linked from it.
|
||||
|
||||
"Hidden" files, and files with names matching the patterns used for backup,
|
||||
temporary, and conflicted files, will be ignored, i.e. not synchronized
|
||||
in either direction. A file is hidden if it has a filename beginning with
|
||||
"." (on any platform), or has the hidden or system attribute on Windows.
|
||||
|
||||
|
||||
Conflict Detection and Resolution
|
||||
---------------------------------
|
||||
|
||||
The combination of local filesystems and distributed objects is
|
||||
an example of shared state concurrency, which is highly error-prone
|
||||
and can result in race conditions that are complex to analyze.
|
||||
Unfortunately we have no option but to use shared state in this
|
||||
situation.
|
||||
|
||||
We call the resulting design issues "dragons" (as in "Here be dragons"),
|
||||
which as a convenient mnemonic we have named after the classical
|
||||
Greek elements Earth, Fire, Air, and Water.
|
||||
|
||||
Note: all filenames used in the following sections are examples,
|
||||
and the filename patterns we use in the actual implementation may
|
||||
differ. The actual patterns will probably include timestamps, and
|
||||
for conflicted files, the nickname of the client that last changed
|
||||
the file.
|
||||
|
||||
|
||||
Earth Dragons: Collisions between local filesystem operations and downloads
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Write/download collisions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Suppose that Alice's Magic Folder client is about to write a
|
||||
version of ``foo`` that it has downloaded in response to a remote
|
||||
change.
|
||||
|
||||
The criteria for distinguishing overwrites from conflicts are
|
||||
described later in the `Fire Dragons`_ section. Suppose that the
|
||||
remote change has been initially classified as an overwrite.
|
||||
(As we will see, it may be reclassified in some circumstances.)
|
||||
|
||||
.. _`Fire Dragons`: #fire-dragons-distinguishing-conflicts-from-overwrites
|
||||
|
||||
A *write/download collision* occurs when another program writes
|
||||
to ``foo`` in the local filesystem, concurrently with the new
|
||||
version being written by the Magic Folder client. We need to
|
||||
ensure that this does not cause data loss, as far as possible.
|
||||
|
||||
An important constraint on the design is that on Windows, it is
|
||||
not possible to rename a file to the same name as an existing
|
||||
file in that directory. Also, on Windows it may not be possible to
|
||||
delete or rename a file that has been opened by another process
|
||||
(depending on the sharing flags specified by that process).
|
||||
Therefore we need to consider carefully how to handle failure
|
||||
conditions.
|
||||
|
||||
In our proposed design, Alice's Magic Folder client follows
|
||||
this procedure for an overwrite in response to a remote change:
|
||||
|
||||
1. Write a temporary file, say ``.foo.tmp``.
|
||||
2. Use the procedure described in the `Fire Dragons_` section
|
||||
to obtain an initial classification as an overwrite or a
|
||||
conflict. (This takes as input the ``last_downloaded_uri``
|
||||
field from the directory entry of the changed ``foo``.)
|
||||
3. Set the ``mtime`` of the replacement file to be *T* seconds
|
||||
before the current local time.
|
||||
4. Perform a ''file replacement'' operation (explained below)
|
||||
with backup filename ``foo.backup``, replaced file ``foo``,
|
||||
and replacement file ``.foo.tmp``. If any step of this
|
||||
operation fails, reclassify as a conflict and stop.
|
||||
|
||||
To reclassify as a conflict, attempt to rename ``.foo.tmp`` to
|
||||
``foo.conflicted``, suppressing errors.
|
||||
|
||||
The implementation of file replacement differs between Unix
|
||||
and Windows. On Unix, it can be implemented as follows:
|
||||
|
||||
* 4a. Set the permissions of the replacement file to be the
|
||||
same as the replaced file, bitwise-or'd with octal 600
|
||||
(``rw-------``).
|
||||
* 4b. Attempt to move the replaced file (``foo``) to the
|
||||
backup filename (``foo.backup``).
|
||||
* 4c. Attempt to create a hard link at the replaced filename
|
||||
(``foo``) pointing to the replacement file (``.foo.tmp``).
|
||||
* 4d. Attempt to unlink the replacement file (``.foo.tmp``),
|
||||
suppressing errors.
|
||||
|
||||
Note that, if there is no conflict, the entry for ``foo``
|
||||
recorded in the `magic folder db`_ will reflect the ``mtime``
|
||||
set in step 3. The link operation in step 4c will cause an
|
||||
``IN_CREATE`` event for ``foo``, but this will not trigger an
|
||||
upload, because the metadata recorded in the database entry
|
||||
will exactly match the metadata for the file's inode on disk.
|
||||
(The two hard links — ``foo`` and, while it still exists,
|
||||
``.foo.tmp`` — share the same inode and therefore the same
|
||||
metadata.)
|
||||
|
||||
.. _`magic folder db`: filesystem_integration.rst#local-scanning-and-database
|
||||
|
||||
On Windows, file replacement can be implemented as a single
|
||||
call to the `ReplaceFileW`_ API (with the
|
||||
``REPLACEFILE_IGNORE_MERGE_ERRORS`` flag).
|
||||
|
||||
Similar to the Unix case, the `ReplaceFileW`_ operation will
|
||||
cause a change notification for ``foo``. The replaced ``foo``
|
||||
has the same ``mtime`` as the replacement file, and so this
|
||||
notification will not trigger an unwanted upload.
|
||||
|
||||
.. _`ReplaceFileW`: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365512%28v=vs.85%29.aspx
|
||||
|
||||
To determine whether this procedure adequately protects against data
|
||||
loss, we need to consider what happens if another process attempts to
|
||||
update ``foo``, for example by renaming ``foo.other`` to ``foo``.
|
||||
This requires us to analyze all possible interleavings between the
|
||||
operations performed by the Magic Folder client and the other process.
|
||||
(Note that atomic operations on a directory are totally ordered.)
|
||||
The set of possible interleavings differs between Windows and Unix.
|
||||
|
||||
On Unix, we have:
|
||||
|
||||
* Interleaving A: the other process' rename precedes our rename in
|
||||
step 4b, and we get an ``IN_MOVED_TO`` event for its rename by
|
||||
step 2. Then we reclassify as a conflict; its changes end up at
|
||||
``foo`` and ours end up at ``foo.conflicted``. This avoids data
|
||||
loss.
|
||||
|
||||
* Interleaving B: its rename precedes ours in step 4b, and we do
|
||||
not get an event for its rename by step 2. Its changes end up at
|
||||
``foo.backup``, and ours end up at ``foo`` after being linked there
|
||||
in step 4c. This avoids data loss.
|
||||
|
||||
* Interleaving C: its rename happens between our rename in step 4b,
|
||||
and our link operation in step 4c of the file replacement. The
|
||||
latter fails with an ``EEXIST`` error because ``foo`` already
|
||||
exists. We reclassify as a conflict; the old version ends up at
|
||||
``foo.backup``, the other process' changes end up at ``foo``, and
|
||||
ours at ``foo.conflicted``. This avoids data loss.
|
||||
|
||||
* Interleaving D: its rename happens after our link in step 4c,
|
||||
and causes an ``IN_MOVED_TO`` event for ``foo``. Its rename also
|
||||
changes the ``mtime`` for ``foo`` so that it is different from
|
||||
the ``mtime`` calculated in step 3, and therefore different
|
||||
from the metadata recorded for ``foo`` in the magic folder db.
|
||||
(Assuming no system clock changes, its rename will set an ``mtime``
|
||||
timestamp corresponding to a time after step 4c, which is not
|
||||
equal to the timestamp *T* seconds before step 4a, provided that
|
||||
*T* seconds is sufficiently greater than the timestamp granularity.)
|
||||
Therefore, an upload will be triggered for ``foo`` after its
|
||||
change, which is correct and avoids data loss.
|
||||
|
||||
On Windows, the internal implementation of `ReplaceFileW`_ is similar
|
||||
to what we have described above for Unix; it works like this:
|
||||
|
||||
* 4a′. Copy metadata (which does not include ``mtime``) from the
|
||||
replaced file (``foo``) to the replacement file (``.foo.tmp``).
|
||||
|
||||
* 4b′. Attempt to move the replaced file (``foo``) onto the
|
||||
backup filename (``foo.backup``), deleting the latter if it
|
||||
already exists.
|
||||
|
||||
* 4c′. Attempt to move the replacement file (``.foo.tmp``) to the
|
||||
replaced filename (``foo``); fail if the destination already
|
||||
exists.
|
||||
|
||||
Notice that this is essentially the same as the algorithm we use
|
||||
for Unix, but steps 4c and 4d on Unix are combined into a single
|
||||
step 4c′. (If there is a failure at steps 4c′ after step 4b′ has
|
||||
completed, the `ReplaceFileW`_ call will fail with return code
|
||||
``ERROR_UNABLE_TO_MOVE_REPLACEMENT_2``. However, it is still
|
||||
preferable to use this API over two `MoveFileExW`_ calls, because
|
||||
it retains the attributes and ACLs of ``foo`` where possible.)
|
||||
|
||||
However, on Windows the other application will not be able to
|
||||
directly rename ``foo.other`` onto ``foo`` (which would fail because
|
||||
the destination already exists); it will have to rename or delete
|
||||
``foo`` first. Without loss of generality, let's say ``foo`` is
|
||||
deleted. This complicates the interleaving analysis, because we
|
||||
have two operations done by the other process interleaving with
|
||||
three done by the magic folder process (rather than one operation
|
||||
interleaving with four as on Unix). The cases are:
|
||||
|
||||
* Interleaving A′: the other process' deletion of ``foo`` and its
|
||||
rename of ``foo.other`` to ``foo`` both precede our rename in
|
||||
step 4b. We get an event corresponding to its rename by step 2.
|
||||
Then we reclassify as a conflict; its changes end up at ``foo``
|
||||
and ours end up at ``foo.conflicted``. This avoids data loss.
|
||||
|
||||
* Interleaving B′: the other process' deletion of ``foo`` and its
|
||||
rename of ``foo.other`` to ``foo`` both precede our rename in
|
||||
step 4b. We do not get an event for its rename by step 2.
|
||||
Its changes end up at ``foo.backup``, and ours end up at ``foo``
|
||||
after being moved there in step 4c′. This avoids data loss.
|
||||
|
||||
* Interleaving C′: the other process' deletion of ``foo`` precedes
|
||||
our rename of ``foo`` to ``foo.backup`` done by `ReplaceFileW`_,
|
||||
but its rename of ``foo.other`` to ``foo`` does not, so we get
|
||||
an ``ERROR_FILE_NOT_FOUND`` error from `ReplaceFileW`_ indicating
|
||||
that the replaced file does not exist. Then we reclassify as a
|
||||
conflict; the other process' changes end up at ``foo`` (after
|
||||
it has renamed ``foo.other`` to ``foo``) and our changes end up
|
||||
at ``foo.conflicted``. This avoids data loss.
|
||||
|
||||
* Interleaving D′: the other process' deletion and/or rename happen
|
||||
during the call to `ReplaceFileW`_, causing the latter to fail.
|
||||
There are two subcases:
|
||||
|
||||
* if the error is ``ERROR_UNABLE_TO_MOVE_REPLACEMENT_2``, then
|
||||
``foo`` is renamed to ``foo.backup`` and ``.foo.tmp`` remains
|
||||
at its original name after the call.
|
||||
* for all other errors, ``foo`` and ``.foo.tmp`` both remain at
|
||||
their original names after the call.
|
||||
|
||||
In both subcases, we reclassify as a conflict and rename ``.foo.tmp``
|
||||
to ``foo.conflicted``. This avoids data loss.
|
||||
|
||||
* Interleaving E′: the other process' deletion of ``foo`` and attempt
|
||||
to rename ``foo.other`` to ``foo`` both happen after all internal
|
||||
operations of `ReplaceFileW`_ have completed. This causes deletion
|
||||
and rename events for ``foo`` (which will in practice be merged due
|
||||
to the pending delay, although we don't rely on that for correctness).
|
||||
The rename also changes the ``mtime`` for ``foo`` so that it is
|
||||
different from the ``mtime`` calculated in step 3, and therefore
|
||||
different from the metadata recorded for ``foo`` in the magic folder
|
||||
db. (Assuming no system clock changes, its rename will set an
|
||||
``mtime`` timestamp corresponding to a time after the internal
|
||||
operations of `ReplaceFileW`_ have completed, which is not equal to
|
||||
the timestamp *T* seconds before `ReplaceFileW`_ is called, provided
|
||||
that *T* seconds is sufficiently greater than the timestamp
|
||||
granularity.) Therefore, an upload will be triggered for ``foo``
|
||||
after its change, which is correct and avoids data loss.
|
||||
|
||||
.. _`MoveFileExW`: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240%28v=vs.85%29.aspx
|
||||
|
||||
We also need to consider what happens if another process opens ``foo``
|
||||
and writes to it directly, rather than renaming another file onto it:
|
||||
|
||||
* On Unix, open file handles refer to inodes, not paths. If the other
|
||||
process opens ``foo`` before it has been renamed to ``foo.backup``,
|
||||
and then closes the file, changes will have been written to the file
|
||||
at the same inode, even if that inode is now linked at ``foo.backup``.
|
||||
This avoids data loss.
|
||||
|
||||
* On Windows, we have two subcases, depending on whether the sharing
|
||||
flags specified by the other process when it opened its file handle
|
||||
included ``FILE_SHARE_DELETE``. (This flag covers both deletion and
|
||||
rename operations.)
|
||||
|
||||
i. If the sharing flags *do not* allow deletion/renaming, the
|
||||
`ReplaceFileW`_ operation will fail without renaming ``foo``.
|
||||
In this case we will end up with ``foo`` changed by the other
|
||||
process, and the downloaded file still in ``foo.tmp``.
|
||||
This avoids data loss.
|
||||
|
||||
ii. If the sharing flags *do* allow deletion/renaming, then
|
||||
data loss or corruption may occur. This is unavoidable and
|
||||
can be attributed to other process making a poor choice of
|
||||
sharing flags (either explicitly if it used `CreateFile`_, or
|
||||
via whichever higher-level API it used).
|
||||
|
||||
.. _`CreateFile`: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx
|
||||
|
||||
Note that it is possible that another process tries to open the file
|
||||
between steps 4b and 4c (or 4b′ and 4c′ on Windows). In this case the
|
||||
open will fail because ``foo`` does not exist. Nevertheless, no data
|
||||
will be lost, and in many cases the user will be able to retry the
|
||||
operation.
|
||||
|
||||
Above we only described the case where the download was initially
|
||||
classified as an overwrite. If it was classed as a conflict, the
|
||||
procedure is the same except that we choose a unique filename
|
||||
for the conflicted file (say, ``foo.conflicted_unique``). We write
|
||||
the new contents to ``.foo.tmp`` and then rename it to
|
||||
``foo.conflicted_unique`` in such a way that the rename will fail
|
||||
if the destination already exists. (On Windows this is a simple
|
||||
rename; on Unix it can be implemented as a link operation followed
|
||||
by an unlink, similar to steps 4c and 4d above.) If this fails
|
||||
because another process wrote ``foo.conflicted_unique`` after we
|
||||
chose the filename, then we retry with a different filename.
|
||||
|
||||
|
||||
Read/download collisions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A *read/download collision* occurs when another program reads
|
||||
from ``foo`` in the local filesystem, concurrently with the new
|
||||
version being written by the Magic Folder client. We want to
|
||||
ensure that any successful attempt to read the file by the other
|
||||
program obtains a consistent view of its contents.
|
||||
|
||||
On Unix, the above procedure for writing downloads is sufficient
|
||||
to achieve this. There are three cases:
|
||||
|
||||
* A. The other process opens ``foo`` for reading before it is
|
||||
renamed to ``foo.backup``. Then the file handle will continue to
|
||||
refer to the old file across the rename, and the other process
|
||||
will read the old contents.
|
||||
|
||||
* B. The other process attempts to open ``foo`` after it has been
|
||||
renamed to ``foo.backup``, and before it is linked in step c.
|
||||
The open call fails, which is acceptable.
|
||||
|
||||
* C. The other process opens ``foo`` after it has been linked to
|
||||
the new file. Then it will read the new contents.
|
||||
|
||||
On Windows, the analysis is very similar, but case A′ needs to
|
||||
be split into two subcases, depending on the sharing mode the other
|
||||
process uses when opening the file for reading:
|
||||
|
||||
* A′. The other process opens ``foo`` before the Magic Folder
|
||||
client's attempt to rename ``foo`` to ``foo.backup`` (as part
|
||||
of the implementation of `ReplaceFileW`_). The subcases are:
|
||||
|
||||
i. The other process uses sharing flags that deny deletion and
|
||||
renames. The `ReplaceFileW`_ call fails, and the download is
|
||||
reclassified as a conflict. The downloaded file ends up at
|
||||
``foo.conflicted``, which is correct.
|
||||
|
||||
ii. The other process uses sharing flags that allow deletion
|
||||
and renames. The `ReplaceFileW`_ call succeeds, and the
|
||||
other process reads inconsistent data. This can be attributed
|
||||
to a poor choice of sharing flags by the other process.
|
||||
|
||||
* B′. The other process attempts to open ``foo`` at the point
|
||||
during the `ReplaceFileW`_ call where it does not exist.
|
||||
The open call fails, which is acceptable.
|
||||
|
||||
* C′. The other process opens ``foo`` after it has been linked to
|
||||
the new file. Then it will read the new contents.
|
||||
|
||||
|
||||
For both write/download and read/download collisions, we have
|
||||
considered only interleavings with a single other process, and
|
||||
only the most common possibilities for the other process'
|
||||
interaction with the file. If multiple other processes are
|
||||
involved, or if a process performs operations other than those
|
||||
considered, then we cannot say much about the outcome in general;
|
||||
however, we believe that such cases will be much less common.
|
||||
|
||||
|
||||
|
||||
Fire Dragons: Distinguishing conflicts from overwrites
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
When synchronizing a file that has changed remotely, the Magic Folder
|
||||
client needs to distinguish between overwrites, in which the remote
|
||||
side was aware of your most recent version and overwrote it with a
|
||||
new version, and conflicts, in which the remote side was unaware of
|
||||
your most recent version when it published its new version. Those two
|
||||
cases have to be handled differently — the latter needs to be raised
|
||||
to the user as an issue the user will have to resolve and the former
|
||||
must not bother the user.
|
||||
|
||||
For example, suppose that Alice's Magic Folder client sees a change
|
||||
to ``foo`` in Bob's DMD. If the version it downloads from Bob's DMD
|
||||
is "based on" the version currently in Alice's local filesystem at
|
||||
the time Alice's client attempts to write the downloaded file, then
|
||||
it is an overwrite. Otherwise it is initially classified as a
|
||||
conflict.
|
||||
|
||||
This initial classification is used by the procedure for writing a
|
||||
file described in the `Earth Dragons`_ section above. As explained
|
||||
in that section, we may reclassify an overwrite as a conflict if an
|
||||
error occurs during the write procedure.
|
||||
|
||||
.. _`Earth Dragons`: #earth-dragons-collisions-between-local-filesystem-operations-and-downloads
|
||||
|
||||
In order to implement this policy, we need to specify how the
|
||||
"based on" relation between file versions is recorded and updated.
|
||||
|
||||
We propose to record this information:
|
||||
|
||||
* in the `magic folder db`_, for local files;
|
||||
* in the Tahoe-LAFS directory metadata, for files stored in the
|
||||
Magic Folder.
|
||||
|
||||
In the magic folder db we will add a *last-downloaded record*,
|
||||
consisting of ``last_downloaded_uri`` and ``last_downloaded_timestamp``
|
||||
fields, for each path stored in the database. Whenever a Magic Folder
|
||||
client downloads a file, it stores the downloaded version's URI and
|
||||
the current local timestamp in this record. Since only immutable
|
||||
files are used, the URI will be an immutable file URI, which is
|
||||
deterministically and uniquely derived from the file contents and
|
||||
the Tahoe-LAFS node's `convergence secret`_.
|
||||
|
||||
(Note that the last-downloaded record is updated regardless of
|
||||
whether the download is an overwrite or a conflict. The rationale
|
||||
for this to avoid "conflict loops" between clients, where every
|
||||
new version after the first conflict would be considered as another
|
||||
conflict.)
|
||||
|
||||
.. _`convergence secret`: https://tahoe-lafs.org/trac/tahoe-lafs/browser/docs/convergence-secret.rst
|
||||
|
||||
Later, in response to a local filesystem change at a given path, the
|
||||
Magic Folder client reads the last-downloaded record associated with
|
||||
that path (if any) from the database and then uploads the current
|
||||
file. When it links the uploaded file into its client DMD, it
|
||||
includes the ``last_downloaded_uri`` field in the metadata of the
|
||||
directory entry, overwriting any existing field of that name. If
|
||||
there was no last-downloaded record associated with the path, this
|
||||
field is omitted.
|
||||
|
||||
Note that ``last_downloaded_uri`` field does *not* record the URI of
|
||||
the uploaded file (which would be redundant); it records the URI of
|
||||
the last download before the local change that caused the upload.
|
||||
The field will be absent if the file has never been downloaded by
|
||||
this client (i.e. if it was created on this client and no change
|
||||
by any other client has been detected).
|
||||
|
||||
A possible refinement also takes into account the
|
||||
``last_downloaded_timestamp`` field from the magic folder db, and
|
||||
compares it to the timestamp of the change that caused the upload
|
||||
(which should be later, assuming no system clock changes).
|
||||
If the duration between these timestamps is very short, then we
|
||||
are uncertain about whether the process on Bob's system that wrote
|
||||
the local file could have taken into account the last download.
|
||||
We can use this information to be conservative about treating
|
||||
changes as conflicts. So, if the duration is less than a configured
|
||||
threshold, we omit the ``last_downloaded_uri`` field from the
|
||||
metadata. This will have the effect of making other clients treat
|
||||
this change as a conflict whenever they already have a copy of the
|
||||
file.
|
||||
|
||||
Now we are ready to describe the algorithm for determining whether a
|
||||
download for the file ``foo`` is an overwrite or a conflict (refining
|
||||
step 2 of the procedure from the `Earth Dragons`_ section).
|
||||
|
||||
Let ``last_downloaded_uri`` be the field of that name obtained from
|
||||
the directory entry metadata for ``foo`` in Bob's DMD (this field
|
||||
may be absent). Then the algorithm is:
|
||||
|
||||
* 2a. If Alice has no local copy of ``foo``, classify as an overwrite.
|
||||
|
||||
* 2b. Otherwise, "stat" ``foo`` to get its *current statinfo* (size
|
||||
in bytes, ``mtime``, and ``ctime``).
|
||||
|
||||
* 2c. Read the following information for the path ``foo`` from the
|
||||
local magic folder db:
|
||||
|
||||
* the *last-uploaded statinfo*, if any (this is the size in
|
||||
bytes, ``mtime``, and ``ctime`` stored in the ``local_files``
|
||||
table when the file was last uploaded);
|
||||
* the ``filecap`` field of the ``caps`` table for this file,
|
||||
which is the URI under which the file was last uploaded.
|
||||
Call this ``last_uploaded_uri``.
|
||||
|
||||
* 2d. If any of the following are true, then classify as a conflict:
|
||||
|
||||
* there are pending notifications of changes to ``foo``;
|
||||
* the last-uploaded statinfo is either absent, or different
|
||||
from the current statinfo;
|
||||
* either ``last_downloaded_uri`` or ``last_uploaded_uri``
|
||||
(or both) are absent, or they are different.
|
||||
|
||||
Otherwise, classify as an overwrite.
|
||||
|
||||
|
||||
Air Dragons: Collisions between local writes and uploads
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Short of filesystem-specific features on Unix or the `shadow copy service`_
|
||||
on Windows (which is per-volume and therefore difficult to use in this
|
||||
context), there is no way to *read* the whole contents of a file
|
||||
atomically. Therefore, when we read a file in order to upload it, we
|
||||
may read an inconsistent version if it was also being written locally.
|
||||
|
||||
.. _`shadow copy service`: https://technet.microsoft.com/en-us/library/ee923636%28v=ws.10%29.aspx
|
||||
|
||||
A well-behaved application can avoid this problem for its writes:
|
||||
|
||||
* On Unix, if another process modifies a file by renaming a temporary
|
||||
file onto it, then we will consistently read either the old contents
|
||||
or the new contents.
|
||||
* On Windows, if the other process uses sharing flags to deny reads
|
||||
while it is writing a file, then we will consistently read either
|
||||
the old contents or the new contents, unless a sharing error occurs.
|
||||
In the case of a sharing error we should retry later, up to a
|
||||
maximum number of retries.
|
||||
|
||||
In the case of a not-so-well-behaved application writing to a file
|
||||
at the same time we read from it, the magic folder will still be
|
||||
eventually consistent, but inconsistent versions may be visible to
|
||||
other users' clients.
|
||||
|
||||
In Objective 2 we implemented a delay, called the *pending delay*,
|
||||
after the notification of a filesystem change and before the file is
|
||||
read in order to upload it (Tahoe-LAFS ticket `#1440`_). If another
|
||||
change notification occurs within the pending delay time, the delay
|
||||
is restarted. This helps to some extent because it means that if
|
||||
files are written more quickly than the pending delay and less
|
||||
frequently than the pending delay, we shouldn't encounter this
|
||||
inconsistency.
|
||||
|
||||
.. _`#1440`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1440
|
||||
|
||||
The likelihood of inconsistency could be further reduced, even for
|
||||
writes by not-so-well-behaved applications, by delaying the actual
|
||||
upload for a further period —called the *stability delay*— after the
|
||||
file has finished being read. If a notification occurs between the
|
||||
end of the pending delay and the end of the stability delay, then
|
||||
the read would be aborted and the notification requeued.
|
||||
|
||||
This would have the effect of ensuring that no write notifications
|
||||
have been received for the file during a time window that brackets
|
||||
the period when it was being read, with margin before and after
|
||||
this period defined by the pending and stability delays. The delays
|
||||
are intended to account for asynchronous notification of events, and
|
||||
caching in the filesystem.
|
||||
|
||||
Note however that we cannot guarantee that the delays will be long
|
||||
enough to prevent inconsistency in any particular case. Also, the
|
||||
stability delay would potentially affect performance significantly
|
||||
because (unlike the pending delay) it is not overlapped when there
|
||||
are multiple files on the upload queue. This performance impact
|
||||
could be mitigated by uploading files in parallel where possible
|
||||
(Tahoe-LAFS ticket `#1459`_).
|
||||
|
||||
We have not yet decided whether to implement the stability delay, and
|
||||
it is not planned to be implemented for the OTF objective 4 milestone.
|
||||
Ticket `#2431`_ has been opened to track this idea.
|
||||
|
||||
.. _`#1459`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1459
|
||||
.. _`#2431`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2431
|
||||
|
||||
Note that the situation of both a local process and the Magic Folder
|
||||
client reading a file at the same time cannot cause any inconsistency.
|
||||
|
||||
|
||||
Water Dragons: Handling deletion and renames
|
||||
''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Deletion of a file
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When a file is deleted from the filesystem of a Magic Folder client,
|
||||
the most intuitive behavior is for it also to be deleted under that
|
||||
name from other clients. To avoid data loss, the other clients should
|
||||
actually rename their copies to a backup filename.
|
||||
|
||||
It would not be sufficient for a Magic Folder client that deletes
|
||||
a file to implement this simply by removing the directory entry from
|
||||
its DMD. Indeed, the entry may not exist in the client's DMD if it
|
||||
has never previously changed the file.
|
||||
|
||||
Instead, the client links a zero-length file into its DMD and sets
|
||||
``deleted: true`` in the directory entry metadata. Other clients
|
||||
take this as a signal to rename their copies to the backup filename.
|
||||
|
||||
Note that the entry for this zero-length file has a version number as
|
||||
usual, and later versions may restore the file.
|
||||
|
||||
When a Magic Folder client restarts, we can detect files that had
|
||||
been downloaded but were deleted while it was not running, because
|
||||
their paths will have last-downloaded records in the magic folder db
|
||||
without any corresponding local file.
|
||||
|
||||
Deletion of a directory
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Local filesystems (unlike a Tahoe-LAFS filesystem) normally cannot
|
||||
unlink a directory that has any remaining children. Therefore a
|
||||
Magic Folder client cannot delete local copies of directories in
|
||||
general, because they will typically contain backup files. This must
|
||||
be done manually on each client if desired.
|
||||
|
||||
Nevertheless, a Magic Folder client that deletes a directory should
|
||||
set ``deleted: true`` on the metadata entry for the corresponding
|
||||
zero-length file. This avoids the directory being recreated after
|
||||
it has been manually deleted from a client.
|
||||
|
||||
Renaming
|
||||
~~~~~~~~
|
||||
|
||||
It is sufficient to handle renaming of a file by treating it as a
|
||||
deletion and an addition under the new name.
|
||||
|
||||
This also applies to directories, although users may find the
|
||||
resulting behavior unintuitive: all of the files under the old name
|
||||
will be renamed to backup filenames, and a new directory structure
|
||||
created under the new name. We believe this is the best that can be
|
||||
done without imposing unreasonable implementation complexity.
|
||||
|
||||
|
||||
Summary
|
||||
-------
|
||||
|
||||
This completes the design of remote-to-local synchronization.
|
||||
We realize that it may seem very complicated. Anecdotally, proprietary
|
||||
filesystem synchronization designs we are aware of, such as Dropbox,
|
||||
are said to incur similar or greater design complexity.
|
|
@ -0,0 +1,207 @@
|
|||
Magic Folder user interface design
|
||||
==================================
|
||||
|
||||
Scope
|
||||
-----
|
||||
|
||||
In this Objective we will design a user interface to allow users to conveniently
|
||||
and securely indicate which folders on some devices should be "magically" linked
|
||||
to which folders on other devices.
|
||||
|
||||
This is a critical usability and security issue for which there is no known perfect
|
||||
solution, but which we believe is amenable to a "good enough" trade-off solution.
|
||||
This document explains the design and justifies its trade-offs in terms of security,
|
||||
usability, and time-to-market.
|
||||
|
||||
Tickets on the Tahoe-LAFS trac with the `otf-magic-folder-objective6`_
|
||||
keyword are within the scope of the user interface design.
|
||||
|
||||
.. _otf-magic-folder-objective6: https://tahoe-lafs.org/trac/tahoe-lafs/query?status=!closed&keywords=~otf-magic-folder-objective6
|
||||
|
||||
Glossary
|
||||
''''''''
|
||||
|
||||
Object: a file or directory
|
||||
|
||||
DMD: distributed mutable directory
|
||||
|
||||
Folder: an abstract directory that is synchronized between clients.
|
||||
(A folder is not the same as the directory corresponding to it on
|
||||
any particular client, nor is it the same as a DMD.)
|
||||
|
||||
Collective: the set of clients subscribed to a given Magic Folder.
|
||||
|
||||
Diminishing: the process of deriving, from an existing capability,
|
||||
another capability that gives less authority (for example, deriving a
|
||||
read cap from a read/write cap).
|
||||
|
||||
|
||||
Design Constraints
|
||||
------------------
|
||||
|
||||
The design of the Tahoe-side representation of a Magic Folder, and the polling
|
||||
mechanism that the Magic Folder clients will use to detect remote changes was
|
||||
discussed in `<remote-to-local-sync.rst>`_, and we will not revisit that here.
|
||||
The assumption made by that design was that each client would be configured with
|
||||
the following information:
|
||||
|
||||
* a write cap to its own *client DMD*.
|
||||
* a read cap to a *collective directory*.
|
||||
|
||||
The collective directory contains links to each client DMD named by the
|
||||
corresponding client's nickname.
|
||||
|
||||
This design was chosen to allow straightforward addition of clients without
|
||||
requiring each existing client to change its configuration.
|
||||
|
||||
Note that each client in a Magic Folder collective has the authority to add,
|
||||
modify or delete any object within the Magic Folder. It is also able to control
|
||||
to some extent whether its writes will be treated by another client as overwrites
|
||||
or as conflicts. However, there is still a reliability benefit to preventing a
|
||||
client from accidentally modifying another client's DMD, or from accidentally
|
||||
modifying the collective directory in a way that would lose data. This motivates
|
||||
ensuring that each client only has access to the caps above, rather than, say,
|
||||
every client having a write cap to the collective directory.
|
||||
|
||||
Another important design constraint is that we cannot violate the
|
||||
`write coordination directive`_; that is, we cannot write to the same mutable
|
||||
directory from multiple clients, even during the setup phase when adding a
|
||||
client.
|
||||
|
||||
.. _`write coordination directive`: ../../write_coordination.rst
|
||||
|
||||
Within these constraints, for usability we want to minimize the number of steps
|
||||
required to configure a Magic Folder collective.
|
||||
|
||||
|
||||
Proposed Design
|
||||
---------------
|
||||
|
||||
Three ``tahoe`` subcommands are added::
|
||||
|
||||
tahoe magic-folder create MAGIC: [MY_NICKNAME LOCAL_DIR]
|
||||
|
||||
Create an empty Magic Folder. The MAGIC: local alias is set
|
||||
to a write cap which can be used to refer to this Magic Folder
|
||||
in future ``tahoe magic-folder invite`` commands.
|
||||
|
||||
If MY_NICKNAME and LOCAL_DIR are given, the current client
|
||||
immediately joins the newly created Magic Folder with that
|
||||
nickname and local directory.
|
||||
|
||||
|
||||
tahoe magic-folder invite MAGIC: THEIR_NICKNAME
|
||||
|
||||
Print an "invitation" that can be used to invite another
|
||||
client to join a Magic Folder, with the given nickname.
|
||||
|
||||
The invitation must be sent to the user of the other client
|
||||
over a secure channel (e.g. PGP email, OTR, or ssh).
|
||||
|
||||
This command will normally be run by the same client that
|
||||
created the Magic Folder. However, it may be run by a
|
||||
different client if the ``MAGIC:`` alias is copied to
|
||||
the ``private/aliases`` file of that other client, or if
|
||||
``MAGIC:`` is replaced by the write cap to which it points.
|
||||
|
||||
|
||||
tahoe magic-folder join INVITATION LOCAL_DIR
|
||||
|
||||
Accept an invitation created by ``tahoe magic-folder invite``.
|
||||
The current client joins the specified Magic Folder, which will
|
||||
appear in the local filesystem at the given directory.
|
||||
|
||||
|
||||
There are no commands to remove a client or to revoke an
|
||||
invitation, although those are possible features that could
|
||||
be added in future. (When removing a client, it is necessary
|
||||
to copy each file it added to some other client's DMD, if it
|
||||
is the most recent version of that file.)
|
||||
|
||||
|
||||
Implementation
|
||||
''''''''''''''
|
||||
|
||||
For "``tahoe magic-folder create MAGIC: [MY_NICKNAME LOCAL_DIR]``" :
|
||||
|
||||
1. Run "``tahoe create-alias MAGIC:``".
|
||||
2. If ``MY_NICKNAME`` and ``LOCAL_DIR`` are given, do the equivalent of::
|
||||
|
||||
INVITATION=`tahoe invite-magic-folder MAGIC: MY_NICKNAME`
|
||||
tahoe join-magic-folder INVITATION LOCAL_DIR
|
||||
|
||||
|
||||
For "``tahoe magic-folder invite COLLECTIVE_WRITECAP NICKNAME``" :
|
||||
|
||||
(``COLLECTIVE_WRITECAP`` can, as a special case, be an alias such as ``MAGIC:``.)
|
||||
|
||||
1. Create an empty client DMD. Let its write URI be ``CLIENT_WRITECAP``.
|
||||
2. Diminish ``CLIENT_WRITECAP`` to ``CLIENT_READCAP``, and
|
||||
diminish ``COLLECTIVE_WRITECAP`` to ``COLLECTIVE_READCAP``.
|
||||
3. Run "``tahoe ln CLIENT_READCAP COLLECTIVE_WRITECAP/NICKNAME``".
|
||||
4. Print "``COLLECTIVE_READCAP+CLIENT_WRITECAP``" as the invitation,
|
||||
accompanied by instructions on how to accept the invitation and
|
||||
the need to send it over a secure channel.
|
||||
|
||||
|
||||
For "``tahoe magic-folder join INVITATION LOCAL_DIR``" :
|
||||
|
||||
1. Parse ``INVITATION`` as ``COLLECTIVE_READCAP+CLIENT_WRITECAP``.
|
||||
2. Write ``CLIENT_WRITECAP`` to the file ``magic_folder_dircap``
|
||||
under the client's ``private`` directory.
|
||||
3. Write ``COLLECTIVE_READCAP`` to the file ``collective_dircap``
|
||||
under the client's ``private`` directory.
|
||||
4. Edit the client's ``tahoe.cfg`` to set
|
||||
``[magic_folder] enabled = True`` and
|
||||
``[magic_folder] local.directory = LOCAL_DIR``.
|
||||
|
||||
|
||||
Discussion
|
||||
----------
|
||||
|
||||
The proposed design has a minor violation of the
|
||||
`Principle of Least Authority`_ in order to reduce the number
|
||||
of steps needed. The invoker of "``tahoe magic-folder invite``"
|
||||
creates the client DMD on behalf of the invited client, and
|
||||
could retain its write cap (which is part of the invitation).
|
||||
|
||||
.. _`Principle of Least Authority`: http://www.eros-os.org/papers/secnotsep.pdf
|
||||
|
||||
A possible alternative design would be for the invited client
|
||||
to create its own client DMD, and send it back to the inviter
|
||||
to be linked into the collective directory. However this would
|
||||
require another secure communication and another command
|
||||
invocation per client. Given that, as mentioned earlier, each
|
||||
client in a Magic Folder collective already has the authority
|
||||
to add, modify or delete any object within the Magic Folder,
|
||||
we considered the potential security/reliability improvement
|
||||
here not to be worth the loss of usability.
|
||||
|
||||
We also considered a design where each client had write access
|
||||
to the collective directory. This would arguably be a more
|
||||
serious violation of the Principle of Least Authority than the
|
||||
one above (because all clients would have excess authority rather
|
||||
than just the inviter). In any case, it was not clear how to make
|
||||
such a design satisfy the `write coordination directive`_,
|
||||
because the collective directory would have needed to be written
|
||||
to by multiple clients.
|
||||
|
||||
The reliance on a secure channel to send the invitation to its
|
||||
intended recipient is not ideal, since it may involve additional
|
||||
software such as clients for PGP, OTR, ssh etc. However, we believe
|
||||
that this complexity is necessary rather than incidental, because
|
||||
there must be some way to distinguish the intended recipient from
|
||||
potential attackers who would try to become members of the Magic
|
||||
Folder collective without authorization. By making use of existing
|
||||
channels that have likely already been set up by security-conscious
|
||||
users, we avoid reinventing the wheel or imposing substantial extra
|
||||
implementation costs.
|
||||
|
||||
The length of an invitation will be approximately the combined
|
||||
length of a Tahoe-LAFS read cap and write cap. This is several
|
||||
lines long, but still short enough to be cut-and-pasted successfully
|
||||
if care is taken. Errors in copying the invitation can be detected
|
||||
since Tahoe-LAFS cap URIs are self-authenticating.
|
||||
|
||||
The implementation of the ``tahoe`` subcommands is straightforward
|
||||
and raises no further difficult design issues.
|
|
@ -0,0 +1,76 @@
|
|||
.. -*- coding: utf-8-with-signature-unix; fill-column: 77 -*-
|
||||
|
||||
==================
|
||||
Getting Tahoe-LAFS
|
||||
==================
|
||||
|
||||
Welcome to `the Tahoe-LAFS project`_, a secure, decentralized, fault-tolerant
|
||||
storage system.
|
||||
|
||||
`about Tahoe-LAFS <about.rst>`__
|
||||
|
||||
.. _the Tahoe-LAFS project: https://tahoe-lafs.org
|
||||
|
||||
How To Get Tahoe-LAFS
|
||||
=====================
|
||||
|
||||
This procedure has been verified to work on Windows, Mac, OpenSolaris, and
|
||||
too many flavors of Linux and of BSD to list.
|
||||
|
||||
In Case Of Trouble
|
||||
------------------
|
||||
|
||||
There are a few 3rd party libraries that Tahoe-LAFS depends on that might not
|
||||
be easy to set up on your platform. If the following instructions don't Just
|
||||
Work without any further effort on your part, then please write to `the
|
||||
tahoe-dev mailing list`_ where friendly hackers will help you out.
|
||||
|
||||
.. _the tahoe-dev mailing list: https://tahoe-lafs.org/cgi-bin/mailman/listinfo/tahoe-dev
|
||||
|
||||
Install Python
|
||||
--------------
|
||||
|
||||
Check if you already have an adequate version of Python installed by running
|
||||
``python -V``. Python v2.6 (v2.6.6 or greater recommended) or Python v2.7
|
||||
will work. Python v3 does not work. On Windows, we recommend the use of
|
||||
native Python v2.7, not Cygwin Python. If you don't have one of these
|
||||
versions of Python installed, `download`_ and install the latest version of
|
||||
Python v2.7. Make sure that the path to the installation directory has no
|
||||
spaces in it (e.g. on Windows, do not install Python in the "Program Files"
|
||||
directory).
|
||||
|
||||
.. _download: https://www.python.org/downloads/
|
||||
|
||||
Get Tahoe-LAFS
|
||||
--------------
|
||||
|
||||
Download the latest stable release, `Tahoe-LAFS v1.10.1`_.
|
||||
|
||||
.. _Tahoe-LAFS v1.10.1: https://tahoe-lafs.org/source/tahoe-lafs/releases/allmydata-tahoe-1.10.1.zip
|
||||
|
||||
Set Up Tahoe-LAFS
|
||||
-----------------
|
||||
|
||||
Unpack the zip file and cd into the top-level directory.
|
||||
|
||||
Run "``python setup.py build``" to generate the ``tahoe`` executable in a
|
||||
subdirectory of the current directory named ``bin``. This will download and
|
||||
build anything you need from various websites.
|
||||
|
||||
On Windows, the ``build`` step might tell you to open a new Command Prompt
|
||||
(or, on XP and earlier, to log out and back in again). This is needed the
|
||||
first time you set up Tahoe-LAFS on a particular installation of Windows.
|
||||
|
||||
Run "``bin/tahoe --version``" (on Windows, "``bin\tahoe --version``") to
|
||||
verify that the executable tool prints out the right version number after
|
||||
"``allmydata-tahoe:``".
|
||||
|
||||
Optionally run "``python setup.py trial``" to verify that it passes all of
|
||||
its self-tests.
|
||||
|
||||
Run Tahoe-LAFS
|
||||
--------------
|
||||
|
||||
Now you are ready to deploy a decentralized filesystem. The ``tahoe``
|
||||
executable in the ``bin`` directory can configure and launch your Tahoe-LAFS
|
||||
nodes. See `<running.rst>`__ for instructions on how to do that.
|
|
@ -1,266 +0,0 @@
|
|||
|
||||
=================
|
||||
Release Checklist
|
||||
=================
|
||||
|
||||
This release checklist specifies a series of checks that anyone engaged in
|
||||
releasing a version of Tahoe should follow.
|
||||
|
||||
Any contributor can do the first part of the release preparation. Only
|
||||
certain contributors can perform other parts. These are the two main
|
||||
sections of this checklist (and could be done by different people).
|
||||
|
||||
A final section describes how to announce the release.
|
||||
|
||||
This checklist is based on the original instructions (in old revisions in the file
|
||||
`docs/how_to_make_a_tahoe-lafs_release.org`).
|
||||
|
||||
|
||||
Any Contributor
|
||||
===============
|
||||
|
||||
Anyone who can create normal PRs should be able to complete this
|
||||
portion of the release process.
|
||||
|
||||
|
||||
Prepare for the Release
|
||||
```````````````````````
|
||||
|
||||
The `master` branch should always be releasable.
|
||||
|
||||
It may be worth asking (on IRC or mailing-ist) if anything will be
|
||||
merged imminently (for example, "I will prepare a release this coming
|
||||
Tuesday if you want to get anything in").
|
||||
|
||||
- Create a ticket for the release in Trac
|
||||
- Ticket number needed in next section
|
||||
- Making first release? See `GPG Setup Instructions <gpg-setup.rst>`__ to make sure you can sign releases. [One time setup]
|
||||
|
||||
Get a clean checkout
|
||||
````````````````````
|
||||
|
||||
The release proccess involves compressing source files and putting them in formats
|
||||
suitable for distribution such as ``.tar.gz`` and ``zip``. That said, it's neccesary to
|
||||
the release process begins with a clean checkout to avoid making a release with
|
||||
previously generated files.
|
||||
|
||||
- Inside the tahoe root dir run ``git clone . ../tahoe-release-x.x.x`` where (x.x.x is the release number such as 1.16.0).
|
||||
|
||||
.. note::
|
||||
The above command would create a new directory at the same level as your original clone named ``tahoe-release-x.x.x``. You can name this folder however you want but it would be a good
|
||||
practice to give it the release name. You MAY also discard this directory once the release
|
||||
process is complete.
|
||||
|
||||
Get into the release directory and install dependencies by running
|
||||
|
||||
- cd ../tahoe-release-x.x.x (assuming you are still in your original clone)
|
||||
- python -m venv venv
|
||||
- ./venv/bin/pip install --editable .[test]
|
||||
|
||||
|
||||
Create Branch and Apply Updates
|
||||
```````````````````````````````
|
||||
|
||||
- Create a branch for the release/candidate (e.g. ``XXXX.release-1.16.0``)
|
||||
- run tox -e news to produce a new NEWS.txt file (this does a commit)
|
||||
- create the news for the release
|
||||
|
||||
- newsfragments/<ticket number>.minor
|
||||
- commit it
|
||||
|
||||
- manually fix NEWS.txt
|
||||
|
||||
- proper title for latest release ("Release 1.16.0" instead of "Release ...post1432")
|
||||
- double-check date (maybe release will be in the future)
|
||||
- spot-check the release notes (these come from the newsfragments
|
||||
files though so don't do heavy editing)
|
||||
- commit these changes
|
||||
|
||||
- update "relnotes.txt"
|
||||
|
||||
- update all mentions of ``1.16.0`` to new and higher release version for example ``1.16.1``
|
||||
- update "previous release" statement and date
|
||||
- summarize major changes
|
||||
- commit it
|
||||
|
||||
- update "nix/tahoe-lafs.nix"
|
||||
|
||||
- change the value given for `version` from `OLD.post1` to `NEW.post1`
|
||||
|
||||
- update "docs/known_issues.rst" if appropriate
|
||||
- Push the branch to github
|
||||
- Create a (draft) PR; this should trigger CI (note that github
|
||||
doesn't let you create a PR without some changes on the branch so
|
||||
running + committing the NEWS.txt file achieves that without changing
|
||||
any code)
|
||||
- Confirm CI runs successfully on all platforms
|
||||
|
||||
|
||||
Create Release Candidate
|
||||
````````````````````````
|
||||
|
||||
Before "officially" tagging any release, we will make a
|
||||
release-candidate available. So there will be at least 1.15.0rc0 (for
|
||||
example). If there are any problems, an rc1 or rc2 etc may also be
|
||||
released. Anyone can sign these releases (ideally they'd be signed
|
||||
"officially" as well, but it's better to get them out than to wait for
|
||||
that).
|
||||
|
||||
Typically expert users will be the ones testing release candidates and
|
||||
they will need to evaluate which contributors' signatures they trust.
|
||||
|
||||
- (all steps above are completed)
|
||||
- sign the release
|
||||
|
||||
- git tag -s -u 0xE34E62D06D0E69CFCA4179FFBDE0D31D68666A7A -m "release Tahoe-LAFS-1.16.0rc0" tahoe-lafs-1.16.0rc0
|
||||
|
||||
.. note::
|
||||
- Replace the key-id above with your own, which can simply be your email if it's attached to your fingerprint.
|
||||
- Don't forget to put the correct tag message and name. In this example, the tag message is "release Tahoe-LAFS-1.16.0rc0" and the tag name is ``tahoe-lafs-1.16.0rc0``
|
||||
|
||||
- build all code locally
|
||||
|
||||
- these should all pass:
|
||||
|
||||
- tox -e py37,codechecks,docs,integration
|
||||
|
||||
- these can fail (ideally they should not of course):
|
||||
|
||||
- tox -e deprecations,upcoming-deprecations
|
||||
|
||||
- clone to a clean, local checkout (to avoid extra files being included in the release)
|
||||
|
||||
- cd /tmp
|
||||
- git clone /home/meejah/src/tahoe-lafs
|
||||
|
||||
- build tarballs
|
||||
|
||||
- tox -e tarballs
|
||||
- Confirm that release tarballs exist by runnig:
|
||||
|
||||
- ls dist/ | grep 1.16.0rc0
|
||||
|
||||
- inspect and test the tarballs
|
||||
|
||||
- install each in a fresh virtualenv
|
||||
- run `tahoe` command
|
||||
|
||||
- when satisfied, sign the tarballs:
|
||||
|
||||
- gpg --pinentry=loopback --armor -u 0xE34E62D06D0E69CFCA4179FFBDE0D31D68666A7A --detach-sign dist/tahoe_lafs-1.16.0rc0-py2.py3-none-any.whl
|
||||
- gpg --pinentry=loopback --armor --detach-sign dist/tahoe_lafs-1.16.0rc0.tar.gz
|
||||
|
||||
|
||||
Privileged Contributor
|
||||
======================
|
||||
|
||||
Steps in this portion require special access to keys or
|
||||
infrastructure. For example, **access to tahoe-lafs.org** to upload
|
||||
binaries or edit HTML.
|
||||
|
||||
|
||||
Hack Tahoe-LAFS
|
||||
```````````````
|
||||
|
||||
Did anyone contribute a hack since the last release? If so, then
|
||||
https://tahoe-lafs.org/hacktahoelafs/ needs to be updated.
|
||||
|
||||
|
||||
Sign Git Tag
|
||||
````````````
|
||||
|
||||
- git tag -s -u 0xE34E62D06D0E69CFCA4179FFBDE0D31D68666A7A -m "release Tahoe-LAFS-X.Y.Z" tahoe-lafs-X.Y.Z
|
||||
|
||||
|
||||
Upload Artifacts
|
||||
````````````````
|
||||
|
||||
Any release-candidate or actual release plus signature (.asc file)
|
||||
need to be uploaded to https://tahoe-lafs.org in `~source/downloads`
|
||||
|
||||
- secure-copy all release artifacts to the download area on the
|
||||
tahoe-lafs.org host machine. `~source/downloads` on there maps to
|
||||
https://tahoe-lafs.org/downloads/ on the Web:
|
||||
|
||||
- scp dist/*1.15.0* username@tahoe-lafs.org:/home/source/downloads
|
||||
|
||||
- the following developers have access to do this:
|
||||
|
||||
- exarkun
|
||||
- meejah
|
||||
- warner
|
||||
|
||||
Push the signed tag to the main repository:
|
||||
|
||||
- git push origin tahoe-lafs-1.17.1
|
||||
|
||||
For the actual release, the tarball and signature files need to be
|
||||
uploaded to PyPI as well.
|
||||
|
||||
- ls dist/*1.19.0*
|
||||
- twine upload --username __token__ --password `cat SECRET-pypi-tahoe-publish-token` dist/*1.19.0*
|
||||
|
||||
The following developers have access to do this:
|
||||
|
||||
- warner
|
||||
- meejah
|
||||
- exarkun (partial?)
|
||||
|
||||
|
||||
Announcing the Release Candidate
|
||||
````````````````````````````````
|
||||
|
||||
The release-candidate should be announced by posting to the
|
||||
mailing-list (tahoe-dev@lists.tahoe-lafs.org). For example:
|
||||
https://lists.tahoe-lafs.org/pipermail/tahoe-dev/2020-October/009978.html
|
||||
|
||||
|
||||
Is The Release Done Yet?
|
||||
````````````````````````
|
||||
|
||||
If anyone reports a problem with a release-candidate then a new
|
||||
release-candidate should be made once a fix has been merged to
|
||||
master. Repeat the above instructions with `rc1` or `rc2` or whatever
|
||||
is appropriate.
|
||||
|
||||
Once a release-candidate has marinated for some time then it can be
|
||||
made into a the actual release.
|
||||
|
||||
The actual release follows the same steps as above, with some differences:
|
||||
|
||||
- there is no "-rcX" on the end of release names
|
||||
- the release is uploaded to PyPI (using Twine)
|
||||
- the version is tagged in Git (ideally using "the tahoe release key"
|
||||
but can be done with any of the authorized core developers' personal
|
||||
key)
|
||||
- the release-candidate branches must be merged back to master after
|
||||
the release is official (e.g. causing newsfragments to be deleted on
|
||||
master, etc)
|
||||
|
||||
|
||||
Announcing the Release
|
||||
----------------------
|
||||
|
||||
|
||||
mailing-lists
|
||||
`````````````
|
||||
|
||||
A new Tahoe release is traditionally announced on our mailing-list
|
||||
(tahoe-dev@tahoe-lafs.org). The former version of these instructions
|
||||
also announced the release on the following other lists:
|
||||
|
||||
- tahoe-announce@tahoe-lafs.org
|
||||
- twisted-python@twistedmatrix.com
|
||||
- liberationtech@lists.stanford.edu
|
||||
- lwn@lwn.net
|
||||
- p2p-hackers@lists.zooko.com
|
||||
- python-list@python.org
|
||||
- http://listcultures.org/pipermail/p2presearch_listcultures.org/
|
||||
- cryptopp-users@googlegroups.com
|
||||
|
||||
|
||||
wiki
|
||||
````
|
||||
|
||||
Edit the "News" section of the front page of https://tahoe-lafs.org
|
||||
with a link to the mailing-list archive of the announcement message.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue