mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-19 21:12:35 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e5e8db431 | ||
|
|
acd7f1a4d5 | ||
|
|
eb6a56b6c6 |
@@ -38,13 +38,13 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
|
||||
- name: Set BUILD_TIME env
|
||||
run: echo BUILD_TIME=$(date -u +%Y%m%d-%H%M) >> ${GITHUB_ENV}
|
||||
|
||||
- name: Go Release Binaries Large Disk
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
asset_name: "weed-large-disk-${{ env.BUILD_TIME }}-${{ matrix.goos }}-${{ matrix.goarch }}"
|
||||
|
||||
- name: Go Release Binaries Normal Volume Size
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
@@ -87,13 +87,13 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
|
||||
- name: Set BUILD_TIME env
|
||||
run: echo BUILD_TIME=$(date -u +%Y%m%d-%H%M) >> ${GITHUB_ENV}
|
||||
|
||||
- name: Go Release Binaries Large Disk
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
asset_name: "weed-large-disk-${{ env.BUILD_TIME }}-${{ matrix.goos }}-${{ matrix.goarch }}"
|
||||
|
||||
- name: Go Release Binaries Normal Volume Size
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
|
||||
@@ -28,9 +28,9 @@ jobs:
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
- name: Go Release Binaries Normal Volume Size
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
binary_name: weed
|
||||
asset_name: "${{ matrix.goos }}_${{ matrix.goarch }}"
|
||||
- name: Go Release Large Disk Binaries
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
|
||||
@@ -28,9 +28,9 @@ jobs:
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
- name: Go Release Binaries Normal Volume Size
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
binary_name: weed
|
||||
asset_name: "${{ matrix.goos }}_${{ matrix.goarch }}"
|
||||
- name: Go Release Large Disk Binaries
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
|
||||
@@ -28,9 +28,9 @@ jobs:
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
- name: Go Release Binaries Normal Volume Size
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
binary_name: weed
|
||||
asset_name: "${{ matrix.goos }}_${{ matrix.goarch }}"
|
||||
- name: Go Release Large Disk Binaries
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
|
||||
@@ -28,9 +28,9 @@ jobs:
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
- name: Go Release Binaries Normal Volume Size
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
binary_name: weed
|
||||
asset_name: "${{ matrix.goos }}_${{ matrix.goarch }}"
|
||||
- name: Go Release Large Disk Binaries
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
|
||||
@@ -28,9 +28,9 @@ jobs:
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
- name: Go Release Binaries Normal Volume Size
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
binary_name: weed
|
||||
asset_name: "${{ matrix.goos }}_${{ matrix.goarch }}_full"
|
||||
- name: Go Release Large Disk Binaries
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
|
||||
@@ -28,9 +28,9 @@ jobs:
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
- name: Go Release Binaries Normal Volume Size
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
binary_name: weed
|
||||
asset_name: "${{ matrix.goos }}_${{ matrix.goarch }}"
|
||||
- name: Go Release Large Disk Binaries
|
||||
uses: wangyoucao577/go-release-action@ec4e3151b3eccfa3527868ba70f60402265fef06 # v1.22
|
||||
uses: wangyoucao577/go-release-action@481a2c1a0f1be199722e3e9b74d7199acafc30a8 # v1.22
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
-
|
||||
name: Docker meta
|
||||
id: docker_meta
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
|
||||
- name: Prepare Docker tag
|
||||
id: tag
|
||||
|
||||
@@ -9,6 +9,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build weed binary
|
||||
run: |
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
- name: Archive logs
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ec-integration-test-logs
|
||||
path: test/erasure_coding
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v2
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v2
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
|
||||
- name: Publish Helm charts
|
||||
uses: stefanprodan/helm-gh-pages@v1.7.0
|
||||
with:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
-master.raftHashicorp -master.electionTimeout 1s -master.volumeSizeLimitMB=100 \
|
||||
-volume.max=100 -volume.preStopSeconds=1 \
|
||||
-master.port=9333 -volume.port=8080 -filer.port=8888 -s3.port=8000 -metricsPort=9324 \
|
||||
-s3.allowDeleteBucketNotEmpty=true -s3.config="$GITHUB_WORKSPACE/docker/compose/s3.json" -master.peers=none &
|
||||
-s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=true -s3.config="$GITHUB_WORKSPACE/docker/compose/s3.json" -master.peers=none &
|
||||
pid=$!
|
||||
|
||||
# Wait for all SeaweedFS components to be ready
|
||||
@@ -368,7 +368,7 @@ jobs:
|
||||
-master.raftHashicorp -master.electionTimeout 1s -master.volumeSizeLimitMB=100 \
|
||||
-volume.max=100 -volume.preStopSeconds=1 \
|
||||
-master.port=9334 -volume.port=8081 -filer.port=8889 -s3.port=8001 -metricsPort=9325 \
|
||||
-s3.allowDeleteBucketNotEmpty=true -s3.config="$GITHUB_WORKSPACE/docker/compose/s3.json" -master.peers=none &
|
||||
-s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=true -s3.config="$GITHUB_WORKSPACE/docker/compose/s3.json" -master.peers=none &
|
||||
pid=$!
|
||||
|
||||
# Wait for all SeaweedFS components to be ready
|
||||
@@ -526,7 +526,7 @@ jobs:
|
||||
-master.raftHashicorp -master.electionTimeout 1s -master.volumeSizeLimitMB=100 \
|
||||
-volume.max=100 -volume.preStopSeconds=1 \
|
||||
-master.port=9335 -volume.port=8082 -filer.port=8890 -s3.port=8002 -metricsPort=9326 \
|
||||
-s3.allowDeleteBucketNotEmpty=true -s3.config="$GITHUB_WORKSPACE/docker/compose/s3.json" -master.peers=none &
|
||||
-s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=true -s3.config="$GITHUB_WORKSPACE/docker/compose/s3.json" -master.peers=none &
|
||||
pid=$!
|
||||
|
||||
# Wait for all SeaweedFS components to be ready
|
||||
@@ -636,7 +636,7 @@ jobs:
|
||||
-master.raftHashicorp -master.electionTimeout 1s -master.volumeSizeLimitMB=100 \
|
||||
-volume.max=100 -volume.preStopSeconds=1 \
|
||||
-master.port=9336 -volume.port=8083 -filer.port=8891 -s3.port=8003 -metricsPort=9327 \
|
||||
-s3.allowDeleteBucketNotEmpty=true -s3.config="$GITHUB_WORKSPACE/docker/compose/s3.json" -master.peers=none &
|
||||
-s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=true -s3.config="$GITHUB_WORKSPACE/docker/compose/s3.json" -master.peers=none &
|
||||
pid=$!
|
||||
|
||||
# Wait for all SeaweedFS components to be ready
|
||||
@@ -817,7 +817,7 @@ jobs:
|
||||
-master.raftHashicorp -master.electionTimeout 1s -master.volumeSizeLimitMB=100 \
|
||||
-volume.max=100 -volume.preStopSeconds=1 \
|
||||
-master.port=9337 -volume.port=8085 -filer.port=8892 -s3.port=8004 -metricsPort=9328 \
|
||||
-s3.allowDeleteBucketNotEmpty=true -s3.config="$GITHUB_WORKSPACE/docker/compose/s3.json" \
|
||||
-s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=true -s3.config="$GITHUB_WORKSPACE/docker/compose/s3.json" \
|
||||
-master.peers=none \
|
||||
> /tmp/seaweedfs-sql-server.log 2>&1 &
|
||||
pid=$!
|
||||
|
||||
@@ -35,10 +35,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ full_install: admin-generate
|
||||
cd weed; go install -tags "elastic gocdk sqlite ydb tarantool tikv rclone"
|
||||
|
||||
server: install
|
||||
weed -v 0 server -s3 -filer -filer.maxMB=64 -volume.max=0 -master.volumeSizeLimitMB=100 -volume.preStopSeconds=1 -s3.port=8000 -s3.allowDeleteBucketNotEmpty=true -s3.config=./docker/compose/s3.json -metricsPort=9324
|
||||
weed -v 0 server -s3 -filer -filer.maxMB=64 -volume.max=0 -master.volumeSizeLimitMB=100 -volume.preStopSeconds=1 -s3.port=8000 -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=true -s3.config=./docker/compose/s3.json -metricsPort=9324
|
||||
|
||||
benchmark: install warp_install
|
||||
pkill weed || true
|
||||
pkill warp || true
|
||||
weed server -debug=$(debug) -s3 -filer -volume.max=0 -master.volumeSizeLimitMB=100 -volume.preStopSeconds=1 -s3.port=8000 -s3.allowDeleteBucketNotEmpty=false -s3.config=./docker/compose/s3.json &
|
||||
weed server -debug=$(debug) -s3 -filer -volume.max=0 -master.volumeSizeLimitMB=100 -volume.preStopSeconds=1 -s3.port=8000 -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=false -s3.config=./docker/compose/s3.json &
|
||||
warp client &
|
||||
while ! nc -z localhost 8000 ; do sleep 1 ; done
|
||||
warp mixed --host=127.0.0.1:8000 --access-key=some_access_key1 --secret-key=some_secret_key1 --autoterm
|
||||
|
||||
@@ -87,7 +87,7 @@ Table of Contents
|
||||
* `export AWS_ACCESS_KEY_ID=admin ; export AWS_SECRET_ACCESS_KEY=key` as the admin credentials to access the object store.
|
||||
* Run `weed server -dir=/some/data/dir -s3` to start one master, one volume server, one filer, and one S3 gateway.
|
||||
|
||||
Also, to increase capacity, just add more volume servers by running `weed volume -dir="/some/data/dir2" -master="<master_host>:9333" -port=8081` locally, or on a different machine, or on thousands of machines. That is it!
|
||||
Also, to increase capacity, just add more volume servers by running `weed volume -dir="/some/data/dir2" -mserver="<master_host>:9333" -port=8081` locally, or on a different machine, or on thousands of machines. That is it!
|
||||
|
||||
## Quick Start SeaweedFS S3 on AWS ##
|
||||
* Setup fast production-ready [SeaweedFS S3 on AWS with cloudformation](https://aws.amazon.com/marketplace/pp/prodview-nzelz5gprlrjc)
|
||||
@@ -206,8 +206,8 @@ SeaweedFS uses HTTP REST operations to read, write, and delete. The responses ar
|
||||
### Start Volume Servers ###
|
||||
|
||||
```
|
||||
> weed volume -dir="/tmp/data1" -max=5 -master="localhost:9333" -port=8080 &
|
||||
> weed volume -dir="/tmp/data2" -max=10 -master="localhost:9333" -port=8081 &
|
||||
> weed volume -dir="/tmp/data1" -max=5 -mserver="localhost:9333" -port=8080 &
|
||||
> weed volume -dir="/tmp/data2" -max=10 -mserver="localhost:9333" -port=8081 &
|
||||
```
|
||||
|
||||
### Write File ###
|
||||
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "18080:18080"
|
||||
command: "volume -master=master:9333 -ip=volume1 -dir=/data -max=10"
|
||||
command: "volume -mserver=master:9333 -ip=volume1 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
@@ -38,7 +38,7 @@ services:
|
||||
ports:
|
||||
- "8081:8080"
|
||||
- "18081:18080"
|
||||
command: "volume -master=master:9333 -ip=volume2 -dir=/data -max=10"
|
||||
command: "volume -mserver=master:9333 -ip=volume2 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
@@ -51,7 +51,7 @@ services:
|
||||
ports:
|
||||
- "8082:8080"
|
||||
- "18082:18080"
|
||||
command: "volume -master=master:9333 -ip=volume3 -dir=/data -max=10"
|
||||
command: "volume -mserver=master:9333 -ip=volume3 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
@@ -64,7 +64,7 @@ services:
|
||||
ports:
|
||||
- "8083:8080"
|
||||
- "18083:18080"
|
||||
command: "volume -master=master:9333 -ip=volume4 -dir=/data -max=10"
|
||||
command: "volume -mserver=master:9333 -ip=volume4 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
@@ -77,7 +77,7 @@ services:
|
||||
ports:
|
||||
- "8084:8080"
|
||||
- "18084:18080"
|
||||
command: "volume -master=master:9333 -ip=volume5 -dir=/data -max=10"
|
||||
command: "volume -mserver=master:9333 -ip=volume5 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
@@ -90,7 +90,7 @@ services:
|
||||
ports:
|
||||
- "8085:8080"
|
||||
- "18085:18080"
|
||||
command: "volume -master=master:9333 -ip=volume6 -dir=/data -max=10"
|
||||
command: "volume -mserver=master:9333 -ip=volume6 -dir=/data -max=10"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
|
||||
@@ -13,7 +13,7 @@ services:
|
||||
|
||||
volume:
|
||||
image: chrislusf/seaweedfs:e2e
|
||||
command: "-v=4 volume -master=master:9333 -ip=volume -ip.bind=0.0.0.0 -preStopSeconds=1"
|
||||
command: "-v=4 volume -mserver=master:9333 -ip=volume -ip.bind=0.0.0.0 -preStopSeconds=1"
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "-I", "http://localhost:8080/healthz" ]
|
||||
interval: 2s
|
||||
|
||||
@@ -36,7 +36,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: 'volume -dataCenter=dc1 -rack=v1 -master="master0:9333,master1:9334,master2:9335" -port=8080 -ip=volume1 -publicUrl=localhost:8080 -preStopSeconds=1'
|
||||
command: 'volume -dataCenter=dc1 -rack=v1 -mserver="master0:9333,master1:9334,master2:9335" -port=8080 -ip=volume1 -publicUrl=localhost:8080 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
@@ -46,7 +46,7 @@ services:
|
||||
ports:
|
||||
- 8082:8082
|
||||
- 18082:18082
|
||||
command: 'volume -dataCenter=dc2 -rack=v2 -master="master0:9333,master1:9334,master2:9335" -port=8082 -ip=volume2 -publicUrl=localhost:8082 -preStopSeconds=1'
|
||||
command: 'volume -dataCenter=dc2 -rack=v2 -mserver="master0:9333,master1:9334,master2:9335" -port=8082 -ip=volume2 -publicUrl=localhost:8082 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
ports:
|
||||
- 8083:8083
|
||||
- 18083:18083
|
||||
command: 'volume -dataCenter=dc3 -rack=v3 -master="master0:9333,master1:9334,master2:9335" -port=8083 -ip=volume3 -publicUrl=localhost:8083 -preStopSeconds=1'
|
||||
command: 'volume -dataCenter=dc3 -rack=v3 -mserver="master0:9333,master1:9334,master2:9335" -port=8083 -ip=volume3 -publicUrl=localhost:8083 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
|
||||
@@ -36,7 +36,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: 'volume -dataCenter=dc1 -rack=v1 -master="master0:9333,master1:9334,master2:9335" -port=8080 -ip=volume1 -publicUrl=localhost:8080 -preStopSeconds=1'
|
||||
command: 'volume -dataCenter=dc1 -rack=v1 -mserver="master0:9333,master1:9334,master2:9335" -port=8080 -ip=volume1 -publicUrl=localhost:8080 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
@@ -46,7 +46,7 @@ services:
|
||||
ports:
|
||||
- 8082:8082
|
||||
- 18082:18082
|
||||
command: 'volume -dataCenter=dc2 -rack=v2 -master="master0:9333,master1:9334,master2:9335" -port=8082 -ip=volume2 -publicUrl=localhost:8082 -preStopSeconds=1'
|
||||
command: 'volume -dataCenter=dc2 -rack=v2 -mserver="master0:9333,master1:9334,master2:9335" -port=8082 -ip=volume2 -publicUrl=localhost:8082 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
ports:
|
||||
- 8083:8083
|
||||
- 18083:18083
|
||||
command: 'volume -dataCenter=dc3 -rack=v3 -master="master0:9333,master1:9334,master2:9335" -port=8083 -ip=volume3 -publicUrl=localhost:8083 -preStopSeconds=1'
|
||||
command: 'volume -dataCenter=dc3 -rack=v3 -mserver="master0:9333,master1:9334,master2:9335" -port=8083 -ip=volume3 -publicUrl=localhost:8083 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
|
||||
@@ -16,7 +16,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "-v=1 volume -master=master:9333 -port=8080 -ip=volume -preStopSeconds=1 -max=10000"
|
||||
command: "-v=1 volume -mserver=master:9333 -port=8080 -ip=volume -preStopSeconds=1 -max=10000"
|
||||
depends_on:
|
||||
- master
|
||||
volumes:
|
||||
|
||||
@@ -42,7 +42,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: 'volume -dataCenter=dc1 -rack=v1 -master="master0:9333,master1:9334,master2:9335" -port=8080 -ip=volume1 -publicUrl=localhost:8080 -preStopSeconds=1'
|
||||
command: 'volume -dataCenter=dc1 -rack=v1 -mserver="master0:9333,master1:9334,master2:9335" -port=8080 -ip=volume1 -publicUrl=localhost:8080 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
@@ -51,7 +51,7 @@ services:
|
||||
ports:
|
||||
- 8082:8082
|
||||
- 18082:18082
|
||||
command: 'volume -dataCenter=dc2 -rack=v2 -master="master0:9333,master1:9334,master2:9335" -port=8082 -ip=volume2 -publicUrl=localhost:8082 -preStopSeconds=1'
|
||||
command: 'volume -dataCenter=dc2 -rack=v2 -mserver="master0:9333,master1:9334,master2:9335" -port=8082 -ip=volume2 -publicUrl=localhost:8082 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
@@ -60,7 +60,7 @@ services:
|
||||
ports:
|
||||
- 8083:8083
|
||||
- 18083:18083
|
||||
command: 'volume -dataCenter=dc3 -rack=v3 -master="master0:9333,master1:9334,master2:9335" -port=8083 -ip=volume3 -publicUrl=localhost:8083 -preStopSeconds=1'
|
||||
command: 'volume -dataCenter=dc3 -rack=v3 -mserver="master0:9333,master1:9334,master2:9335" -port=8083 -ip=volume3 -publicUrl=localhost:8083 -preStopSeconds=1'
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume"
|
||||
command: "volume -mserver=master:9333 -port=8080 -ip=volume"
|
||||
depends_on:
|
||||
- master
|
||||
mysql:
|
||||
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume -max=0 -preStopSeconds=1"
|
||||
command: "volume -mserver=master:9333 -port=8080 -ip=volume -max=0 -preStopSeconds=1"
|
||||
depends_on:
|
||||
- master
|
||||
s3:
|
||||
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
ports:
|
||||
- 7455:8080
|
||||
- 9325:9325
|
||||
command: 'volume -master="master:9333" -port=8080 -metricsPort=9325 -preStopSeconds=1 -publicUrl=localhost:7455'
|
||||
command: 'volume -mserver="master:9333" -port=8080 -metricsPort=9325 -preStopSeconds=1 -publicUrl=localhost:7455'
|
||||
depends_on:
|
||||
- master
|
||||
filer:
|
||||
|
||||
@@ -14,7 +14,7 @@ services:
|
||||
- 9325:9325
|
||||
volumes:
|
||||
- /Volumes/mobile_disk/99:/data
|
||||
command: 'volume -master="master:9333" -port=8080 -metricsPort=9325 -preStopSeconds=1 -publicUrl=localhost:7455'
|
||||
command: 'volume -mserver="master:9333" -port=8080 -metricsPort=9325 -preStopSeconds=1 -publicUrl=localhost:7455'
|
||||
depends_on:
|
||||
- master
|
||||
filer:
|
||||
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume"
|
||||
command: "volume -mserver=master:9333 -port=8080 -ip=volume"
|
||||
depends_on:
|
||||
- master
|
||||
s3:
|
||||
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume -max=0 -preStopSeconds=1"
|
||||
command: "volume -mserver=master:9333 -port=8080 -ip=volume -max=0 -preStopSeconds=1"
|
||||
depends_on:
|
||||
- master
|
||||
s3:
|
||||
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume -preStopSeconds=1"
|
||||
command: "volume -mserver=master:9333 -port=8080 -ip=volume -preStopSeconds=1"
|
||||
depends_on:
|
||||
- master
|
||||
filer:
|
||||
|
||||
@@ -15,7 +15,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume -preStopSeconds=1"
|
||||
command: "volume -mserver=master:9333 -port=8080 -ip=volume -preStopSeconds=1"
|
||||
depends_on:
|
||||
- master
|
||||
s3:
|
||||
@@ -24,7 +24,7 @@ services:
|
||||
- 8888:8888
|
||||
- 18888:18888
|
||||
- 8000:8000
|
||||
command: 'filer -master="master:9333" -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8000 -s3.allowDeleteBucketNotEmpty=false'
|
||||
command: 'filer -master="master:9333" -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8000 -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=false'
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
depends_on:
|
||||
|
||||
@@ -71,7 +71,7 @@ services:
|
||||
- net
|
||||
command:
|
||||
- 'volume'
|
||||
- '-master=master:9333'
|
||||
- '-mserver=master:9333'
|
||||
- '-port=8080'
|
||||
deploy:
|
||||
mode: global
|
||||
|
||||
@@ -17,7 +17,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: "volume -master=master:9333 -port=8080 -ip=volume -max=0 -preStopSeconds=1"
|
||||
command: "volume -mserver=master:9333 -port=8080 -ip=volume -max=0 -preStopSeconds=1"
|
||||
depends_on:
|
||||
- master
|
||||
s3:
|
||||
|
||||
@@ -15,7 +15,7 @@ services:
|
||||
|
||||
s3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
command: "server -ip=127.0.0.1 -filer -master.volumeSizeLimitMB=16 -volume.max=0 -volume -volume.preStopSeconds=1 -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8000 -s3.allowDeleteBucketNotEmpty=false"
|
||||
command: "server -ip=127.0.0.1 -filer -master.volumeSizeLimitMB=16 -volume.max=0 -volume -volume.preStopSeconds=1 -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8000 -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=false"
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
environment:
|
||||
|
||||
@@ -20,7 +20,7 @@ services:
|
||||
- 8888:8888
|
||||
- 8000:8000
|
||||
- 18888:18888
|
||||
command: "server -ip=s3 -filer -master.volumeSizeLimitMB=16 -volume.max=0 -volume -volume.preStopSeconds=1 -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8000 -s3.allowDeleteBucketNotEmpty=false"
|
||||
command: "server -ip=s3 -filer -master.volumeSizeLimitMB=16 -volume.max=0 -volume -volume.preStopSeconds=1 -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8000 -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=false"
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
environment:
|
||||
|
||||
@@ -14,7 +14,7 @@ services:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
- 9325:9325
|
||||
command: 'volume -ip=volume -master="master:9333" -ip.bind=0.0.0.0 -port=8080 -metricsPort=9325'
|
||||
command: 'volume -ip=volume -mserver="master:9333" -ip.bind=0.0.0.0 -port=8080 -metricsPort=9325'
|
||||
depends_on:
|
||||
- master
|
||||
filer:
|
||||
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 18080:18080
|
||||
command: 'volume -ip=volume -master="master:9333" -ip.bind=0.0.0.0 -port=8080'
|
||||
command: 'volume -ip=volume -mserver="master:9333" -ip.bind=0.0.0.0 -port=8080'
|
||||
depends_on:
|
||||
- master
|
||||
filer:
|
||||
|
||||
@@ -51,7 +51,7 @@ require (
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/karlseguin/ccache/v2 v2.0.8
|
||||
github.com/klauspost/compress v1.18.2
|
||||
github.com/klauspost/reedsolomon v1.12.6
|
||||
github.com/klauspost/reedsolomon v1.12.5
|
||||
github.com/kurin/blazer v0.5.3
|
||||
github.com/linxGnu/grocksdb v1.10.3
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
@@ -118,7 +118,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/kms v1.23.2
|
||||
cloud.google.com/go/kms v1.23.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0
|
||||
github.com/Jille/raft-grpc-transport v1.6.1
|
||||
github.com/ThreeDotsLabs/watermill v1.5.1
|
||||
@@ -126,10 +126,10 @@ require (
|
||||
github.com/apple/foundationdb/bindings/go v0.0.0-20240515141816-262c6fe778ad
|
||||
github.com/arangodb/go-driver v1.6.9
|
||||
github.com/armon/go-metrics v0.4.1
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.1
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.31.3
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.3
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.20
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.89.1
|
||||
github.com/cognusion/imaging v1.0.2
|
||||
github.com/fluent/fluent-logger-golang v1.10.1
|
||||
github.com/getsentry/sentry-go v0.38.0
|
||||
@@ -162,7 +162,7 @@ require (
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.121.0
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.6
|
||||
go.uber.org/atomic v1.11.0
|
||||
golang.org/x/sync v0.19.0
|
||||
golang.org/x/sync v0.18.0
|
||||
golang.org/x/tools/godoc v0.1.0-deprecated
|
||||
google.golang.org/grpc/security/advancedtls v1.0.0
|
||||
)
|
||||
@@ -260,23 +260,23 @@ require (
|
||||
github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc // indirect
|
||||
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.18.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sns v1.34.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3 // indirect
|
||||
github.com/aws/smithy-go v1.24.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.39.0 // indirect
|
||||
github.com/aws/smithy-go v1.23.2 // indirect
|
||||
github.com/boltdb/bolt v1.3.1 // indirect
|
||||
github.com/bradenaw/juniper v0.15.3 // indirect
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
||||
|
||||
@@ -290,8 +290,8 @@ cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxs
|
||||
cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg=
|
||||
cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0=
|
||||
cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w=
|
||||
cloud.google.com/go/kms v1.23.2 h1:4IYDQL5hG4L+HzJBhzejUySoUOheh3Lk5YT4PCyyW6k=
|
||||
cloud.google.com/go/kms v1.23.2/go.mod h1:rZ5kK0I7Kn9W4erhYVoIRPtpizjunlrfU4fUkumUp8g=
|
||||
cloud.google.com/go/kms v1.23.1 h1:Mesyv84WoP3tPjUC0O5LRqPWICO0ufdpWf9jtBCEz64=
|
||||
cloud.google.com/go/kms v1.23.1/go.mod h1:rZ5kK0I7Kn9W4erhYVoIRPtpizjunlrfU4fUkumUp8g=
|
||||
cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
|
||||
cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
|
||||
cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE=
|
||||
@@ -665,48 +665,48 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ=
|
||||
github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.1 h1:difXb4maDZkRH0x//Qkwcfpdg1XQVXEAEs2DdXldFFc=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.2 h1:t9yYsydLYNBk9cJ73rgPhPWqOh/52fcWDQB5b1JsKSY=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.2/go.mod h1:IusfVNTmiSN3t4rhxWFaBAqn+mcNdwKtPcV16eYdgko=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.31.3 h1:RIb3yr/+PZ18YYNe6MDiG/3jVoJrPmdoCARwNkMGvco=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.31.3/go.mod h1:jjgx1n7x0FAKl6TnakqrpkHWWKcX3xfWtdnIJs5K9CE=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.3 h1:01Ym72hK43hjwDeJUfi1l2oYLXBAOR8gNSZNmXmvuas=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.3/go.mod h1:55nWF/Sr9Zvls0bGnWkRxUdhzKqj9uRNlPvgV1vgxKc=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15 h1:utxLraaifrSBkeyII9mIbVwXXWrZdlPO7FIKmyLCEcY=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15/go.mod h1:hW6zjYUDQwfz3icf4g2O41PHi77u10oAzJ84iSzR/lo=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.20 h1:KFndAnHd9NUuzikHjQ8D5CfFVO+bgELkmcGY8yAw98Q=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.20/go.mod h1:9mCi28a+fmBHSQ0UM79omkz6JtN+PEsvLrnG36uoUv0=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.12 h1:VO3FIM2TDbm0kqp6sFNR0PbioXJb/HzCDW6NtIZpIWE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.12/go.mod h1:6C39gB8kg82tx3r72muZSrNhHia9rjGkX7ORaS2GKNE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.18.4 h1:0SzCLoPRSK3qSydsaFQWugP+lOBCTPwfcBOm6222+UA=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.18.4/go.mod h1:JAet9FsBHjfdI+TnMBX4ModNNaQHAd3dc/Bk+cNsxeM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15 h1:Y5YXgygXwDI5P4RkteB5yF7v35neH7LfJKBG+hzIons=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15/go.mod h1:K+/1EpG42dFSY7CBj+Fruzm8PsCGWTXJ3jdeJ659oGQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15 h1:AvltKnW9ewxX2hFmQS0FyJH93aSvJVUEFvXfU+HWtSE=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15/go.mod h1:3I4oCdZdmgrREhU74qS1dK9yZ62yumob+58AbFR4cQA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.12 h1:p/9flfXdoAnwJnuW9xHEAFY22R3A6skYkW19JFF9F+8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.12/go.mod h1:ZTLHakoVCTtW8AaLGSwJ3LXqHD9uQKnOcv1TrpO6u2k=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.12 h1:2lTWFvRcnWFFLzHWmtddu5MTchc5Oj2OOey++99tPZ0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.12/go.mod h1:hI92pK+ho8HVcWMHKHrK3Uml4pfG7wvL86FzO0LVtQQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15 h1:NLYTEyZmVZo0Qh183sC8nC+ydJXOOeIL/qI/sS3PdLY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15/go.mod h1:Z803iB3B0bc8oJV8zH2PERLRfQUJ2n2BXISpsA4+O1M=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6 h1:P1MU/SuhadGvg2jtviDXPEejU3jBNhoeeAlRadHzvHI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6/go.mod h1:5KYaMG6wmVKMFBSfWoyG/zH8pWwzQFnKgpoSRlXHKdQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15 h1:3/u/4yZOffg5jdNk1sDpOQ4Y+R6Xbh+GzpDrSZjuy3U=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15/go.mod h1:4Zkjq0FKjE78NKjabuM4tRXKFzUJWXgP0ItEZK8l7JU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15 h1:wsSQ4SVz5YE1crz0Ap7VBZrV4nNqZt4CIBBT8mnwoNc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15/go.mod h1:I7sditnFGtYMIqPRU1QoHZAUrXkGp4SczmlLwrNPlD0=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0 h1:IrbE3B8O9pm3lsg96AXIN5MXX4pECEuExh/A0Du3AuI=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0/go.mod h1:/sJLzHtiiZvs6C1RbxS/anSAFwZD6oC6M/kotQzOiLw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.12 h1:itu4KHu8JK/N6NcLIISlf3LL1LccMqruLUXZ9y7yBZw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.12/go.mod h1:i+6vTU3xziikTY3vcox23X8pPGW5X3wVgd1VZ7ha+x8=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.2 h1:xtuxji5CS0JknaXoACOunXOYOQzgfTvGAc9s2QdCJA4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.2/go.mod h1:zxwi0DIR0rcRcgdbl7E2MSOvxDyyXGBlScvBkARFaLQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.3 h1:NEe7FaViguRQEm8zl8Ay/kC/QRsMtWUiCGZajQIsLdc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.3/go.mod h1:JLuCKu5VfiLBBBl/5IzZILU7rxS0koQpHzMOCzycOJU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.12 h1:MM8imH7NZ0ovIVX7D2RxfMDv7Jt9OiUXkcQ+GqywA7M=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.12/go.mod h1:gf4OGwdNkbEsb7elw2Sy76odfhwNktWII3WgvQgQQ6w=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.12 h1:R3uW0iKl8rgNEXNjVGliW/oMEh9fO/LlUEV8RvIFr1I=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.12/go.mod h1:XEttbEr5yqsw8ebi7vlDoGJJjMXRez4/s9pibpJyL5s=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.89.1 h1:Dq82AV+Qxpno/fG162eAhnD8d48t9S+GZCfz7yv1VeA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.89.1/go.mod h1:MbKLznDKpf7PnSonNRUVYZzfP0CeLkRIUexeblgKcU4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sns v1.34.7 h1:OBuZE9Wt8h2imuRktu+WfjiTGrnYdCIJg8IX92aalHE=
|
||||
github.com/aws/aws-sdk-go-v2/service/sns v1.34.7/go.mod h1:4WYoZAhHt+dWYpoOQUgkUKfuQbE6Gg/hW4oXE0pKS9U=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8 h1:80dpSqWMwx2dAm30Ib7J6ucz1ZHfiv5OCRwN/EnCOXQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8/go.mod h1:IzNt/udsXlETCdvBOL0nmyMe2t9cGmXmZgsdoZGYYhI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6 h1:8sTTiw+9yuNXcfWeqKF2x01GqCF49CpP4Z9nKrrk/ts=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6/go.mod h1:8WYg+Y40Sn3X2hioaaWAAIngndR8n1XFdRPPX+7QBaM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11 h1:E+KqWoVsSrj1tJ6I/fjDIu5xoS2Zacuu1zT+H7KtiIk=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11/go.mod h1:qyWHz+4lvkXcr3+PoGlGHEI+3DLLiU6/GdrFfMaAhB0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3 h1:tzMkjh0yTChUqJDgGkcDdxvZDSrJ/WB6R6ymI5ehqJI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3/go.mod h1:T270C0R5sZNLbWUe8ueiAF42XSZxxPocTaGSgs5c/60=
|
||||
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
|
||||
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.0 h1:xHXvxst78wBpJFgDW07xllOx0IAzbryrSdM4nMVQ4Dw=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.0/go.mod h1:/e8m+AO6HNPPqMyfKRtzZ9+mBF5/x1Wk8QiDva4m07I=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.4 h1:tBw2Qhf0kj4ZwtsVpDiVRU3zKLvjvjgIjHMKirxXg8M=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.4/go.mod h1:Deq4B7sRM6Awq/xyOBlxBdgW8/Z926KYNNaGMW2lrkA=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.39.0 h1:C+BRMnasSYFcgDw8o9H5hzehKzXyAb9GY5v/8bP9DUY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.39.0/go.mod h1:4EjU+4mIx6+JqKQkruye+CaigV7alL3thVPfDd9VlMs=
|
||||
github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
|
||||
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||
github.com/bazelbuild/rules_go v0.46.0 h1:CTefzjN/D3Cdn3rkrM6qMWuQj59OBcuOjyIp3m4hZ7s=
|
||||
github.com/bazelbuild/rules_go v0.46.0/go.mod h1:Dhcz716Kqg1RHNWos+N6MlXNkjNP2EwZQ0LukRKJfMs=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
@@ -1329,8 +1329,8 @@ github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxh
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/klauspost/reedsolomon v1.12.6 h1:8pqE9aECQG/ZFitiUD1xK/E83zwosBAZtE3UbuZM8TQ=
|
||||
github.com/klauspost/reedsolomon v1.12.6/go.mod h1:ggJT9lc71Vu+cSOPBlxGvBN6TfAS77qB4fp8vJ05NSA=
|
||||
github.com/klauspost/reedsolomon v1.12.5 h1:4cJuyH926If33BeDgiZpI5OU0pE+wUHZvMSyNGqN73Y=
|
||||
github.com/klauspost/reedsolomon v1.12.5/go.mod h1:LkXRjLYGM8K/iQfujYnaPeDmhZLqkrGUyG9p7zs5L68=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -2110,8 +2110,8 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
apiVersion: v1
|
||||
description: SeaweedFS
|
||||
name: seaweedfs
|
||||
appVersion: "4.02"
|
||||
appVersion: "4.01"
|
||||
# Dev note: Trigger a helm chart release by `git tag -a helm-<version>`
|
||||
version: 4.0.402
|
||||
version: 4.0.401
|
||||
|
||||
@@ -15,9 +15,9 @@ metadata:
|
||||
{{- toYaml .Values.allInOne.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
replicas: {{ .Values.allInOne.replicas | default 1 }}
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: {{ .Values.allInOne.updateStrategy.type | default "Recreate" }}
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -130,23 +130,12 @@ spec:
|
||||
value: {{ include "seaweedfs.cluster.masterAddress" . | quote }}
|
||||
- name: {{ $clusterFilerKey }}
|
||||
value: {{ include "seaweedfs.cluster.filerAddress" . | quote }}
|
||||
{{- if .Values.allInOne.secretExtraEnvironmentVars }}
|
||||
{{- range $key, $value := .Values.allInOne.secretExtraEnvironmentVars }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
{{ toYaml $value | nindent 16 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
command:
|
||||
- "/bin/sh"
|
||||
- "-ec"
|
||||
- |
|
||||
/usr/bin/weed \
|
||||
{{- if .Values.allInOne.loggingOverrideLevel }}
|
||||
-v={{ .Values.allInOne.loggingOverrideLevel }} \
|
||||
{{- else }}
|
||||
-v={{ .Values.global.loggingLevel }} \
|
||||
{{- end }}
|
||||
server \
|
||||
-dir=/data \
|
||||
-master \
|
||||
@@ -202,9 +191,6 @@ spec:
|
||||
{{- else if .Values.master.metricsPort }}
|
||||
-metricsPort={{ .Values.master.metricsPort }} \
|
||||
{{- end }}
|
||||
{{- if .Values.allInOne.metricsIp }}
|
||||
-metricsIp={{ .Values.allInOne.metricsIp }} \
|
||||
{{- end }}
|
||||
-filer \
|
||||
-filer.port={{ .Values.filer.port }} \
|
||||
{{- if .Values.filer.disableDirListing }}
|
||||
@@ -233,75 +219,61 @@ spec:
|
||||
{{- end }}
|
||||
{{- if .Values.allInOne.s3.enabled }}
|
||||
-s3 \
|
||||
-s3.port={{ .Values.allInOne.s3.port | default .Values.s3.port }} \
|
||||
{{- $domainName := .Values.allInOne.s3.domainName | default .Values.s3.domainName }}
|
||||
{{- if $domainName }}
|
||||
-s3.domainName={{ $domainName }} \
|
||||
-s3.port={{ .Values.s3.port }} \
|
||||
{{- if .Values.s3.domainName }}
|
||||
-s3.domainName={{ .Values.s3.domainName }} \
|
||||
{{- end }}
|
||||
{{- if .Values.global.enableSecurity }}
|
||||
{{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }}
|
||||
{{- if $httpsPort }}
|
||||
-s3.port.https={{ $httpsPort }} \
|
||||
{{- if .Values.s3.httpsPort }}
|
||||
-s3.port.https={{ .Values.s3.httpsPort }} \
|
||||
{{- end }}
|
||||
-s3.cert.file=/usr/local/share/ca-certificates/client/tls.crt \
|
||||
-s3.key.file=/usr/local/share/ca-certificates/client/tls.key \
|
||||
{{- end }}
|
||||
{{- if or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth }}
|
||||
{{- if eq (typeOf .Values.s3.allowEmptyFolder) "bool" }}
|
||||
-s3.allowEmptyFolder={{ .Values.s3.allowEmptyFolder }} \
|
||||
{{- end }}
|
||||
{{- if .Values.s3.enableAuth }}
|
||||
-s3.config=/etc/sw/s3/seaweedfs_s3_config \
|
||||
{{- end }}
|
||||
{{- $auditLogConfig := .Values.allInOne.s3.auditLogConfig | default .Values.s3.auditLogConfig }}
|
||||
{{- if $auditLogConfig }}
|
||||
{{- if .Values.s3.auditLogConfig }}
|
||||
-s3.auditLogConfig=/etc/sw/s3/s3_auditLogConfig.json \
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.allInOne.sftp.enabled }}
|
||||
-sftp \
|
||||
-sftp.port={{ .Values.allInOne.sftp.port | default .Values.sftp.port }} \
|
||||
{{- $sshPrivateKey := .Values.allInOne.sftp.sshPrivateKey | default .Values.sftp.sshPrivateKey }}
|
||||
{{- if $sshPrivateKey }}
|
||||
-sftp.sshPrivateKey={{ $sshPrivateKey }} \
|
||||
-sftp.port={{ .Values.sftp.port }} \
|
||||
{{- if .Values.sftp.sshPrivateKey }}
|
||||
-sftp.sshPrivateKey={{ .Values.sftp.sshPrivateKey }} \
|
||||
{{- end }}
|
||||
{{- $hostKeysFolder := .Values.allInOne.sftp.hostKeysFolder | default .Values.sftp.hostKeysFolder }}
|
||||
{{- if $hostKeysFolder }}
|
||||
-sftp.hostKeysFolder={{ $hostKeysFolder }} \
|
||||
{{- if .Values.sftp.hostKeysFolder }}
|
||||
-sftp.hostKeysFolder={{ .Values.sftp.hostKeysFolder }} \
|
||||
{{- end }}
|
||||
{{- $authMethods := .Values.allInOne.sftp.authMethods | default .Values.sftp.authMethods }}
|
||||
{{- if $authMethods }}
|
||||
-sftp.authMethods={{ $authMethods }} \
|
||||
{{- if .Values.sftp.authMethods }}
|
||||
-sftp.authMethods={{ .Values.sftp.authMethods }} \
|
||||
{{- end }}
|
||||
{{- $maxAuthTries := .Values.allInOne.sftp.maxAuthTries | default .Values.sftp.maxAuthTries }}
|
||||
{{- if $maxAuthTries }}
|
||||
-sftp.maxAuthTries={{ $maxAuthTries }} \
|
||||
{{- if .Values.sftp.maxAuthTries }}
|
||||
-sftp.maxAuthTries={{ .Values.sftp.maxAuthTries }} \
|
||||
{{- end }}
|
||||
{{- $bannerMessage := .Values.allInOne.sftp.bannerMessage | default .Values.sftp.bannerMessage }}
|
||||
{{- if $bannerMessage }}
|
||||
-sftp.bannerMessage="{{ $bannerMessage }}" \
|
||||
{{- if .Values.sftp.bannerMessage }}
|
||||
-sftp.bannerMessage="{{ .Values.sftp.bannerMessage }}" \
|
||||
{{- end }}
|
||||
{{- $loginGraceTime := .Values.allInOne.sftp.loginGraceTime | default .Values.sftp.loginGraceTime }}
|
||||
{{- if $loginGraceTime }}
|
||||
-sftp.loginGraceTime={{ $loginGraceTime }} \
|
||||
{{- if .Values.sftp.loginGraceTime }}
|
||||
-sftp.loginGraceTime={{ .Values.sftp.loginGraceTime }} \
|
||||
{{- end }}
|
||||
{{- $clientAliveInterval := .Values.allInOne.sftp.clientAliveInterval | default .Values.sftp.clientAliveInterval }}
|
||||
{{- if $clientAliveInterval }}
|
||||
-sftp.clientAliveInterval={{ $clientAliveInterval }} \
|
||||
{{- if .Values.sftp.clientAliveInterval }}
|
||||
-sftp.clientAliveInterval={{ .Values.sftp.clientAliveInterval }} \
|
||||
{{- end }}
|
||||
{{- $clientAliveCountMax := .Values.allInOne.sftp.clientAliveCountMax | default .Values.sftp.clientAliveCountMax }}
|
||||
{{- if $clientAliveCountMax }}
|
||||
-sftp.clientAliveCountMax={{ $clientAliveCountMax }} \
|
||||
{{- if .Values.sftp.clientAliveCountMax }}
|
||||
-sftp.clientAliveCountMax={{ .Values.sftp.clientAliveCountMax }} \
|
||||
{{- end }}
|
||||
{{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }}
|
||||
-sftp.userStoreFile=/etc/sw/sftp/seaweedfs_sftp_config \
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $extraArgsCount := len .Values.allInOne.extraArgs }}
|
||||
{{- range $i, $arg := .Values.allInOne.extraArgs }}
|
||||
{{ $arg | quote }}{{ if ne (add1 $i) $extraArgsCount }} \{{ end }}
|
||||
{{- end }}
|
||||
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
{{- if and .Values.allInOne.s3.enabled (or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth) }}
|
||||
{{- if and .Values.allInOne.s3.enabled (or .Values.s3.enableAuth .Values.filer.s3.enableAuth) }}
|
||||
- name: config-s3-users
|
||||
mountPath: /etc/sw/s3
|
||||
readOnly: true
|
||||
@@ -310,12 +282,10 @@ spec:
|
||||
- name: config-ssh
|
||||
mountPath: /etc/sw/ssh
|
||||
readOnly: true
|
||||
{{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }}
|
||||
- mountPath: /etc/sw/sftp
|
||||
name: config-users
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.filer.notificationConfig }}
|
||||
- name: notification-config
|
||||
mountPath: /etc/seaweedfs/notification.toml
|
||||
@@ -362,16 +332,15 @@ spec:
|
||||
- containerPort: {{ .Values.filer.grpcPort }}
|
||||
name: swfs-fil-grpc
|
||||
{{- if .Values.allInOne.s3.enabled }}
|
||||
- containerPort: {{ .Values.allInOne.s3.port | default .Values.s3.port }}
|
||||
- containerPort: {{ .Values.s3.port }}
|
||||
name: swfs-s3
|
||||
{{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }}
|
||||
{{- if $httpsPort }}
|
||||
- containerPort: {{ $httpsPort }}
|
||||
{{- if .Values.s3.httpsPort }}
|
||||
- containerPort: {{ .Values.s3.httpsPort }}
|
||||
name: swfs-s3-tls
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.allInOne.sftp.enabled }}
|
||||
- containerPort: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }}
|
||||
- containerPort: {{ .Values.sftp.port }}
|
||||
name: swfs-sftp
|
||||
{{- end }}
|
||||
{{- if .Values.allInOne.metricsPort }}
|
||||
@@ -420,31 +389,26 @@ spec:
|
||||
path: {{ .Values.allInOne.data.hostPathPrefix }}/seaweedfs-all-in-one-data/
|
||||
type: DirectoryOrCreate
|
||||
{{- else if eq .Values.allInOne.data.type "persistentVolumeClaim" }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ template "seaweedfs.name" . }}-all-in-one-data
|
||||
{{- else if eq .Values.allInOne.data.type "existingClaim" }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.allInOne.data.claimName }}
|
||||
{{- else if eq .Values.allInOne.data.type "emptyDir" }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- if and .Values.allInOne.s3.enabled (or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth) }}
|
||||
{{- if and .Values.allInOne.s3.enabled (or .Values.s3.enableAuth .Values.filer.s3.enableAuth) }}
|
||||
- name: config-s3-users
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: {{ default (printf "%s-s3-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.s3.existingConfigSecret .Values.s3.existingConfigSecret .Values.filer.s3.existingConfigSecret) }}
|
||||
secretName: {{ default (printf "%s-s3-secret" (include "seaweedfs.name" .)) (or .Values.s3.existingConfigSecret .Values.filer.s3.existingConfigSecret) }}
|
||||
{{- end }}
|
||||
{{- if .Values.allInOne.sftp.enabled }}
|
||||
- name: config-ssh
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: {{ default (printf "%s-sftp-ssh-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.sftp.existingSshConfigSecret .Values.sftp.existingSshConfigSecret) }}
|
||||
{{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }}
|
||||
secretName: {{ default (printf "%s-sftp-ssh-secret" (include "seaweedfs.name" .)) .Values.sftp.existingSshConfigSecret }}
|
||||
- name: config-users
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: {{ default (printf "%s-sftp-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.sftp.existingConfigSecret .Values.sftp.existingConfigSecret) }}
|
||||
{{- end }}
|
||||
secretName: {{ default (printf "%s-sftp-secret" (include "seaweedfs.name" .)) .Values.sftp.existingConfigSecret }}
|
||||
{{- end }}
|
||||
{{- if .Values.filer.notificationConfig }}
|
||||
- name: notification-config
|
||||
|
||||
@@ -1,28 +1,21 @@
|
||||
{{- if .Values.allInOne.enabled }}
|
||||
{{- if eq .Values.allInOne.data.type "persistentVolumeClaim" }}
|
||||
{{- if and .Values.allInOne.enabled (eq .Values.allInOne.data.type "persistentVolumeClaim") }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-all-in-one-data
|
||||
namespace: {{ .Release.Namespace }}
|
||||
name: {{ .Values.allInOne.data.claimName }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: seaweedfs-all-in-one
|
||||
{{- with .Values.allInOne.data.annotations }}
|
||||
{{- if .Values.allInOne.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- toYaml .Values.allInOne.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
accessModes:
|
||||
{{- toYaml (.Values.allInOne.data.accessModes | default (list "ReadWriteOnce")) | nindent 4 }}
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.allInOne.data.size }}
|
||||
{{- if .Values.allInOne.data.storageClass }}
|
||||
storageClassName: {{ .Values.allInOne.data.storageClass }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.allInOne.data.size | default "10Gi" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -15,7 +15,6 @@ metadata:
|
||||
{{- toYaml .Values.allInOne.service.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ .Values.allInOne.service.type | default "ClusterIP" }}
|
||||
internalTrafficPolicy: {{ .Values.allInOne.service.internalTrafficPolicy | default "Cluster" }}
|
||||
ports:
|
||||
# Master ports
|
||||
@@ -51,14 +50,13 @@ spec:
|
||||
# S3 ports (if enabled)
|
||||
{{- if .Values.allInOne.s3.enabled }}
|
||||
- name: "swfs-s3"
|
||||
port: {{ .Values.allInOne.s3.port | default .Values.s3.port }}
|
||||
targetPort: {{ .Values.allInOne.s3.port | default .Values.s3.port }}
|
||||
port: {{ if .Values.allInOne.s3.enabled }}{{ .Values.s3.port }}{{ else }}{{ .Values.filer.s3.port }}{{ end }}
|
||||
targetPort: {{ if .Values.allInOne.s3.enabled }}{{ .Values.s3.port }}{{ else }}{{ .Values.filer.s3.port }}{{ end }}
|
||||
protocol: TCP
|
||||
{{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }}
|
||||
{{- if $httpsPort }}
|
||||
{{- if and .Values.allInOne.s3.enabled .Values.s3.httpsPort }}
|
||||
- name: "swfs-s3-tls"
|
||||
port: {{ $httpsPort }}
|
||||
targetPort: {{ $httpsPort }}
|
||||
port: {{ .Values.s3.httpsPort }}
|
||||
targetPort: {{ .Values.s3.httpsPort }}
|
||||
protocol: TCP
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -66,8 +64,8 @@ spec:
|
||||
# SFTP ports (if enabled)
|
||||
{{- if .Values.allInOne.sftp.enabled }}
|
||||
- name: "swfs-sftp"
|
||||
port: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }}
|
||||
targetPort: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }}
|
||||
port: {{ .Values.sftp.port }}
|
||||
targetPort: {{ .Values.sftp.port }}
|
||||
protocol: TCP
|
||||
{{- end }}
|
||||
|
||||
@@ -82,4 +80,4 @@ spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/component: seaweedfs-all-in-one
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,8 +1,5 @@
|
||||
{{- /* Filer ingress works for both normal mode (filer.enabled) and all-in-one mode (allInOne.enabled) */}}
|
||||
{{- $filerEnabled := or .Values.filer.enabled .Values.allInOne.enabled }}
|
||||
{{- if and $filerEnabled .Values.filer.ingress.enabled }}
|
||||
{{- /* Determine service name based on deployment mode */}}
|
||||
{{- $serviceName := ternary (printf "%s-all-in-one" (include "seaweedfs.name" .)) (printf "%s-filer" (include "seaweedfs.name" .)) .Values.allInOne.enabled }}
|
||||
{{- if .Values.filer.enabled }}
|
||||
{{- if .Values.filer.ingress.enabled }}
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
@@ -36,14 +33,16 @@ spec:
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ $serviceName }}
|
||||
name: {{ template "seaweedfs.name" . }}-filer
|
||||
port:
|
||||
number: {{ .Values.filer.port }}
|
||||
#name:
|
||||
{{- else }}
|
||||
serviceName: {{ $serviceName }}
|
||||
serviceName: {{ template "seaweedfs.name" . }}-filer
|
||||
servicePort: {{ .Values.filer.port }}
|
||||
{{- end }}
|
||||
{{- if .Values.filer.ingress.host }}
|
||||
host: {{ .Values.filer.ingress.host }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -213,6 +213,9 @@ spec:
|
||||
-s3.cert.file=/usr/local/share/ca-certificates/client/tls.crt \
|
||||
-s3.key.file=/usr/local/share/ca-certificates/client/tls.key \
|
||||
{{- end }}
|
||||
{{- if eq (typeOf .Values.filer.s3.allowEmptyFolder) "bool" }}
|
||||
-s3.allowEmptyFolder={{ .Values.filer.s3.allowEmptyFolder }} \
|
||||
{{- end }}
|
||||
{{- if .Values.filer.s3.enableAuth }}
|
||||
-s3.config=/etc/sw/seaweedfs_s3_config \
|
||||
{{- end }}
|
||||
@@ -220,7 +223,7 @@ spec:
|
||||
-s3.auditLogConfig=/etc/sw/filer_s3_auditLogConfig.json \
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
-master={{ include "seaweedfs.masterServerArg" . }} \
|
||||
-master={{ if .Values.global.masterServer }}{{.Values.global.masterServer}}{{ else }}{{ range $index := until (.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }}{{ end }} \
|
||||
{{- range .Values.filer.extraArgs }}
|
||||
{{ . }} \
|
||||
{{- end }}
|
||||
|
||||
@@ -184,7 +184,7 @@ spec:
|
||||
-garbageThreshold={{ .Values.master.garbageThreshold }} \
|
||||
{{- end }}
|
||||
-ip=${POD_NAME}.${SEAWEEDFS_FULLNAME}-master.{{ .Release.Namespace }} \
|
||||
-peers={{ include "seaweedfs.masterServers" . }} \
|
||||
-peers={{ range $index := until (.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }} \
|
||||
{{- range .Values.master.extraArgs }}
|
||||
{{ . }} \
|
||||
{{- end }}
|
||||
|
||||
@@ -143,6 +143,9 @@ spec:
|
||||
{{- if .Values.s3.domainName }}
|
||||
-domainName={{ .Values.s3.domainName }} \
|
||||
{{- end }}
|
||||
{{- if eq (typeOf .Values.s3.allowEmptyFolder) "bool" }}
|
||||
-allowEmptyFolder={{ .Values.s3.allowEmptyFolder }} \
|
||||
{{- end }}
|
||||
{{- if .Values.s3.enableAuth }}
|
||||
-config=/etc/sw/seaweedfs_s3_config \
|
||||
{{- end }}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
{{- /* S3 ingress works for standalone S3 gateway (s3.enabled), S3 on Filer (filer.s3.enabled), and all-in-one mode (allInOne.s3.enabled) */}}
|
||||
{{- $s3Enabled := or .Values.s3.enabled (and .Values.filer.s3.enabled (not .Values.allInOne.enabled)) (and .Values.allInOne.enabled .Values.allInOne.s3.enabled) }}
|
||||
{{- if and $s3Enabled .Values.s3.ingress.enabled }}
|
||||
{{- /* Determine service name based on deployment mode */}}
|
||||
{{- $serviceName := ternary (printf "%s-all-in-one" (include "seaweedfs.name" .)) (printf "%s-s3" (include "seaweedfs.name" .)) .Values.allInOne.enabled }}
|
||||
{{- $s3Port := .Values.allInOne.s3.port | default .Values.s3.port }}
|
||||
{{- if .Values.s3.ingress.enabled }}
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
@@ -37,12 +32,13 @@ spec:
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ $serviceName }}
|
||||
name: {{ template "seaweedfs.name" . }}-s3
|
||||
port:
|
||||
number: {{ $s3Port }}
|
||||
number: {{ .Values.s3.port }}
|
||||
#name:
|
||||
{{- else }}
|
||||
serviceName: {{ $serviceName }}
|
||||
servicePort: {{ $s3Port }}
|
||||
serviceName: {{ template "seaweedfs.name" . }}-s3
|
||||
servicePort: {{ .Values.s3.port }}
|
||||
{{- end }}
|
||||
{{- if .Values.s3.ingress.host }}
|
||||
host: {{ .Values.s3.ingress.host | quote }}
|
||||
|
||||
@@ -246,28 +246,3 @@ If allInOne is enabled, point to the all-in-one service; otherwise, point to the
|
||||
{{- end -}}
|
||||
{{- printf "%s%s.%s:%d" (include "seaweedfs.name" .) $serviceNameSuffix .Release.Namespace (int .Values.filer.port) -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Generate comma-separated list of master server addresses.
|
||||
Usage: {{ include "seaweedfs.masterServers" . }}
|
||||
Output example: ${SEAWEEDFS_FULLNAME}-master-0.${SEAWEEDFS_FULLNAME}-master.namespace:9333,${SEAWEEDFS_FULLNAME}-master-1...
|
||||
*/}}
|
||||
{{- define "seaweedfs.masterServers" -}}
|
||||
{{- $fullname := include "seaweedfs.name" . -}}
|
||||
{{- range $index := until (.Values.master.replicas | int) -}}
|
||||
{{- if $index }},{{ end -}}
|
||||
${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Generate master server argument value, using global.masterServer if set, otherwise the generated list.
|
||||
Usage: {{ include "seaweedfs.masterServerArg" . }}
|
||||
*/}}
|
||||
{{- define "seaweedfs.masterServerArg" -}}
|
||||
{{- if .Values.global.masterServer -}}
|
||||
{{- .Values.global.masterServer -}}
|
||||
{{- else -}}
|
||||
{{- include "seaweedfs.masterServers" . -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
@@ -1,32 +1,6 @@
|
||||
{{- /* Support bucket creation for both standalone filer.s3 and allInOne modes */}}
|
||||
{{- $createBuckets := list }}
|
||||
{{- $s3Enabled := false }}
|
||||
{{- $enableAuth := false }}
|
||||
{{- $existingConfigSecret := "" }}
|
||||
|
||||
{{- /* Check allInOne mode first */}}
|
||||
{{- if .Values.allInOne.enabled }}
|
||||
{{- if .Values.allInOne.s3.enabled }}
|
||||
{{- $s3Enabled = true }}
|
||||
{{- if .Values.allInOne.s3.createBuckets }}
|
||||
{{- $createBuckets = .Values.allInOne.s3.createBuckets }}
|
||||
{{- end }}
|
||||
{{- $enableAuth = or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth }}
|
||||
{{- $existingConfigSecret = or .Values.allInOne.s3.existingConfigSecret .Values.s3.existingConfigSecret .Values.filer.s3.existingConfigSecret }}
|
||||
{{- end }}
|
||||
{{- else if .Values.master.enabled }}
|
||||
{{- /* Check standalone filer.s3 mode */}}
|
||||
{{- if .Values.filer.s3.enabled }}
|
||||
{{- $s3Enabled = true }}
|
||||
{{- if .Values.filer.s3.createBuckets }}
|
||||
{{- $createBuckets = .Values.filer.s3.createBuckets }}
|
||||
{{- end }}
|
||||
{{- $enableAuth = .Values.filer.s3.enableAuth }}
|
||||
{{- $existingConfigSecret = .Values.filer.s3.existingConfigSecret }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if and $s3Enabled $createBuckets }}
|
||||
{{- if .Values.master.enabled }}
|
||||
{{- if .Values.filer.s3.enabled }}
|
||||
{{- if .Values.filer.s3.createBuckets }}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
@@ -58,9 +32,9 @@ spec:
|
||||
- name: WEED_CLUSTER_DEFAULT
|
||||
value: "sw"
|
||||
- name: WEED_CLUSTER_SW_MASTER
|
||||
value: {{ include "seaweedfs.cluster.masterAddress" . | quote }}
|
||||
value: "{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}:{{ .Values.master.port }}"
|
||||
- name: WEED_CLUSTER_SW_FILER
|
||||
value: {{ include "seaweedfs.cluster.filerAddress" . | quote }}
|
||||
value: "{{ template "seaweedfs.name" . }}-filer-client.{{ .Release.Namespace }}:{{ .Values.filer.port }}"
|
||||
- name: POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
@@ -97,29 +71,24 @@ spec:
|
||||
echo "Service at $url failed to become ready within 5 minutes"
|
||||
exit 1
|
||||
}
|
||||
{{- if .Values.allInOne.enabled }}
|
||||
wait_for_service "http://$WEED_CLUSTER_SW_MASTER{{ .Values.allInOne.readinessProbe.httpGet.path }}"
|
||||
wait_for_service "http://$WEED_CLUSTER_SW_FILER{{ .Values.filer.readinessProbe.httpGet.path }}"
|
||||
{{- else }}
|
||||
wait_for_service "http://$WEED_CLUSTER_SW_MASTER{{ .Values.master.readinessProbe.httpGet.path }}"
|
||||
wait_for_service "http://$WEED_CLUSTER_SW_FILER{{ .Values.filer.readinessProbe.httpGet.path }}"
|
||||
{{- end }}
|
||||
{{- range $createBuckets }}
|
||||
/bin/echo \
|
||||
"s3.bucket.create --name {{ .name }}" |\
|
||||
{{- range $reg, $props := $.Values.filer.s3.createBuckets }}
|
||||
exec /bin/echo \
|
||||
"s3.bucket.create --name {{ $props.name }}" |\
|
||||
/usr/bin/weed shell
|
||||
{{- end }}
|
||||
{{- range $createBuckets }}
|
||||
{{- if .anonymousRead }}
|
||||
/bin/echo \
|
||||
{{- range $reg, $props := $.Values.filer.s3.createBuckets }}
|
||||
{{- if $props.anonymousRead }}
|
||||
exec /bin/echo \
|
||||
"s3.configure --user anonymous \
|
||||
--buckets {{ .name }} \
|
||||
--buckets {{ $props.name }} \
|
||||
--actions Read \
|
||||
--apply true" |\
|
||||
/usr/bin/weed shell
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if $enableAuth }}
|
||||
{{- if .Values.filer.s3.enableAuth }}
|
||||
volumeMounts:
|
||||
- name: config-users
|
||||
mountPath: /etc/sw
|
||||
@@ -137,15 +106,17 @@ spec:
|
||||
{{- if .Values.filer.containerSecurityContext.enabled }}
|
||||
securityContext: {{- omit .Values.filer.containerSecurityContext "enabled" | toYaml | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $enableAuth }}
|
||||
{{- if .Values.filer.s3.enableAuth }}
|
||||
volumes:
|
||||
- name: config-users
|
||||
secret:
|
||||
defaultMode: 420
|
||||
{{- if $existingConfigSecret }}
|
||||
secretName: {{ $existingConfigSecret }}
|
||||
{{- if not (empty .Values.filer.s3.existingConfigSecret) }}
|
||||
secretName: {{ .Values.filer.s3.existingConfigSecret }}
|
||||
{{- else }}
|
||||
secretName: {{ template "seaweedfs.name" . }}-s3-secret
|
||||
secretName: seaweedfs-s3-secret
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}{{/** if .Values.filer.s3.enableAuth **/}}
|
||||
{{- end }}{{/** if .Values.master.enabled **/}}
|
||||
{{- end }}{{/** if .Values.filer.s3.enabled **/}}
|
||||
{{- end }}{{/** if .Values.filer.s3.createBuckets **/}}
|
||||
|
||||
@@ -196,7 +196,7 @@ spec:
|
||||
-minFreeSpacePercent={{ $volume.minFreeSpacePercent }} \
|
||||
-ip=${POD_NAME}.${SEAWEEDFS_FULLNAME}-{{ $volumeName }}.{{ $.Release.Namespace }} \
|
||||
-compactionMBps={{ $volume.compactionMBps }} \
|
||||
-master={{ include "seaweedfs.masterServerArg" $ }} \
|
||||
-mserver={{ if $.Values.global.masterServer }}{{ $.Values.global.masterServer}}{{ else }}{{ range $index := until ($.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }}{{ end }}
|
||||
{{- range $volume.extraArgs }}
|
||||
{{ . }} \
|
||||
{{- end }}
|
||||
|
||||
@@ -310,7 +310,7 @@ volume:
|
||||
# limit file size to avoid out of memory, default 256mb
|
||||
fileSizeLimitMB: null
|
||||
# minimum free disk space(in percents). If free disk space lower this value - all volumes marks as ReadOnly
|
||||
minFreeSpacePercent: 1
|
||||
minFreeSpacePercent: 7
|
||||
|
||||
# Custom command line arguments to add to the volume command
|
||||
# Example to fix IPv6 metrics connectivity issues:
|
||||
@@ -856,6 +856,8 @@ filer:
|
||||
port: 8333
|
||||
# add additional https port
|
||||
httpsPort: 0
|
||||
# allow empty folders
|
||||
allowEmptyFolder: false
|
||||
# Suffix of the host name, {bucket}.{domainName}
|
||||
domainName: ""
|
||||
# enable user & permission to s3 (need to inject to all services)
|
||||
@@ -883,6 +885,8 @@ s3:
|
||||
httpsPort: 0
|
||||
metricsPort: 9327
|
||||
loggingOverrideLevel: null
|
||||
# allow empty folders
|
||||
allowEmptyFolder: true
|
||||
# enable user & permission to s3 (need to inject to all services)
|
||||
enableAuth: false
|
||||
# set to the name of an existing kubernetes Secret with the s3 json config file
|
||||
@@ -1093,7 +1097,6 @@ allInOne:
|
||||
enabled: false
|
||||
imageOverride: null
|
||||
restartPolicy: Always
|
||||
replicas: 1 # Number of replicas (note: multiple replicas may require shared storage)
|
||||
|
||||
# Core configuration
|
||||
idleTimeout: 30 # Connection idle seconds
|
||||
@@ -1105,85 +1108,24 @@ allInOne:
|
||||
metricsIp: "" # Metrics listen IP. If empty, defaults to bindAddress
|
||||
loggingOverrideLevel: null # Override logging level
|
||||
|
||||
# Custom command line arguments to add to the server command
|
||||
# Example to fix IPv6 metrics connectivity issues:
|
||||
# extraArgs: ["-metricsIp", "0.0.0.0"]
|
||||
# Example with multiple args:
|
||||
# extraArgs: ["-customFlag", "value", "-anotherFlag"]
|
||||
extraArgs: []
|
||||
|
||||
# Update strategy configuration
|
||||
# type: Recreate or RollingUpdate
|
||||
# For single replica, Recreate is recommended to avoid data conflicts.
|
||||
# For multiple replicas with RollingUpdate, you MUST use shared storage
|
||||
# (e.g., data.type: persistentVolumeClaim with ReadWriteMany access mode)
|
||||
# to avoid data loss or inconsistency between pods.
|
||||
updateStrategy:
|
||||
type: Recreate
|
||||
|
||||
# S3 gateway configuration
|
||||
# Note: Most parameters below default to null, which means they inherit from
|
||||
# the global s3.* settings. Set explicit values here to override for allInOne only.
|
||||
# Service configuration
|
||||
s3:
|
||||
enabled: false # Whether to enable S3 gateway
|
||||
port: null # S3 gateway port (null inherits from s3.port)
|
||||
httpsPort: null # S3 gateway HTTPS port (null inherits from s3.httpsPort)
|
||||
domainName: null # Suffix of the host name (null inherits from s3.domainName)
|
||||
enableAuth: false # Enable user & permission to S3
|
||||
# Set to the name of an existing kubernetes Secret with the s3 json config file
|
||||
# should have a secret key called seaweedfs_s3_config with an inline json config
|
||||
existingConfigSecret: null
|
||||
auditLogConfig: null # S3 audit log configuration (null inherits from s3.auditLogConfig)
|
||||
# You may specify buckets to be created during the install process.
|
||||
# Buckets may be exposed publicly by setting `anonymousRead` to `true`
|
||||
# createBuckets:
|
||||
# - name: bucket-a
|
||||
# anonymousRead: true
|
||||
# - name: bucket-b
|
||||
# anonymousRead: false
|
||||
|
||||
# SFTP server configuration
|
||||
# Note: Most parameters below default to null, which means they inherit from
|
||||
# the global sftp.* settings. Set explicit values here to override for allInOne only.
|
||||
sftp:
|
||||
enabled: false # Whether to enable SFTP server
|
||||
port: null # SFTP port (null inherits from sftp.port)
|
||||
sshPrivateKey: null # Path to SSH private key (null inherits from sftp.sshPrivateKey)
|
||||
hostKeysFolder: null # Path to SSH host keys folder (null inherits from sftp.hostKeysFolder)
|
||||
authMethods: null # Comma-separated auth methods (null inherits from sftp.authMethods)
|
||||
maxAuthTries: null # Maximum authentication attempts (null inherits from sftp.maxAuthTries)
|
||||
bannerMessage: null # Banner message (null inherits from sftp.bannerMessage)
|
||||
loginGraceTime: null # Login grace time (null inherits from sftp.loginGraceTime)
|
||||
clientAliveInterval: null # Client keep-alive interval (null inherits from sftp.clientAliveInterval)
|
||||
clientAliveCountMax: null # Maximum missed keep-alive messages (null inherits from sftp.clientAliveCountMax)
|
||||
enableAuth: false # Enable SFTP authentication
|
||||
# Set to the name of an existing kubernetes Secret with the sftp json config file
|
||||
existingConfigSecret: null
|
||||
# Set to the name of an existing kubernetes Secret with the SSH keys
|
||||
existingSshConfigSecret: null
|
||||
|
||||
# Service settings
|
||||
service:
|
||||
annotations: {} # Annotations for the service
|
||||
type: ClusterIP # Service type (ClusterIP, NodePort, LoadBalancer)
|
||||
internalTrafficPolicy: Cluster # Internal traffic policy
|
||||
|
||||
# Note: For ingress in all-in-one mode, use the standard s3.ingress and
|
||||
# filer.ingress settings. The templates automatically detect all-in-one mode
|
||||
# and point to the correct service (seaweedfs-all-in-one instead of
|
||||
# seaweedfs-s3 or seaweedfs-filer).
|
||||
|
||||
# Storage configuration
|
||||
data:
|
||||
type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir", "existingClaim"
|
||||
type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir"
|
||||
hostPathPrefix: /mnt/data # Path prefix for hostPath volumes
|
||||
claimName: seaweedfs-data-pvc # Name of the PVC to use (for existingClaim type)
|
||||
size: null # Size of the PVC (null defaults to 10Gi for persistentVolumeClaim type)
|
||||
storageClass: null # Storage class for the PVC (null uses cluster default)
|
||||
# accessModes for the PVC. Default is ["ReadWriteOnce"].
|
||||
# For multi-replica deployments, use ["ReadWriteMany"] with a compatible storage class.
|
||||
accessModes: []
|
||||
annotations: {} # Annotations for the PVC
|
||||
claimName: seaweedfs-data-pvc # Name of the PVC to use
|
||||
size: "" # Size of the PVC
|
||||
storageClass: "" # Storage class for the PVC
|
||||
|
||||
# Health checks
|
||||
readinessProbe:
|
||||
@@ -1212,18 +1154,6 @@ allInOne:
|
||||
|
||||
# Additional resources
|
||||
extraEnvironmentVars: {} # Additional environment variables
|
||||
# Secret environment variables (for database credentials, etc.)
|
||||
# Example:
|
||||
# secretExtraEnvironmentVars:
|
||||
# WEED_POSTGRES_USERNAME:
|
||||
# secretKeyRef:
|
||||
# name: postgres-credentials
|
||||
# key: username
|
||||
# WEED_POSTGRES_PASSWORD:
|
||||
# secretKeyRef:
|
||||
# name: postgres-credentials
|
||||
# key: password
|
||||
secretExtraEnvironmentVars: {}
|
||||
extraVolumeMounts: "" # Additional volume mounts
|
||||
extraVolumes: "" # Additional volumes
|
||||
initContainers: "" # Init containers
|
||||
@@ -1243,7 +1173,7 @@ allInOne:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: seaweedfs-all-in-one
|
||||
app.kubernetes.io/component: master
|
||||
topologyKey: kubernetes.io/hostname
|
||||
|
||||
# Topology Spread Constraints Settings
|
||||
@@ -1251,16 +1181,16 @@ allInOne:
|
||||
# for a PodSpec. By Default no constraints are set.
|
||||
topologySpreadConstraints: ""
|
||||
|
||||
# Toleration Settings for pods
|
||||
# Toleration Settings for master pods
|
||||
# This should be a multi-line string matching the Toleration array
|
||||
# in a PodSpec.
|
||||
tolerations: ""
|
||||
|
||||
# nodeSelector labels for pod assignment, formatted as a muli-line string.
|
||||
# nodeSelector labels for master pod assignment, formatted as a muli-line string.
|
||||
# ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
|
||||
nodeSelector: ""
|
||||
|
||||
# Used to assign priority to pods
|
||||
# Used to assign priority to master pods
|
||||
# ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/
|
||||
priorityClassName: ""
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ These tests verify actual FileSystem operations against a running SeaweedFS inst
|
||||
weed master
|
||||
|
||||
# Terminal 2: Start volume server
|
||||
weed volume -master=localhost:9333
|
||||
weed volume -mserver=localhost:9333
|
||||
|
||||
# Terminal 3: Start filer
|
||||
weed filer -master=localhost:9333
|
||||
|
||||
@@ -32,7 +32,7 @@ services:
|
||||
- "18080:18080"
|
||||
command: >
|
||||
volume
|
||||
-master=seaweedfs-master:9333
|
||||
-mserver=seaweedfs-master:9333
|
||||
-port=8080
|
||||
-dir=/data
|
||||
-max=100
|
||||
|
||||
@@ -21,7 +21,7 @@ services:
|
||||
seaweedfs-volume:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
container_name: seaweedfs-volume
|
||||
command: volume -master=seaweedfs-master:9333 -ip=seaweedfs-volume -port=8080 -dir=/data
|
||||
command: volume -mserver=seaweedfs-master:9333 -ip=seaweedfs-volume -port=8080 -dir=/data
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
|
||||
@@ -21,7 +21,7 @@ services:
|
||||
seaweedfs-volume:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
container_name: seaweedfs-volume
|
||||
command: volume -master=seaweedfs-master:9333 -ip=seaweedfs-volume -port=8080 -dir=/data
|
||||
command: volume -mserver=seaweedfs-master:9333 -ip=seaweedfs-volume -port=8080 -dir=/data
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
|
||||
@@ -107,7 +107,7 @@ wait_for_service "Master" "http://localhost:9333/cluster/status"
|
||||
|
||||
# Start SeaweedFS Volume Server
|
||||
echo -e "${BLUE}💾 Starting SeaweedFS Volume Server...${NC}"
|
||||
./weed volume -master=localhost:9333 -port=8080 -dir=/tmp/seaweedfs-volume &
|
||||
./weed volume -mserver=localhost:9333 -port=8080 -dir=/tmp/seaweedfs-volume &
|
||||
VOLUME_PID=$!
|
||||
wait_for_service "Volume Server" "http://localhost:8080/status"
|
||||
|
||||
|
||||
@@ -431,7 +431,7 @@ func startSeaweedFSCluster(ctx context.Context, dataDir string) (*TestCluster, e
|
||||
"-port", port,
|
||||
"-dir", volumeDir,
|
||||
"-max", "10",
|
||||
"-master", "127.0.0.1:9333",
|
||||
"-mserver", "127.0.0.1:9333",
|
||||
"-ip", "127.0.0.1",
|
||||
"-dataCenter", "dc1",
|
||||
"-rack", rack,
|
||||
@@ -956,7 +956,7 @@ func startMultiDiskCluster(ctx context.Context, dataDir string) (*MultiDiskClust
|
||||
"-port", port,
|
||||
"-dir", strings.Join(diskDirs, ","),
|
||||
"-max", strings.Join(maxVolumes, ","),
|
||||
"-master", "127.0.0.1:9334",
|
||||
"-mserver", "127.0.0.1:9334",
|
||||
"-ip", "127.0.0.1",
|
||||
"-dataCenter", "dc1",
|
||||
"-rack", rack,
|
||||
|
||||
@@ -147,7 +147,7 @@ services:
|
||||
- "8888:8888"
|
||||
- "8333:8333"
|
||||
- "18888:18888"
|
||||
command: "server -ip=seaweedfs -filer -master.volumeSizeLimitMB=16 -volume.max=0 -volume -volume.preStopSeconds=1 -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8333 -s3.allowDeleteBucketNotEmpty=false"
|
||||
command: "server -ip=seaweedfs -filer -master.volumeSizeLimitMB=16 -volume.max=0 -volume -volume.preStopSeconds=1 -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8333 -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=false"
|
||||
volumes:
|
||||
- ./s3.json:/etc/seaweedfs/s3.json
|
||||
- ./filer.toml:/etc/seaweedfs/filer.toml
|
||||
|
||||
@@ -116,7 +116,7 @@ services:
|
||||
- WEED_FOUNDATIONDB_MAX_RETRY_DELAY
|
||||
- WEED_MASTER_VOLUME_GROWTH_COPY_1=1
|
||||
- WEED_MASTER_VOLUME_GROWTH_COPY_OTHER=1
|
||||
command: "weed server -ip=seaweedfs -filer -master.volumeSizeLimitMB=16 -volume.max=0 -volume -volume.preStopSeconds=1 -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8333 -s3.allowDeleteBucketNotEmpty=false"
|
||||
command: "weed server -ip=seaweedfs -filer -master.volumeSizeLimitMB=16 -volume.max=0 -volume -volume.preStopSeconds=1 -s3 -s3.config=/etc/seaweedfs/s3.json -s3.port=8333 -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=false"
|
||||
|
||||
configs:
|
||||
fdb.cluster:
|
||||
|
||||
@@ -194,7 +194,7 @@ func (f *FuseTestFramework) startMaster(config *TestConfig) error {
|
||||
func (f *FuseTestFramework) startVolumeServers(config *TestConfig) error {
|
||||
args := []string{
|
||||
"volume",
|
||||
"-master=" + f.masterAddr,
|
||||
"-mserver=" + f.masterAddr,
|
||||
"-ip=127.0.0.1",
|
||||
"-port=18080",
|
||||
"-dir=" + filepath.Join(f.dataDir, "volume"),
|
||||
|
||||
@@ -27,7 +27,7 @@ services:
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "18080:18080"
|
||||
command: "volume -master=seaweedfs-master:9333 -ip=seaweedfs-volume -ip.bind=0.0.0.0 -port=8080 -port.grpc=18080 -publicUrl=seaweedfs-volume:8080 -max=100 -dir=/data -preStopSeconds=1"
|
||||
command: "volume -mserver=seaweedfs-master:9333 -ip=seaweedfs-volume -ip.bind=0.0.0.0 -port=8080 -port.grpc=18080 -publicUrl=seaweedfs-volume:8080 -max=100 -dir=/data -preStopSeconds=1"
|
||||
volumes:
|
||||
- seaweedfs-volume-data:/data
|
||||
depends_on:
|
||||
|
||||
@@ -111,7 +111,7 @@ services:
|
||||
- "18080:18080" # gRPC port
|
||||
command:
|
||||
- volume
|
||||
- -master=seaweedfs-master:9333
|
||||
- -mserver=seaweedfs-master:9333
|
||||
- -ip=seaweedfs-volume
|
||||
- -port=8080
|
||||
- -port.grpc=18080
|
||||
|
||||
+2
-2
@@ -141,7 +141,7 @@ require (
|
||||
github.com/karlseguin/ccache/v2 v2.0.8 // indirect
|
||||
github.com/klauspost/compress v1.18.2 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/klauspost/reedsolomon v1.12.6 // indirect
|
||||
github.com/klauspost/reedsolomon v1.12.5 // indirect
|
||||
github.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988 // indirect
|
||||
github.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
@@ -234,7 +234,7 @@ require (
|
||||
golang.org/x/image v0.33.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
|
||||
+4
-4
@@ -433,8 +433,8 @@ github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uq
|
||||
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/klauspost/reedsolomon v1.12.6 h1:8pqE9aECQG/ZFitiUD1xK/E83zwosBAZtE3UbuZM8TQ=
|
||||
github.com/klauspost/reedsolomon v1.12.6/go.mod h1:ggJT9lc71Vu+cSOPBlxGvBN6TfAS77qB4fp8vJ05NSA=
|
||||
github.com/klauspost/reedsolomon v1.12.5 h1:4cJuyH926If33BeDgiZpI5OU0pE+wUHZvMSyNGqN73Y=
|
||||
github.com/klauspost/reedsolomon v1.12.5/go.mod h1:LkXRjLYGM8K/iQfujYnaPeDmhZLqkrGUyG9p7zs5L68=
|
||||
github.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988 h1:CjEMN21Xkr9+zwPmZPaJJw+apzVbjGL5uK/6g9Q2jGU=
|
||||
github.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988/go.mod h1:/agobYum3uo/8V6yPVnq+R82pyVGCeuWW5arT4Txn8A=
|
||||
github.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6 h1:FHVoZMOVRA+6/y4yRlbiR3WvsrOcKBd/f64H7YiWR2U=
|
||||
@@ -841,8 +841,8 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
||||
@@ -113,7 +113,7 @@ services:
|
||||
- "18080:18080"
|
||||
command:
|
||||
- volume
|
||||
- -master=seaweedfs-master:9333
|
||||
- -mserver=seaweedfs-master:9333
|
||||
- -ip=seaweedfs-volume
|
||||
- -port=8080
|
||||
- -port.grpc=18080
|
||||
|
||||
@@ -64,7 +64,7 @@ services:
|
||||
- "8080:8080"
|
||||
command:
|
||||
- volume
|
||||
- -master=seaweedfs-master:9333
|
||||
- -mserver=seaweedfs-master:9333
|
||||
- -ip=seaweedfs-volume
|
||||
- -publicUrl=seaweedfs-volume:8080
|
||||
depends_on:
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ weed server -mq.broker -mq.agent -filer -volume -master.peers=none
|
||||
|
||||
# Or start components separately
|
||||
weed master -peers=none
|
||||
weed volume -master=localhost:9333
|
||||
weed volume -mserver=localhost:9333
|
||||
weed filer -master=localhost:9333
|
||||
weed mq.broker -filer=localhost:8888
|
||||
weed mq.agent -brokers=localhost:17777
|
||||
|
||||
@@ -30,6 +30,7 @@ services:
|
||||
- -s3=true
|
||||
- -s3.port=8333
|
||||
- -webdav=false
|
||||
- -s3.allowEmptyFolder=false
|
||||
- -mq.broker=true
|
||||
- -mq.agent=true
|
||||
- -ip=seaweedfs
|
||||
|
||||
@@ -74,7 +74,7 @@ start-seaweedfs: check-binary
|
||||
@sleep 3
|
||||
|
||||
# Start volume server
|
||||
@nohup $(SEAWEEDFS_BINARY) volume -port=$(VOLUME_PORT) -master=127.0.0.1:$(MASTER_PORT) -dir=/tmp/seaweedfs-test-copying-volume -ip=127.0.0.1 > /tmp/seaweedfs-volume.log 2>&1 &
|
||||
@nohup $(SEAWEEDFS_BINARY) volume -port=$(VOLUME_PORT) -mserver=127.0.0.1:$(MASTER_PORT) -dir=/tmp/seaweedfs-test-copying-volume -ip=127.0.0.1 > /tmp/seaweedfs-volume.log 2>&1 &
|
||||
@sleep 3
|
||||
|
||||
# Start filer server (using standard SeaweedFS gRPC port convention: HTTP port + 10000)
|
||||
|
||||
@@ -79,11 +79,12 @@ start-server: check-deps
|
||||
@echo "🔍 DEBUG: Creating volume directory..."
|
||||
@mkdir -p ./test-volume-data
|
||||
@echo "🔍 DEBUG: Launching SeaweedFS server in background..."
|
||||
@echo "🔍 DEBUG: Command: $(WEED_BINARY) server -debug -s3 -s3.port=$(S3_PORT) -s3.allowDeleteBucketNotEmpty=true -s3.config=../../../docker/compose/s3.json -filer -filer.maxMB=64 -master.volumeSizeLimitMB=50 -volume.max=100 -dir=./test-volume-data -volume.preStopSeconds=1 -metricsPort=9324"
|
||||
@echo "🔍 DEBUG: Command: $(WEED_BINARY) server -debug -s3 -s3.port=$(S3_PORT) -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=true -s3.config=../../../docker/compose/s3.json -filer -filer.maxMB=64 -master.volumeSizeLimitMB=50 -volume.max=100 -dir=./test-volume-data -volume.preStopSeconds=1 -metricsPort=9324"
|
||||
@$(WEED_BINARY) server \
|
||||
-debug \
|
||||
-s3 \
|
||||
-s3.port=$(S3_PORT) \
|
||||
-s3.allowEmptyFolder=false \
|
||||
-s3.allowDeleteBucketNotEmpty=true \
|
||||
-s3.config=../../../docker/compose/s3.json \
|
||||
-filer \
|
||||
|
||||
@@ -75,7 +75,7 @@ start-services: ## Start SeaweedFS services for testing
|
||||
-dataCenter=dc1 -rack=rack1 \
|
||||
-dir=test-volume-data \
|
||||
-max=100 \
|
||||
-master=localhost:$(MASTER_PORT) > weed-volume.log 2>&1 & \
|
||||
-mserver=localhost:$(MASTER_PORT) > weed-volume.log 2>&1 & \
|
||||
echo $$! > $(VOLUME_PID_FILE)
|
||||
|
||||
@echo "Waiting for volume server to be ready..."
|
||||
|
||||
@@ -21,7 +21,7 @@ services:
|
||||
seaweedfs-volume:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
container_name: seaweedfs-volume-test
|
||||
command: volume -dir=/data -port=8083 -master=seaweedfs-master:9333
|
||||
command: volume -dir=/data -port=8083 -mserver=seaweedfs-master:9333
|
||||
ports:
|
||||
- "8083:8083"
|
||||
volumes:
|
||||
|
||||
@@ -51,7 +51,7 @@ services:
|
||||
ports:
|
||||
- "8083:8083"
|
||||
- "18083:18083"
|
||||
command: "volume -ip=weed-volume -port=8083 -dir=/data -master=weed-master:9333 -dataCenter=dc1 -rack=rack1"
|
||||
command: "volume -ip=weed-volume -port=8083 -dir=/data -mserver=weed-master:9333 -dataCenter=dc1 -rack=rack1"
|
||||
volumes:
|
||||
- volume-data:/data
|
||||
networks:
|
||||
|
||||
@@ -134,7 +134,7 @@ start-seaweedfs-ci: check-binary
|
||||
|
||||
# Start volume server with master HTTP port and increased capacity
|
||||
@echo "Starting volume server..."
|
||||
@nohup $(SEAWEEDFS_BINARY) volume -port=$(VOLUME_PORT) -master=127.0.0.1:$(MASTER_PORT) -dir=/tmp/seaweedfs-test-parquet-volume -max=$(VOLUME_MAX_COUNT) -ip=127.0.0.1 -preStopSeconds=1 > /tmp/seaweedfs-parquet-volume.log 2>&1 &
|
||||
@nohup $(SEAWEEDFS_BINARY) volume -port=$(VOLUME_PORT) -mserver=127.0.0.1:$(MASTER_PORT) -dir=/tmp/seaweedfs-test-parquet-volume -max=$(VOLUME_MAX_COUNT) -ip=127.0.0.1 -preStopSeconds=1 > /tmp/seaweedfs-parquet-volume.log 2>&1 &
|
||||
@sleep 5
|
||||
|
||||
# Start filer server with embedded S3
|
||||
|
||||
@@ -81,11 +81,12 @@ start-server: check-deps
|
||||
@echo "🔍 DEBUG: Creating volume directory..."
|
||||
@mkdir -p ./test-volume-data
|
||||
@echo "🔍 DEBUG: Launching SeaweedFS server in background..."
|
||||
@echo "🔍 DEBUG: Command: $(WEED_BINARY) server -debug -s3 -s3.port=$(S3_PORT) -s3.allowDeleteBucketNotEmpty=true -s3.config=../../../docker/compose/s3.json -filer -filer.maxMB=64 -master.volumeSizeLimitMB=50 -volume.max=100 -dir=./test-volume-data -volume.preStopSeconds=1 -metricsPort=9324"
|
||||
@echo "🔍 DEBUG: Command: $(WEED_BINARY) server -debug -s3 -s3.port=$(S3_PORT) -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=true -s3.config=../../../docker/compose/s3.json -filer -filer.maxMB=64 -master.volumeSizeLimitMB=50 -volume.max=100 -dir=./test-volume-data -volume.preStopSeconds=1 -metricsPort=9324"
|
||||
@$(WEED_BINARY) server \
|
||||
-debug \
|
||||
-s3 \
|
||||
-s3.port=$(S3_PORT) \
|
||||
-s3.allowEmptyFolder=false \
|
||||
-s3.allowDeleteBucketNotEmpty=true \
|
||||
-s3.config=../../../docker/compose/s3.json \
|
||||
-filer \
|
||||
|
||||
@@ -236,7 +236,7 @@ func TestObjectLockHeadersNonVersionedBucket(t *testing.T) {
|
||||
bucketName := getNewBucketName()
|
||||
|
||||
// Create regular bucket without object lock/versioning
|
||||
createBucketWithoutObjectLock(t, client, bucketName)
|
||||
createBucket(t, client, bucketName)
|
||||
defer deleteBucket(t, client, bucketName)
|
||||
|
||||
key := "test-non-versioned"
|
||||
|
||||
@@ -69,19 +69,8 @@ func getNewBucketName() string {
|
||||
return fmt.Sprintf("%s%d", defaultConfig.BucketPrefix, timestamp)
|
||||
}
|
||||
|
||||
// createBucket creates a new bucket for testing with Object Lock enabled
|
||||
// Object Lock is required for retention and legal hold functionality per AWS S3 specification
|
||||
// createBucket creates a new bucket for testing
|
||||
func createBucket(t *testing.T, client *s3.Client, bucketName string) {
|
||||
_, err := client.CreateBucket(context.TODO(), &s3.CreateBucketInput{
|
||||
Bucket: aws.String(bucketName),
|
||||
ObjectLockEnabledForBucket: aws.Bool(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// createBucketWithoutObjectLock creates a new bucket without Object Lock enabled
|
||||
// Use this only for tests that specifically need to verify non-Object-Lock bucket behavior
|
||||
func createBucketWithoutObjectLock(t *testing.T, client *s3.Client, bucketName string) {
|
||||
_, err := client.CreateBucket(context.TODO(), &s3.CreateBucketInput{
|
||||
Bucket: aws.String(bucketName),
|
||||
})
|
||||
|
||||
@@ -102,7 +102,7 @@ start-seaweedfs: check-binary
|
||||
@sleep 3
|
||||
|
||||
# Start volume server with master HTTP port and increased capacity
|
||||
@nohup $(SEAWEEDFS_BINARY) volume -port=$(VOLUME_PORT) -master=127.0.0.1:$(MASTER_PORT) -dir=/tmp/seaweedfs-test-sse-volume -max=$(VOLUME_MAX_COUNT) -ip=127.0.0.1 > /tmp/seaweedfs-sse-volume.log 2>&1 &
|
||||
@nohup $(SEAWEEDFS_BINARY) volume -port=$(VOLUME_PORT) -mserver=127.0.0.1:$(MASTER_PORT) -dir=/tmp/seaweedfs-test-sse-volume -max=$(VOLUME_MAX_COUNT) -ip=127.0.0.1 > /tmp/seaweedfs-sse-volume.log 2>&1 &
|
||||
@sleep 5
|
||||
|
||||
# Start filer server (using standard SeaweedFS gRPC port convention: HTTP port + 10000)
|
||||
@@ -359,7 +359,7 @@ start-seaweedfs-ci: check-binary
|
||||
|
||||
# Start volume server with master HTTP port and increased capacity
|
||||
@echo "Starting volume server..."
|
||||
@nohup $(SEAWEEDFS_BINARY) volume -port=$(VOLUME_PORT) -master=127.0.0.1:$(MASTER_PORT) -dir=/tmp/seaweedfs-test-sse-volume -max=$(VOLUME_MAX_COUNT) -ip=127.0.0.1 > /tmp/seaweedfs-sse-volume.log 2>&1 &
|
||||
@nohup $(SEAWEEDFS_BINARY) volume -port=$(VOLUME_PORT) -mserver=127.0.0.1:$(MASTER_PORT) -dir=/tmp/seaweedfs-test-sse-volume -max=$(VOLUME_MAX_COUNT) -ip=127.0.0.1 > /tmp/seaweedfs-sse-volume.log 2>&1 &
|
||||
@sleep 5
|
||||
|
||||
# Create S3 JSON configuration with KMS (Local provider) and basic identity for embedded S3
|
||||
|
||||
@@ -50,7 +50,7 @@ services:
|
||||
- "8080:8080"
|
||||
command:
|
||||
- volume
|
||||
- -master=seaweedfs-master:9333
|
||||
- -mserver=seaweedfs-master:9333
|
||||
- -port=8080
|
||||
- -ip=seaweedfs-volume
|
||||
- -publicUrl=seaweedfs-volume:8080
|
||||
|
||||
@@ -77,7 +77,7 @@ start-server: check-deps
|
||||
@echo "🔍 DEBUG: Creating volume directory..."
|
||||
@mkdir -p ./test-volume-data
|
||||
@echo "🔍 DEBUG: Launching SeaweedFS server in background..."
|
||||
@echo "🔍 DEBUG: Command: $(WEED_BINARY) server -filer -filer.maxMB=64 -s3 -ip.bind 0.0.0.0 -dir=./test-volume-data -master.raftHashicorp -master.electionTimeout 1s -master.volumeSizeLimitMB=100 -volume.max=100 -volume.preStopSeconds=1 -master.port=$(MASTER_PORT) -volume.port=$(VOLUME_PORT) -filer.port=$(FILER_PORT) -s3.port=$(S3_PORT) -metricsPort=9329 -s3.allowDeleteBucketNotEmpty=true -s3.config=../../../docker/compose/s3.json -master.peers=none"
|
||||
@echo "🔍 DEBUG: Command: $(WEED_BINARY) server -filer -filer.maxMB=64 -s3 -ip.bind 0.0.0.0 -dir=./test-volume-data -master.raftHashicorp -master.electionTimeout 1s -master.volumeSizeLimitMB=100 -volume.max=100 -volume.preStopSeconds=1 -master.port=$(MASTER_PORT) -volume.port=$(VOLUME_PORT) -filer.port=$(FILER_PORT) -s3.port=$(S3_PORT) -metricsPort=9329 -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=true -s3.config=../../../docker/compose/s3.json -master.peers=none"
|
||||
@$(WEED_BINARY) server \
|
||||
-filer \
|
||||
-filer.maxMB=64 \
|
||||
@@ -94,6 +94,7 @@ start-server: check-deps
|
||||
-filer.port=$(FILER_PORT) \
|
||||
-s3.port=$(S3_PORT) \
|
||||
-metricsPort=9329 \
|
||||
-s3.allowEmptyFolder=false \
|
||||
-s3.allowDeleteBucketNotEmpty=true \
|
||||
-s3.config=../../../docker/compose/s3.json \
|
||||
-master.peers=none \
|
||||
|
||||
@@ -81,11 +81,12 @@ start-server: check-deps
|
||||
@echo "🔍 DEBUG: Creating volume directory..."
|
||||
@mkdir -p ./test-volume-data
|
||||
@echo "🔍 DEBUG: Launching SeaweedFS server in background..."
|
||||
@echo "🔍 DEBUG: Command: $(WEED_BINARY) server -debug -s3 -s3.port=$(S3_PORT) -s3.allowDeleteBucketNotEmpty=true -s3.config=../../../docker/compose/s3.json -filer -filer.maxMB=64 -master.volumeSizeLimitMB=50 -volume.max=100 -dir=./test-volume-data -volume.preStopSeconds=1 -metricsPort=9324"
|
||||
@echo "🔍 DEBUG: Command: $(WEED_BINARY) server -debug -s3 -s3.port=$(S3_PORT) -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=true -s3.config=../../../docker/compose/s3.json -filer -filer.maxMB=64 -master.volumeSizeLimitMB=50 -volume.max=100 -dir=./test-volume-data -volume.preStopSeconds=1 -metricsPort=9324"
|
||||
@$(WEED_BINARY) server \
|
||||
-debug \
|
||||
-s3 \
|
||||
-s3.port=$(S3_PORT) \
|
||||
-s3.allowEmptyFolder=false \
|
||||
-s3.allowDeleteBucketNotEmpty=true \
|
||||
-s3.config=../../../docker/compose/s3.json \
|
||||
-filer \
|
||||
@@ -221,7 +222,7 @@ test-with-server: start-server
|
||||
test-versioning-with-configs: check-deps
|
||||
@echo "Testing with different S3 configurations..."
|
||||
@echo "Testing with empty folder allowed..."
|
||||
@$(WEED_BINARY) server -s3 -s3.port=$(S3_PORT) -filer -master.volumeSizeLimitMB=100 -volume.max=100 > weed-test-config1.log 2>&1 & echo $$! > weed-config1.pid
|
||||
@$(WEED_BINARY) server -s3 -s3.port=$(S3_PORT) -s3.allowEmptyFolder=true -filer -master.volumeSizeLimitMB=100 -volume.max=100 > weed-test-config1.log 2>&1 & echo $$! > weed-config1.pid
|
||||
@sleep 5
|
||||
@go test -v -timeout=5m -run "TestVersioningBasicWorkflow" . || true
|
||||
@if [ -f weed-config1.pid ]; then kill -TERM $$(cat weed-config1.pid) 2>/dev/null || true; rm -f weed-config1.pid; fi
|
||||
@@ -267,6 +268,7 @@ debug-server:
|
||||
-debug \
|
||||
-s3 \
|
||||
-s3.port=$(S3_PORT) \
|
||||
-s3.allowEmptyFolder=false \
|
||||
-s3.allowDeleteBucketNotEmpty=true \
|
||||
-s3.config=../../../docker/compose/s3.json \
|
||||
-filer \
|
||||
@@ -315,6 +317,7 @@ start-server-simple: check-deps
|
||||
-debug \
|
||||
-s3 \
|
||||
-s3.port=$(S3_PORT) \
|
||||
-s3.allowEmptyFolder=false \
|
||||
-s3.allowDeleteBucketNotEmpty=true \
|
||||
-s3.config=../../../docker/compose/s3.json \
|
||||
-filer \
|
||||
|
||||
@@ -268,7 +268,7 @@ func (f *SftpTestFramework) startMaster(config *TestConfig) error {
|
||||
func (f *SftpTestFramework) startVolumeServer(config *TestConfig) error {
|
||||
args := []string{
|
||||
"volume",
|
||||
"-master=" + f.masterAddr,
|
||||
"-mserver=" + f.masterAddr,
|
||||
"-ip=127.0.0.1",
|
||||
"-port=18080",
|
||||
"-dir=" + filepath.Join(f.dataDir, "volume"),
|
||||
|
||||
@@ -121,11 +121,8 @@ func init() {
|
||||
filerS3Options.tlsPrivateKey = cmdFiler.Flag.String("s3.key.file", "", "path to the TLS private key file")
|
||||
filerS3Options.tlsCertificate = cmdFiler.Flag.String("s3.cert.file", "", "path to the TLS certificate file")
|
||||
filerS3Options.config = cmdFiler.Flag.String("s3.config", "", "path to the config file")
|
||||
filerS3Options.iamConfig = cmdFiler.Flag.String("s3.iam.config", "", "path to the advanced IAM config file")
|
||||
filerS3Options.auditLogConfig = cmdFiler.Flag.String("s3.auditLogConfig", "", "path to the audit log config file")
|
||||
filerS3Options.metricsHttpPort = cmdFiler.Flag.Int("s3.metricsPort", 0, "Prometheus metrics listen port")
|
||||
filerS3Options.metricsHttpIp = cmdFiler.Flag.String("s3.metricsIp", "", "metrics listen ip. If empty, default to same as -s3.ip.bind option.")
|
||||
cmdFiler.Flag.Bool("s3.allowEmptyFolder", true, "deprecated, ignored. Empty folder cleanup is now automatic.")
|
||||
filerS3Options.allowEmptyFolder = cmdFiler.Flag.Bool("s3.allowEmptyFolder", true, "allow empty folders")
|
||||
filerS3Options.allowDeleteBucketNotEmpty = cmdFiler.Flag.Bool("s3.allowDeleteBucketNotEmpty", true, "allow recursive deleting all entries along with bucket")
|
||||
filerS3Options.localSocket = cmdFiler.Flag.String("s3.localSocket", "", "default to /tmp/seaweedfs-s3-<port>.sock")
|
||||
filerS3Options.tlsCACertificate = cmdFiler.Flag.String("s3.cacert.file", "", "path to the TLS CA certificate file")
|
||||
@@ -232,10 +229,6 @@ func runFiler(cmd *Command, args []string) bool {
|
||||
if *f.dataCenter != "" && *filerS3Options.dataCenter == "" {
|
||||
filerS3Options.dataCenter = f.dataCenter
|
||||
}
|
||||
// Set S3 metrics IP based on bind IP if not explicitly set
|
||||
if *filerS3Options.metricsHttpIp == "" {
|
||||
*filerS3Options.metricsHttpIp = *filerS3Options.bindIp
|
||||
}
|
||||
go func(delay time.Duration) {
|
||||
time.Sleep(delay * time.Second)
|
||||
filerS3Options.startS3Server()
|
||||
|
||||
+3
-1
@@ -49,6 +49,7 @@ type S3Options struct {
|
||||
tlsVerifyClientCert *bool
|
||||
metricsHttpPort *int
|
||||
metricsHttpIp *string
|
||||
allowEmptyFolder *bool
|
||||
allowDeleteBucketNotEmpty *bool
|
||||
auditLogConfig *string
|
||||
localFilerSocket *string
|
||||
@@ -79,7 +80,7 @@ func init() {
|
||||
s3StandaloneOptions.tlsVerifyClientCert = cmdS3.Flag.Bool("tlsVerifyClientCert", false, "whether to verify the client's certificate")
|
||||
s3StandaloneOptions.metricsHttpPort = cmdS3.Flag.Int("metricsPort", 0, "Prometheus metrics listen port")
|
||||
s3StandaloneOptions.metricsHttpIp = cmdS3.Flag.String("metricsIp", "", "metrics listen ip. If empty, default to same as -ip.bind option.")
|
||||
cmdS3.Flag.Bool("allowEmptyFolder", true, "deprecated, ignored. Empty folder cleanup is now automatic.")
|
||||
s3StandaloneOptions.allowEmptyFolder = cmdS3.Flag.Bool("allowEmptyFolder", true, "allow empty folders")
|
||||
s3StandaloneOptions.allowDeleteBucketNotEmpty = cmdS3.Flag.Bool("allowDeleteBucketNotEmpty", true, "allow recursive deleting all entries along with bucket")
|
||||
s3StandaloneOptions.localFilerSocket = cmdS3.Flag.String("localFilerSocket", "", "local filer socket path")
|
||||
s3StandaloneOptions.localSocket = cmdS3.Flag.String("localSocket", "", "default to /tmp/seaweedfs-s3-<port>.sock")
|
||||
@@ -272,6 +273,7 @@ func (s3opt *S3Options) startS3Server() bool {
|
||||
AllowedOrigins: strings.Split(*s3opt.allowedOrigins, ","),
|
||||
BucketsPath: filerBucketsPath,
|
||||
GrpcDialOption: grpcDialOption,
|
||||
AllowEmptyFolder: *s3opt.allowEmptyFolder,
|
||||
AllowDeleteBucketNotEmpty: *s3opt.allowDeleteBucketNotEmpty,
|
||||
LocalFilerSocket: localFilerSocket,
|
||||
DataCenter: *s3opt.dataCenter,
|
||||
|
||||
@@ -63,9 +63,9 @@ port = 3306
|
||||
username = "root"
|
||||
password = ""
|
||||
database = "" # create or use an existing database
|
||||
connection_max_idle = 10
|
||||
connection_max_open = 50
|
||||
connection_max_lifetime_seconds = 300
|
||||
connection_max_idle = 2
|
||||
connection_max_open = 100
|
||||
connection_max_lifetime_seconds = 0
|
||||
interpolateParams = false
|
||||
# if insert/upsert failing, you can disable upsert or update query syntax to match your RDBMS syntax:
|
||||
enableUpsert = true
|
||||
@@ -87,9 +87,9 @@ port = 3306
|
||||
username = "root"
|
||||
password = ""
|
||||
database = "" # create or use an existing database
|
||||
connection_max_idle = 10
|
||||
connection_max_open = 50
|
||||
connection_max_lifetime_seconds = 300
|
||||
connection_max_idle = 2
|
||||
connection_max_open = 100
|
||||
connection_max_lifetime_seconds = 0
|
||||
interpolateParams = false
|
||||
# if insert/upsert failing, you can disable upsert or update query syntax to match your RDBMS syntax:
|
||||
enableUpsert = true
|
||||
@@ -117,9 +117,9 @@ sslmode = "disable"
|
||||
# sslkey = "/path/to/client.key" # client private key file
|
||||
# sslrootcert = "/path/to/ca.crt" # CA certificate file
|
||||
# sslcrl = "/path/to/client.crl" # Certificate Revocation List (CRL) (optional)
|
||||
connection_max_idle = 10
|
||||
connection_max_open = 50
|
||||
connection_max_lifetime_seconds = 300
|
||||
connection_max_idle = 100
|
||||
connection_max_open = 100
|
||||
connection_max_lifetime_seconds = 0
|
||||
# Set to true when using PgBouncer connection pooler
|
||||
pgbouncer_compatible = false
|
||||
# if insert/upsert failing, you can disable upsert or update query syntax to match your RDBMS syntax:
|
||||
@@ -156,9 +156,9 @@ sslmode = "disable"
|
||||
# sslkey = "/path/to/client.key" # client private key file
|
||||
# sslrootcert = "/path/to/ca.crt" # CA certificate file
|
||||
# sslcrl = "/path/to/client.crl" # Certificate Revocation List (CRL) (optional)
|
||||
connection_max_idle = 10
|
||||
connection_max_open = 50
|
||||
connection_max_lifetime_seconds = 300
|
||||
connection_max_idle = 100
|
||||
connection_max_open = 100
|
||||
connection_max_lifetime_seconds = 0
|
||||
# Set to true when using PgBouncer connection pooler
|
||||
pgbouncer_compatible = false
|
||||
# if insert/upsert failing, you can disable upsert or update query syntax to match your RDBMS syntax:
|
||||
|
||||
@@ -52,20 +52,3 @@ enabled = false
|
||||
# create binding myexchange => myqueue
|
||||
topic_url = "rabbit://myexchange"
|
||||
sub_url = "rabbit://myqueue"
|
||||
|
||||
[notification.webhook]
|
||||
# Send file system events to HTTP webhook endpoints (push model)
|
||||
# BEST FOR: Low to moderate traffic (< 100 events/second sustained)
|
||||
# FOR HIGH TRAFFIC: Consider using Kafka, SQS, or pull-based event logs instead
|
||||
# Documentation: https://github.com/seaweedfs/seaweedfs/wiki/Filer-Notification-Webhook
|
||||
enabled = false
|
||||
endpoint = "https://your-server.com/webhook" # required: HTTP endpoint URL
|
||||
bearer_token = "" # optional: bearer token for authentication
|
||||
timeout_seconds = 10 # optional: HTTP timeout (default: 10, range: 1-300)
|
||||
max_retries = 3 # optional: retry attempts (default: 3, range: 0-10)
|
||||
backoff_seconds = 3 # optional: initial backoff delay (default: 3, range: 1-60)
|
||||
max_backoff_seconds = 30 # optional: max backoff delay (default: 30, range: backoff_seconds-300)
|
||||
workers = 5 # optional: concurrent workers (default: 5, range: 1-100)
|
||||
buffer_size = 10000 # optional: event buffer size (default: 10000, range: 100-1000000)
|
||||
# event_types = ["create", "update", "delete", "rename"] # optional: filter by event types (default: all)
|
||||
# path_prefixes = ["/important", "/data"] # optional: filter by path prefixes (default: all)
|
||||
|
||||
@@ -166,7 +166,7 @@ func init() {
|
||||
s3Options.config = cmdServer.Flag.String("s3.config", "", "path to the config file")
|
||||
s3Options.iamConfig = cmdServer.Flag.String("s3.iam.config", "", "path to the advanced IAM config file for S3. Overrides -iam.config if both are provided.")
|
||||
s3Options.auditLogConfig = cmdServer.Flag.String("s3.auditLogConfig", "", "path to the audit log config file")
|
||||
cmdServer.Flag.Bool("s3.allowEmptyFolder", true, "deprecated, ignored. Empty folder cleanup is now automatic.")
|
||||
s3Options.allowEmptyFolder = cmdServer.Flag.Bool("s3.allowEmptyFolder", true, "allow empty folders")
|
||||
s3Options.allowDeleteBucketNotEmpty = cmdServer.Flag.Bool("s3.allowDeleteBucketNotEmpty", true, "allow recursive deleting all entries along with bucket")
|
||||
s3Options.localSocket = cmdServer.Flag.String("s3.localSocket", "", "default to /tmp/seaweedfs-s3-<port>.sock")
|
||||
s3Options.bindIp = cmdServer.Flag.String("s3.ip.bind", "", "ip address to bind to. If empty, default to same as -ip.bind option.")
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/sftpd"
|
||||
stats_collect "github.com/seaweedfs/seaweedfs/weed/stats"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/grace"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -149,9 +148,6 @@ func (sftpOpt *SftpOptions) startSftpServer() bool {
|
||||
UserStoreFile: *sftpOpt.userStoreFile,
|
||||
})
|
||||
|
||||
// Register reload hook for HUP signal
|
||||
grace.OnReload(service.Reload)
|
||||
|
||||
// Set up Unix socket if on non-Windows platforms
|
||||
if runtime.GOOS != "windows" {
|
||||
localSocket := *sftpOpt.localSocket
|
||||
|
||||
@@ -186,22 +186,14 @@ func (p *OIDCProvider) Authenticate(ctx context.Context, token string) (*provide
|
||||
attributes["roles"] = strings.Join(roles, ",")
|
||||
}
|
||||
|
||||
identity := &providers.ExternalIdentity{
|
||||
return &providers.ExternalIdentity{
|
||||
UserID: claims.Subject,
|
||||
Email: email,
|
||||
DisplayName: displayName,
|
||||
Groups: groups,
|
||||
Attributes: attributes,
|
||||
Provider: p.name,
|
||||
}
|
||||
|
||||
// Pass the token expiration to limit session duration
|
||||
// This ensures the STS session doesn't exceed the source token's validity
|
||||
if !claims.ExpiresAt.IsZero() {
|
||||
identity.TokenExpiration = &claims.ExpiresAt
|
||||
}
|
||||
|
||||
return identity, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetUserInfo retrieves user information from the UserInfo endpoint
|
||||
@@ -380,24 +372,6 @@ func (p *OIDCProvider) ValidateToken(ctx context.Context, token string) (*provid
|
||||
Claims: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
// Extract time-based claims (exp, iat, nbf)
|
||||
for key, target := range map[string]*time.Time{
|
||||
"exp": &tokenClaims.ExpiresAt,
|
||||
"iat": &tokenClaims.IssuedAt,
|
||||
"nbf": &tokenClaims.NotBefore,
|
||||
} {
|
||||
if val, ok := claims[key]; ok {
|
||||
switch v := val.(type) {
|
||||
case float64:
|
||||
*target = time.Unix(int64(v), 0)
|
||||
case json.Number:
|
||||
if intVal, err := v.Int64(); err == nil {
|
||||
*target = time.Unix(intVal, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy all claims
|
||||
for key, value := range claims {
|
||||
tokenClaims.Claims[key] = value
|
||||
|
||||
@@ -47,10 +47,6 @@ type ExternalIdentity struct {
|
||||
|
||||
// Provider is the name of the identity provider
|
||||
Provider string `json:"provider"`
|
||||
|
||||
// TokenExpiration is the expiration time of the source identity token
|
||||
// This is used to limit session duration to not exceed the token's exp claim
|
||||
TokenExpiration *time.Time `json:"tokenExpiration,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates the external identity structure
|
||||
|
||||
@@ -422,9 +422,8 @@ func (s *STSService) AssumeRoleWithWebIdentity(ctx context.Context, request *Ass
|
||||
return nil, fmt.Errorf("role assumption denied: %w", err)
|
||||
}
|
||||
|
||||
// 3. Calculate session duration, capping at the source token's expiration
|
||||
// This ensures sessions from short-lived tokens (e.g., GitLab CI job tokens) don't outlive their source
|
||||
sessionDuration := s.calculateSessionDuration(request.DurationSeconds, externalIdentity.TokenExpiration)
|
||||
// 3. Calculate session duration
|
||||
sessionDuration := s.calculateSessionDuration(request.DurationSeconds)
|
||||
expiresAt := time.Now().Add(sessionDuration)
|
||||
|
||||
// 4. Generate session ID and credentials
|
||||
@@ -503,8 +502,7 @@ func (s *STSService) AssumeRoleWithCredentials(ctx context.Context, request *Ass
|
||||
}
|
||||
|
||||
// 4. Calculate session duration
|
||||
// For credential-based auth, there's no source token with expiration to cap against
|
||||
sessionDuration := s.calculateSessionDuration(request.DurationSeconds, nil)
|
||||
sessionDuration := s.calculateSessionDuration(request.DurationSeconds)
|
||||
expiresAt := time.Now().Add(sessionDuration)
|
||||
|
||||
// 5. Generate session ID and temporary credentials
|
||||
@@ -747,42 +745,14 @@ func (s *STSService) validateRoleAssumptionForCredentials(ctx context.Context, r
|
||||
return nil
|
||||
}
|
||||
|
||||
// calculateSessionDuration calculates the session duration, respecting the source token's expiration
|
||||
// If the incoming web identity token has an exp claim, the session duration is capped to not exceed it
|
||||
// This ensures that sessions from short-lived tokens (e.g., GitLab CI job tokens) don't outlive their source
|
||||
func (s *STSService) calculateSessionDuration(durationSeconds *int64, tokenExpiration *time.Time) time.Duration {
|
||||
var duration time.Duration
|
||||
// calculateSessionDuration calculates the session duration
|
||||
func (s *STSService) calculateSessionDuration(durationSeconds *int64) time.Duration {
|
||||
if durationSeconds != nil {
|
||||
duration = time.Duration(*durationSeconds) * time.Second
|
||||
} else {
|
||||
// Use default from config
|
||||
duration = s.Config.TokenDuration.Duration
|
||||
return time.Duration(*durationSeconds) * time.Second
|
||||
}
|
||||
|
||||
// If the source token has an expiration, cap the session duration to not exceed it
|
||||
// This follows the principle: "if calculated exp > incoming exp claim, then limit outgoing exp to incoming exp"
|
||||
if tokenExpiration != nil && !tokenExpiration.IsZero() {
|
||||
timeUntilTokenExpiry := time.Until(*tokenExpiration)
|
||||
if timeUntilTokenExpiry <= 0 {
|
||||
// Token already expired - use minimal duration as defense-in-depth
|
||||
// The token should have been rejected during validation, but we handle this defensively
|
||||
glog.V(2).Infof("Source token already expired, using minimal session duration")
|
||||
duration = time.Minute
|
||||
} else if timeUntilTokenExpiry < duration {
|
||||
glog.V(2).Infof("Limiting session duration from %v to %v based on source token expiration",
|
||||
duration, timeUntilTokenExpiry)
|
||||
duration = timeUntilTokenExpiry
|
||||
}
|
||||
}
|
||||
|
||||
// Cap at MaxSessionLength if configured
|
||||
if s.Config.MaxSessionLength.Duration > 0 && duration > s.Config.MaxSessionLength.Duration {
|
||||
glog.V(2).Infof("Limiting session duration from %v to %v based on MaxSessionLength config",
|
||||
duration, s.Config.MaxSessionLength.Duration)
|
||||
duration = s.Config.MaxSessionLength.Duration
|
||||
}
|
||||
|
||||
return duration
|
||||
// Use default from config
|
||||
return s.Config.TokenDuration.Duration
|
||||
}
|
||||
|
||||
// extractSessionIdFromToken extracts session ID from JWT session token
|
||||
|
||||
@@ -451,212 +451,3 @@ func (m *MockIdentityProvider) ValidateToken(ctx context.Context, token string)
|
||||
}
|
||||
return nil, fmt.Errorf("invalid token")
|
||||
}
|
||||
|
||||
// TestSessionDurationCappedByTokenExpiration tests that session duration is capped by the source token's exp claim
|
||||
func TestSessionDurationCappedByTokenExpiration(t *testing.T) {
|
||||
service := NewSTSService()
|
||||
|
||||
config := &STSConfig{
|
||||
TokenDuration: FlexibleDuration{time.Hour}, // Default: 1 hour
|
||||
MaxSessionLength: FlexibleDuration{time.Hour * 12},
|
||||
Issuer: "test-sts",
|
||||
SigningKey: []byte("test-signing-key-32-characters-long"),
|
||||
}
|
||||
|
||||
err := service.Initialize(config)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
durationSeconds *int64
|
||||
tokenExpiration *time.Time
|
||||
expectedMaxSeconds int64
|
||||
description string
|
||||
}{
|
||||
{
|
||||
name: "no token expiration - use default duration",
|
||||
durationSeconds: nil,
|
||||
tokenExpiration: nil,
|
||||
expectedMaxSeconds: 3600, // 1 hour default
|
||||
description: "When no token expiration is set, use the configured default duration",
|
||||
},
|
||||
{
|
||||
name: "token expires before default duration",
|
||||
durationSeconds: nil,
|
||||
tokenExpiration: timePtr(time.Now().Add(30 * time.Minute)),
|
||||
expectedMaxSeconds: 30 * 60, // 30 minutes
|
||||
description: "When token expires in 30 min, session should be capped at 30 min",
|
||||
},
|
||||
{
|
||||
name: "token expires after default duration - use default",
|
||||
durationSeconds: nil,
|
||||
tokenExpiration: timePtr(time.Now().Add(2 * time.Hour)),
|
||||
expectedMaxSeconds: 3600, // 1 hour default, since it's less than 2 hour token expiry
|
||||
description: "When token expires after default duration, use the default duration",
|
||||
},
|
||||
{
|
||||
name: "requested duration shorter than token expiry",
|
||||
durationSeconds: int64Ptr(1800), // 30 min requested
|
||||
tokenExpiration: timePtr(time.Now().Add(time.Hour)),
|
||||
expectedMaxSeconds: 1800, // 30 minutes as requested
|
||||
description: "When requested duration is shorter than token expiry, use requested duration",
|
||||
},
|
||||
{
|
||||
name: "requested duration longer than token expiry - cap at token expiry",
|
||||
durationSeconds: int64Ptr(3600), // 1 hour requested
|
||||
tokenExpiration: timePtr(time.Now().Add(15 * time.Minute)),
|
||||
expectedMaxSeconds: 15 * 60, // Capped at 15 minutes
|
||||
description: "When requested duration exceeds token expiry, cap at token expiry",
|
||||
},
|
||||
{
|
||||
name: "GitLab CI short-lived token scenario",
|
||||
durationSeconds: nil,
|
||||
tokenExpiration: timePtr(time.Now().Add(5 * time.Minute)),
|
||||
expectedMaxSeconds: 5 * 60, // 5 minutes
|
||||
description: "GitLab CI job with 5 minute timeout should result in 5 minute session",
|
||||
},
|
||||
{
|
||||
name: "already expired token - defense in depth",
|
||||
durationSeconds: nil,
|
||||
tokenExpiration: timePtr(time.Now().Add(-5 * time.Minute)), // Expired 5 minutes ago
|
||||
expectedMaxSeconds: 60, // 1 minute minimum
|
||||
description: "Already expired token should result in minimal 1 minute session",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
duration := service.calculateSessionDuration(tt.durationSeconds, tt.tokenExpiration)
|
||||
|
||||
// Allow 5 second tolerance for time calculations
|
||||
maxExpected := time.Duration(tt.expectedMaxSeconds+5) * time.Second
|
||||
minExpected := time.Duration(tt.expectedMaxSeconds-5) * time.Second
|
||||
|
||||
assert.GreaterOrEqual(t, duration, minExpected,
|
||||
"%s: duration %v should be >= %v", tt.description, duration, minExpected)
|
||||
assert.LessOrEqual(t, duration, maxExpected,
|
||||
"%s: duration %v should be <= %v", tt.description, duration, maxExpected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestAssumeRoleWithWebIdentityRespectsTokenExpiration tests end-to-end that session duration is capped
|
||||
func TestAssumeRoleWithWebIdentityRespectsTokenExpiration(t *testing.T) {
|
||||
service := NewSTSService()
|
||||
|
||||
config := &STSConfig{
|
||||
TokenDuration: FlexibleDuration{time.Hour},
|
||||
MaxSessionLength: FlexibleDuration{time.Hour * 12},
|
||||
Issuer: "test-sts",
|
||||
SigningKey: []byte("test-signing-key-32-characters-long"),
|
||||
}
|
||||
|
||||
err := service.Initialize(config)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up mock trust policy validator
|
||||
mockValidator := &MockTrustPolicyValidator{}
|
||||
service.SetTrustPolicyValidator(mockValidator)
|
||||
|
||||
// Create a mock provider that returns tokens with short expiration
|
||||
shortLivedTokenExpiration := time.Now().Add(10 * time.Minute)
|
||||
mockProvider := &MockIdentityProviderWithExpiration{
|
||||
name: "short-lived-issuer",
|
||||
tokenExpiration: &shortLivedTokenExpiration,
|
||||
}
|
||||
service.RegisterProvider(mockProvider)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Create a JWT token with short expiration
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"iss": "short-lived-issuer",
|
||||
"sub": "test-user",
|
||||
"aud": "test-client",
|
||||
"exp": shortLivedTokenExpiration.Unix(),
|
||||
"iat": time.Now().Unix(),
|
||||
})
|
||||
tokenString, err := token.SignedString([]byte("test-signing-key"))
|
||||
require.NoError(t, err)
|
||||
|
||||
request := &AssumeRoleWithWebIdentityRequest{
|
||||
RoleArn: "arn:aws:iam::role/TestRole",
|
||||
WebIdentityToken: tokenString,
|
||||
RoleSessionName: "test-session",
|
||||
}
|
||||
|
||||
response, err := service.AssumeRoleWithWebIdentity(ctx, request)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, response)
|
||||
|
||||
// Verify the session expires at or before the token expiration
|
||||
// Allow 5 second tolerance
|
||||
assert.True(t, response.Credentials.Expiration.Before(shortLivedTokenExpiration.Add(5*time.Second)),
|
||||
"Session expiration (%v) should not exceed token expiration (%v)",
|
||||
response.Credentials.Expiration, shortLivedTokenExpiration)
|
||||
}
|
||||
|
||||
// MockIdentityProviderWithExpiration is a mock provider that returns tokens with configurable expiration
|
||||
type MockIdentityProviderWithExpiration struct {
|
||||
name string
|
||||
tokenExpiration *time.Time
|
||||
}
|
||||
|
||||
func (m *MockIdentityProviderWithExpiration) Name() string {
|
||||
return m.name
|
||||
}
|
||||
|
||||
func (m *MockIdentityProviderWithExpiration) GetIssuer() string {
|
||||
return m.name
|
||||
}
|
||||
|
||||
func (m *MockIdentityProviderWithExpiration) Initialize(config interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockIdentityProviderWithExpiration) Authenticate(ctx context.Context, token string) (*providers.ExternalIdentity, error) {
|
||||
// Parse the token to get subject
|
||||
parsedToken, _, err := new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse token: %w", err)
|
||||
}
|
||||
|
||||
claims, ok := parsedToken.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid claims")
|
||||
}
|
||||
|
||||
subject, _ := claims["sub"].(string)
|
||||
|
||||
identity := &providers.ExternalIdentity{
|
||||
UserID: subject,
|
||||
Email: subject + "@example.com",
|
||||
DisplayName: "Test User",
|
||||
Provider: m.name,
|
||||
TokenExpiration: m.tokenExpiration,
|
||||
}
|
||||
|
||||
return identity, nil
|
||||
}
|
||||
|
||||
func (m *MockIdentityProviderWithExpiration) GetUserInfo(ctx context.Context, userID string) (*providers.ExternalIdentity, error) {
|
||||
return &providers.ExternalIdentity{
|
||||
UserID: userID,
|
||||
Provider: m.name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *MockIdentityProviderWithExpiration) ValidateToken(ctx context.Context, token string) (*providers.TokenClaims, error) {
|
||||
claims := &providers.TokenClaims{
|
||||
Subject: "test-user",
|
||||
Issuer: m.name,
|
||||
}
|
||||
if m.tokenExpiration != nil {
|
||||
claims.ExpiresAt = *m.tokenExpiration
|
||||
}
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
func timePtr(t time.Time) *time.Time {
|
||||
return &t
|
||||
}
|
||||
|
||||
@@ -18,28 +18,22 @@ const (
|
||||
directoryStreamBaseOffset = 2 // . & ..
|
||||
)
|
||||
|
||||
// DirectoryHandle represents an open directory handle.
|
||||
// It maintains state for directory listing pagination and is protected by a mutex
|
||||
// to handle concurrent readdir operations from NFS-Ganesha and other multi-threaded clients.
|
||||
type DirectoryHandle struct {
|
||||
sync.Mutex
|
||||
isFinished bool
|
||||
entryStream []*filer.Entry
|
||||
entryStreamOffset uint64
|
||||
}
|
||||
|
||||
func (dh *DirectoryHandle) reset() {
|
||||
dh.isFinished = false
|
||||
// Nil out pointers to allow garbage collection of old entries,
|
||||
// then reuse the slice's capacity to avoid re-allocations.
|
||||
for i := range dh.entryStream {
|
||||
dh.entryStream[i] = nil
|
||||
*dh = DirectoryHandle{
|
||||
isFinished: false,
|
||||
entryStream: []*filer.Entry{},
|
||||
entryStreamOffset: directoryStreamBaseOffset,
|
||||
}
|
||||
dh.entryStream = dh.entryStream[:0]
|
||||
dh.entryStreamOffset = directoryStreamBaseOffset
|
||||
}
|
||||
|
||||
type DirectoryHandleToInode struct {
|
||||
// shares the file handle id sequencer with FileHandleToInode{nextFh}
|
||||
sync.Mutex
|
||||
dir2inode map[DirectoryHandleId]*DirectoryHandle
|
||||
}
|
||||
@@ -51,14 +45,14 @@ func NewDirectoryHandleToInode() *DirectoryHandleToInode {
|
||||
}
|
||||
|
||||
func (wfs *WFS) AcquireDirectoryHandle() (DirectoryHandleId, *DirectoryHandle) {
|
||||
fh := DirectoryHandleId(util.RandomUint64())
|
||||
fh := FileHandleId(util.RandomUint64())
|
||||
|
||||
wfs.dhMap.Lock()
|
||||
defer wfs.dhMap.Unlock()
|
||||
dh := &DirectoryHandle{}
|
||||
dh := new(DirectoryHandle)
|
||||
dh.reset()
|
||||
wfs.dhMap.dir2inode[fh] = dh
|
||||
return fh, dh
|
||||
wfs.dhMap.dir2inode[DirectoryHandleId(fh)] = dh
|
||||
return DirectoryHandleId(fh), dh
|
||||
}
|
||||
|
||||
func (wfs *WFS) GetDirectoryHandle(dhid DirectoryHandleId) *DirectoryHandle {
|
||||
@@ -67,7 +61,7 @@ func (wfs *WFS) GetDirectoryHandle(dhid DirectoryHandleId) *DirectoryHandle {
|
||||
if dh, found := wfs.dhMap.dir2inode[dhid]; found {
|
||||
return dh
|
||||
}
|
||||
dh := &DirectoryHandle{}
|
||||
dh := new(DirectoryHandle)
|
||||
dh.reset()
|
||||
wfs.dhMap.dir2inode[dhid] = dh
|
||||
return dh
|
||||
@@ -143,13 +137,7 @@ func (wfs *WFS) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out *fus
|
||||
}
|
||||
|
||||
func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPlusMode bool) fuse.Status {
|
||||
// Get the directory handle and lock it for the duration of this operation.
|
||||
// This serializes concurrent readdir calls on the same handle, fixing the
|
||||
// race condition that caused hangs with NFS-Ganesha.
|
||||
dh := wfs.GetDirectoryHandle(DirectoryHandleId(input.Fh))
|
||||
dh.Lock()
|
||||
defer dh.Unlock()
|
||||
|
||||
if input.Offset == 0 {
|
||||
dh.reset()
|
||||
} else if dh.isFinished && input.Offset >= dh.entryStreamOffset {
|
||||
@@ -166,7 +154,7 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPl
|
||||
}
|
||||
|
||||
var dirEntry fuse.DirEntry
|
||||
processEachEntryFn := func(entry *filer.Entry) bool {
|
||||
processEachEntryFn := func(entry *filer.Entry) (bool, error) {
|
||||
dirEntry.Name = entry.Name()
|
||||
dirEntry.Mode = toSyscallMode(entry.Mode)
|
||||
inode := wfs.inodeToPath.Lookup(dirPath.Child(dirEntry.Name), entry.Crtime.Unix(), entry.IsDirectory(), len(entry.HardLinkId) > 0, entry.Inode, isPlusMode)
|
||||
@@ -174,13 +162,13 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPl
|
||||
if !isPlusMode {
|
||||
if !out.AddDirEntry(dirEntry) {
|
||||
isEarlyTerminated = true
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
entryOut := out.AddDirLookupEntry(dirEntry)
|
||||
if entryOut == nil {
|
||||
isEarlyTerminated = true
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
if fh, found := wfs.fhMap.FindFileHandle(inode); found {
|
||||
glog.V(4).Infof("readdir opened file %s", dirPath.Child(dirEntry.Name))
|
||||
@@ -188,7 +176,7 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPl
|
||||
}
|
||||
wfs.outputFilerEntry(entryOut, inode, entry)
|
||||
}
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if input.Offset < directoryStreamBaseOffset {
|
||||
@@ -219,7 +207,7 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPl
|
||||
entryCurrentIndex := input.Offset - dh.entryStreamOffset
|
||||
for uint64(len(dh.entryStream)) > entryCurrentIndex {
|
||||
entry := dh.entryStream[entryCurrentIndex]
|
||||
if processEachEntryFn(entry) {
|
||||
if process, _ := processEachEntryFn(entry); process {
|
||||
lastEntryName = entry.Name()
|
||||
entryCurrentIndex++
|
||||
} else {
|
||||
@@ -229,16 +217,14 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPl
|
||||
}
|
||||
}
|
||||
|
||||
if err := meta_cache.EnsureVisited(wfs.metaCache, wfs, dirPath); err != nil {
|
||||
var err error
|
||||
if err = meta_cache.EnsureVisited(wfs.metaCache, wfs, dirPath); err != nil {
|
||||
glog.Errorf("dir ReadDirAll %s: %v", dirPath, err)
|
||||
return fuse.EIO
|
||||
}
|
||||
listErr := wfs.metaCache.ListDirectoryEntries(context.Background(), dirPath, lastEntryName, false, int64(math.MaxInt32), func(entry *filer.Entry) (bool, error) {
|
||||
dh.entryStream = append(dh.entryStream, entry)
|
||||
if !processEachEntryFn(entry) {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
return processEachEntryFn(entry)
|
||||
})
|
||||
if listErr != nil {
|
||||
glog.Errorf("list meta cache: %v", listErr)
|
||||
|
||||
@@ -8,24 +8,16 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
util_http "github.com/seaweedfs/seaweedfs/weed/util/http"
|
||||
)
|
||||
|
||||
const (
|
||||
maxWebhookRetryDepth = 2
|
||||
)
|
||||
|
||||
type httpClient struct {
|
||||
endpoint string
|
||||
token string
|
||||
timeout time.Duration
|
||||
client *http.Client // Reused HTTP client with redirect prevention
|
||||
endpointMu sync.RWMutex
|
||||
finalURL string // Cached final URL after following redirects
|
||||
endpoint string
|
||||
token string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func newHTTPClient(cfg *config) (*httpClient, error) {
|
||||
@@ -33,24 +25,10 @@ func newHTTPClient(cfg *config) (*httpClient, error) {
|
||||
endpoint: cfg.endpoint,
|
||||
token: cfg.authBearerToken,
|
||||
timeout: time.Duration(cfg.timeoutSeconds) * time.Second,
|
||||
client: &http.Client{
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *httpClient) sendMessage(message *webhookMessage) error {
|
||||
return h.sendMessageWithRetry(message, 0)
|
||||
}
|
||||
|
||||
func (h *httpClient) sendMessageWithRetry(message *webhookMessage, depth int) error {
|
||||
// Prevent infinite recursion
|
||||
if depth > maxWebhookRetryDepth {
|
||||
return fmt.Errorf("webhook max retry depth exceeded")
|
||||
}
|
||||
|
||||
// Serialize the protobuf message to JSON for HTTP payload
|
||||
notificationData, err := json.Marshal(message.Notification)
|
||||
if err != nil {
|
||||
@@ -68,16 +46,7 @@ func (h *httpClient) sendMessageWithRetry(message *webhookMessage, depth int) er
|
||||
return fmt.Errorf("failed to marshal message: %w", err)
|
||||
}
|
||||
|
||||
// Use cached final URL if available, otherwise use original endpoint
|
||||
h.endpointMu.RLock()
|
||||
targetURL := h.finalURL
|
||||
usingCachedURL := targetURL != ""
|
||||
if targetURL == "" {
|
||||
targetURL = h.endpoint
|
||||
}
|
||||
h.endpointMu.RUnlock()
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, targetURL, bytes.NewBuffer(jsonData))
|
||||
req, err := http.NewRequest(http.MethodPost, h.endpoint, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
@@ -87,88 +56,29 @@ func (h *httpClient) sendMessageWithRetry(message *webhookMessage, depth int) er
|
||||
req.Header.Set("Authorization", "Bearer "+h.token)
|
||||
}
|
||||
|
||||
// Apply timeout via context (not on client) to avoid redundancy
|
||||
if h.timeout > 0 {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), h.timeout)
|
||||
defer cancel()
|
||||
req = req.WithContext(ctx)
|
||||
}
|
||||
|
||||
resp, err := h.client.Do(req)
|
||||
resp, err := util_http.Do(req)
|
||||
if err != nil {
|
||||
if drainErr := drainResponse(resp); drainErr != nil {
|
||||
glog.Errorf("failed to drain response: %v", drainErr)
|
||||
}
|
||||
|
||||
// If using cached URL and request failed, clear cache and retry with original endpoint
|
||||
if usingCachedURL && depth == 0 {
|
||||
glog.V(1).Infof("Webhook request to cached URL %s failed, clearing cache and retrying with original endpoint", targetURL)
|
||||
h.setFinalURL("")
|
||||
return h.sendMessageWithRetry(message, depth+1)
|
||||
if err = drainResponse(resp); err != nil {
|
||||
glog.Errorf("failed to drain response: %v", err)
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
// Handle redirects by caching the final destination and recreating POST request
|
||||
if resp.StatusCode >= 300 && resp.StatusCode < 400 {
|
||||
// Drain and close response body to enable connection reuse
|
||||
util_http.CloseResponse(resp)
|
||||
|
||||
location := resp.Header.Get("Location")
|
||||
if location == "" {
|
||||
return fmt.Errorf("webhook returned redirect status %d without Location header", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Resolve relative URLs against the request URL
|
||||
reqURL := req.URL
|
||||
finalURL, err := reqURL.Parse(location)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse redirect location: %w", err)
|
||||
}
|
||||
|
||||
// Update finalURL to follow the redirect for this attempt
|
||||
finalURLStr := finalURL.String()
|
||||
h.setFinalURL(finalURLStr)
|
||||
|
||||
if depth == 0 {
|
||||
glog.V(1).Infof("Webhook endpoint redirected from %s to %s, caching final destination", targetURL, finalURLStr)
|
||||
} else {
|
||||
glog.V(1).Infof("Webhook endpoint redirected from %s to %s (following redirect on retry)", targetURL, finalURLStr)
|
||||
}
|
||||
|
||||
// Recreate the POST request to the final destination (increment depth to prevent infinite loops)
|
||||
return h.sendMessageWithRetry(message, depth+1)
|
||||
}
|
||||
|
||||
// If using cached URL and got an error response, clear cache and retry with original endpoint
|
||||
if resp.StatusCode >= 400 && usingCachedURL && depth == 0 {
|
||||
// Drain and close response body to enable connection reuse
|
||||
util_http.CloseResponse(resp)
|
||||
|
||||
glog.V(1).Infof("Webhook request to cached URL %s returned error %d, clearing cache and retrying with original endpoint", targetURL, resp.StatusCode)
|
||||
h.setFinalURL("")
|
||||
return h.sendMessageWithRetry(message, depth+1)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
// Drain and close response body before returning error to enable connection reuse
|
||||
util_http.CloseResponse(resp)
|
||||
return fmt.Errorf("webhook returned status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Drain and close response body on success to enable connection reuse
|
||||
util_http.CloseResponse(resp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpClient) setFinalURL(url string) {
|
||||
h.endpointMu.Lock()
|
||||
h.finalURL = url
|
||||
h.endpointMu.Unlock()
|
||||
}
|
||||
|
||||
func drainResponse(resp *http.Response) error {
|
||||
if resp == nil || resp.Body == nil {
|
||||
return nil
|
||||
|
||||
@@ -148,375 +148,3 @@ func TestHttpClientSendMessageNetworkError(t *testing.T) {
|
||||
t.Error("Expected error for network failure")
|
||||
}
|
||||
}
|
||||
|
||||
// TestHttpClientFollowsRedirectAsPost verifies that redirects are followed with POST method preserved
|
||||
func TestHttpClientFollowsRedirectAsPost(t *testing.T) {
|
||||
redirectCalled := false
|
||||
finalCalled := false
|
||||
var finalMethod string
|
||||
var finalBody map[string]interface{}
|
||||
|
||||
// Create final destination server
|
||||
finalServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
finalCalled = true
|
||||
finalMethod = r.Method
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
json.Unmarshal(body, &finalBody)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer finalServer.Close()
|
||||
|
||||
// Create redirect server
|
||||
redirectServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
redirectCalled = true
|
||||
// Return 301 redirect to final server
|
||||
http.Redirect(w, r, finalServer.URL, http.StatusMovedPermanently)
|
||||
}))
|
||||
defer redirectServer.Close()
|
||||
|
||||
cfg := &config{
|
||||
endpoint: redirectServer.URL,
|
||||
authBearerToken: "test-token",
|
||||
timeoutSeconds: 5,
|
||||
}
|
||||
|
||||
client, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create HTTP client: %v", err)
|
||||
}
|
||||
|
||||
message := &filer_pb.EventNotification{
|
||||
NewEntry: &filer_pb.Entry{
|
||||
Name: "test.txt",
|
||||
},
|
||||
}
|
||||
|
||||
// Send message - should follow redirect and recreate POST request
|
||||
err = client.sendMessage(newWebhookMessage("/test/path", message))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to send message: %v", err)
|
||||
}
|
||||
|
||||
if !redirectCalled {
|
||||
t.Error("Expected redirect server to be called")
|
||||
}
|
||||
|
||||
if !finalCalled {
|
||||
t.Error("Expected final server to be called after redirect")
|
||||
}
|
||||
|
||||
if finalMethod != "POST" {
|
||||
t.Errorf("Expected POST method at final destination, got %s", finalMethod)
|
||||
}
|
||||
|
||||
if finalBody["key"] != "/test/path" {
|
||||
t.Errorf("Expected key '/test/path' at final destination, got %v", finalBody["key"])
|
||||
}
|
||||
|
||||
// Verify the final URL is cached
|
||||
client.endpointMu.RLock()
|
||||
cachedURL := client.finalURL
|
||||
client.endpointMu.RUnlock()
|
||||
|
||||
if cachedURL != finalServer.URL {
|
||||
t.Errorf("Expected cached URL %s, got %s", finalServer.URL, cachedURL)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHttpClientUsesCachedRedirect verifies that subsequent requests use the cached redirect destination
|
||||
func TestHttpClientUsesCachedRedirect(t *testing.T) {
|
||||
redirectCount := 0
|
||||
finalCount := 0
|
||||
|
||||
// Create final destination server
|
||||
finalServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
finalCount++
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer finalServer.Close()
|
||||
|
||||
// Create redirect server
|
||||
redirectServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
redirectCount++
|
||||
http.Redirect(w, r, finalServer.URL, http.StatusMovedPermanently)
|
||||
}))
|
||||
defer redirectServer.Close()
|
||||
|
||||
cfg := &config{
|
||||
endpoint: redirectServer.URL,
|
||||
authBearerToken: "test-token",
|
||||
timeoutSeconds: 5,
|
||||
}
|
||||
|
||||
client, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create HTTP client: %v", err)
|
||||
}
|
||||
|
||||
message := &filer_pb.EventNotification{
|
||||
NewEntry: &filer_pb.Entry{
|
||||
Name: "test.txt",
|
||||
},
|
||||
}
|
||||
|
||||
// First request - should hit redirect server
|
||||
err = client.sendMessage(newWebhookMessage("/test/path1", message))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to send first message: %v", err)
|
||||
}
|
||||
|
||||
if redirectCount != 1 {
|
||||
t.Errorf("Expected 1 redirect call, got %d", redirectCount)
|
||||
}
|
||||
if finalCount != 1 {
|
||||
t.Errorf("Expected 1 final call, got %d", finalCount)
|
||||
}
|
||||
|
||||
// Second request - should use cached URL and skip redirect server
|
||||
err = client.sendMessage(newWebhookMessage("/test/path2", message))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to send second message: %v", err)
|
||||
}
|
||||
|
||||
if redirectCount != 1 {
|
||||
t.Errorf("Expected redirect server to be called only once (cached), got %d calls", redirectCount)
|
||||
}
|
||||
if finalCount != 2 {
|
||||
t.Errorf("Expected 2 final calls, got %d", finalCount)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHttpClientPreservesPostMethod verifies POST method is preserved and not converted to GET
|
||||
func TestHttpClientPreservesPostMethod(t *testing.T) {
|
||||
var receivedMethod string
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
receivedMethod = r.Method
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
cfg := &config{
|
||||
endpoint: server.URL,
|
||||
authBearerToken: "test-token",
|
||||
timeoutSeconds: 5,
|
||||
}
|
||||
|
||||
client, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create HTTP client: %v", err)
|
||||
}
|
||||
|
||||
message := &filer_pb.EventNotification{
|
||||
NewEntry: &filer_pb.Entry{
|
||||
Name: "test.txt",
|
||||
},
|
||||
}
|
||||
|
||||
err = client.sendMessage(newWebhookMessage("/test/path", message))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to send message: %v", err)
|
||||
}
|
||||
|
||||
if receivedMethod != "POST" {
|
||||
t.Errorf("Expected POST method, got %s", receivedMethod)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHttpClientInvalidatesCacheOnError verifies that cache is invalidated when cached URL fails
|
||||
func TestHttpClientInvalidatesCacheOnError(t *testing.T) {
|
||||
finalServerDown := false // Start with server UP
|
||||
originalCallCount := 0
|
||||
finalCallCount := 0
|
||||
|
||||
// Create final destination server that can be toggled
|
||||
finalServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
finalCallCount++
|
||||
if finalServerDown {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}))
|
||||
defer finalServer.Close()
|
||||
|
||||
// Create redirect server
|
||||
redirectServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
originalCallCount++
|
||||
http.Redirect(w, r, finalServer.URL, http.StatusMovedPermanently)
|
||||
}))
|
||||
defer redirectServer.Close()
|
||||
|
||||
cfg := &config{
|
||||
endpoint: redirectServer.URL,
|
||||
authBearerToken: "test-token",
|
||||
timeoutSeconds: 5,
|
||||
}
|
||||
|
||||
client, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create HTTP client: %v", err)
|
||||
}
|
||||
|
||||
message := &filer_pb.EventNotification{
|
||||
NewEntry: &filer_pb.Entry{
|
||||
Name: "test.txt",
|
||||
},
|
||||
}
|
||||
|
||||
// First request - should follow redirect and cache the final URL
|
||||
err = client.sendMessage(newWebhookMessage("/test/path1", message))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to send first message: %v", err)
|
||||
}
|
||||
|
||||
if originalCallCount != 1 {
|
||||
t.Errorf("Expected 1 original call, got %d", originalCallCount)
|
||||
}
|
||||
if finalCallCount != 1 {
|
||||
t.Errorf("Expected 1 final call, got %d", finalCallCount)
|
||||
}
|
||||
|
||||
// Verify cache was set
|
||||
client.endpointMu.RLock()
|
||||
cachedURL := client.finalURL
|
||||
client.endpointMu.RUnlock()
|
||||
if cachedURL != finalServer.URL {
|
||||
t.Errorf("Expected cached URL %s, got %s", finalServer.URL, cachedURL)
|
||||
}
|
||||
|
||||
// Second request with cached URL working - should use cache
|
||||
err = client.sendMessage(newWebhookMessage("/test/path2", message))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to send second message: %v", err)
|
||||
}
|
||||
|
||||
if originalCallCount != 1 {
|
||||
t.Errorf("Expected still 1 original call (using cache), got %d", originalCallCount)
|
||||
}
|
||||
if finalCallCount != 2 {
|
||||
t.Errorf("Expected 2 final calls, got %d", finalCallCount)
|
||||
}
|
||||
|
||||
// Third request - bring final server DOWN, should invalidate cache and retry with original
|
||||
// Flow: cached URL (fail, depth=0) -> clear cache -> retry original (depth=1) -> redirect -> final (fail, depth=2)
|
||||
finalServerDown = true
|
||||
err = client.sendMessage(newWebhookMessage("/test/path3", message))
|
||||
if err == nil {
|
||||
t.Error("Expected error when cached URL fails and retry also fails")
|
||||
}
|
||||
|
||||
// originalCallCount: 1 (initial) + 1 (retry after cache invalidation) = 2
|
||||
if originalCallCount != 2 {
|
||||
t.Errorf("Expected 2 original calls, got %d", originalCallCount)
|
||||
}
|
||||
// finalCallCount: 2 (previous) + 1 (cached fail) + 1 (retry after redirect) = 4
|
||||
if finalCallCount != 4 {
|
||||
t.Errorf("Expected 4 final calls, got %d", finalCallCount)
|
||||
}
|
||||
|
||||
// Verify final URL is still set (to the failed destination from the redirect)
|
||||
client.endpointMu.RLock()
|
||||
finalURLAfterError := client.finalURL
|
||||
client.endpointMu.RUnlock()
|
||||
if finalURLAfterError != finalServer.URL {
|
||||
t.Errorf("Expected finalURL to be %s after error, got %s", finalServer.URL, finalURLAfterError)
|
||||
}
|
||||
|
||||
// Fourth request - bring final server back UP
|
||||
// Since cache still has the final URL, it should use it directly
|
||||
finalServerDown = false
|
||||
err = client.sendMessage(newWebhookMessage("/test/path4", message))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to send fourth message after recovery: %v", err)
|
||||
}
|
||||
|
||||
// Should have used the cached URL directly (no new original call)
|
||||
// originalCallCount: still 2
|
||||
if originalCallCount != 2 {
|
||||
t.Errorf("Expected 2 original calls (using cache), got %d", originalCallCount)
|
||||
}
|
||||
// finalCallCount: 4 + 1 = 5
|
||||
if finalCallCount != 5 {
|
||||
t.Errorf("Expected 5 final calls, got %d", finalCallCount)
|
||||
}
|
||||
|
||||
// Verify cache was re-established
|
||||
client.endpointMu.RLock()
|
||||
reestablishedCache := client.finalURL
|
||||
client.endpointMu.RUnlock()
|
||||
if reestablishedCache != finalServer.URL {
|
||||
t.Errorf("Expected cache to be re-established to %s, got %s", finalServer.URL, reestablishedCache)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHttpClientInvalidatesCacheOnNetworkError verifies cache invalidation on network errors
|
||||
func TestHttpClientInvalidatesCacheOnNetworkError(t *testing.T) {
|
||||
originalCallCount := 0
|
||||
var finalServer *httptest.Server
|
||||
// Create redirect server
|
||||
redirectServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
originalCallCount++
|
||||
if finalServer != nil {
|
||||
http.Redirect(w, r, finalServer.URL, http.StatusMovedPermanently)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}))
|
||||
defer redirectServer.Close()
|
||||
|
||||
// Create final destination server
|
||||
finalServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
cfg := &config{
|
||||
endpoint: redirectServer.URL,
|
||||
authBearerToken: "test-token",
|
||||
timeoutSeconds: 5,
|
||||
}
|
||||
|
||||
client, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create HTTP client: %v", err)
|
||||
}
|
||||
|
||||
message := &filer_pb.EventNotification{
|
||||
NewEntry: &filer_pb.Entry{
|
||||
Name: "test.txt",
|
||||
},
|
||||
}
|
||||
|
||||
// First request - establish cache
|
||||
err = client.sendMessage(newWebhookMessage("/test/path1", message))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to send first message: %v", err)
|
||||
}
|
||||
|
||||
if originalCallCount != 1 {
|
||||
t.Errorf("Expected 1 original call, got %d", originalCallCount)
|
||||
}
|
||||
|
||||
// Close final server to simulate network error
|
||||
cachedURL := finalServer.URL
|
||||
finalServer.Close()
|
||||
finalServer = nil
|
||||
|
||||
// Second request - cached URL is down, should invalidate and retry with original
|
||||
err = client.sendMessage(newWebhookMessage("/test/path2", message))
|
||||
if err == nil {
|
||||
t.Error("Expected error when network fails")
|
||||
}
|
||||
|
||||
if originalCallCount != 2 {
|
||||
t.Errorf("Expected 2 original calls (retry after cache invalidation), got %d", originalCallCount)
|
||||
}
|
||||
|
||||
// Verify cache was cleared
|
||||
client.endpointMu.RLock()
|
||||
clearedCache := client.finalURL
|
||||
client.endpointMu.RUnlock()
|
||||
if clearedCache == cachedURL {
|
||||
t.Errorf("Expected cache to be invalidated, but still has %s", clearedCache)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,6 @@ type Queue struct {
|
||||
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
|
||||
// Semaphore for controlling concurrent webhook requests
|
||||
sem chan struct{}
|
||||
}
|
||||
|
||||
func (w *Queue) GetName() string {
|
||||
@@ -92,9 +89,6 @@ func (w *Queue) initialize(cfg *config) error {
|
||||
w.config = cfg
|
||||
w.filter = newFilter(cfg)
|
||||
|
||||
// Initialize semaphore for controlling concurrent webhook requests
|
||||
w.sem = make(chan struct{}, cfg.nWorkers)
|
||||
|
||||
hClient, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create webhook http client: %w", err)
|
||||
@@ -147,17 +141,14 @@ func (w *Queue) setupWatermillQueue(cfg *config) error {
|
||||
router.AddPlugin(plugin.SignalsHandler)
|
||||
router.AddMiddleware(retryMiddleware, poisonQueue)
|
||||
|
||||
// Add a single handler to avoid duplicate message delivery.
|
||||
// With gochannel's default behavior, each handler call creates
|
||||
// a separate subscription, and all subscriptions receive their own copy of each message.
|
||||
// Using a single handler ensures each webhook is sent only once.
|
||||
// Concurrency is controlled via semaphore in handleWebhook based on nWorkers config.
|
||||
router.AddConsumerHandler(
|
||||
"webhook_handler",
|
||||
pubSubTopicName,
|
||||
w.queueChannel,
|
||||
w.handleWebhook,
|
||||
)
|
||||
for i := 0; i < cfg.nWorkers; i++ {
|
||||
router.AddNoPublisherHandler(
|
||||
pubSubHandlerNameTemplate(i),
|
||||
pubSubTopicName,
|
||||
w.queueChannel,
|
||||
w.handleWebhook,
|
||||
)
|
||||
}
|
||||
|
||||
go func() {
|
||||
// cancels the queue context so the dead letter logger exists in case context not canceled by the shutdown signal already
|
||||
@@ -174,10 +165,6 @@ func (w *Queue) setupWatermillQueue(cfg *config) error {
|
||||
}
|
||||
|
||||
func (w *Queue) handleWebhook(msg *message.Message) error {
|
||||
// Acquire semaphore slot (blocks if at capacity)
|
||||
w.sem <- struct{}{}
|
||||
defer func() { <-w.sem }()
|
||||
|
||||
var n filer_pb.EventNotification
|
||||
if err := proto.Unmarshal(msg.Payload, &n); err != nil {
|
||||
glog.Errorf("failed to unmarshal protobuf message: %v", err)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user