mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-10 00:25:52 +00:00
Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a993e4aa62 | ||
|
|
2d2d2f5ca2 | ||
|
|
1b06f6850a | ||
|
|
724731d26f | ||
|
|
62c4ef3536 | ||
|
|
6389a40088 | ||
|
|
ab5fda67c8 | ||
|
|
c9c91ba568 | ||
|
|
41d079a316 | ||
|
|
b1d63d0943 | ||
|
|
92800c31a2 | ||
|
|
551a31e156 | ||
|
|
0a6b289025 | ||
|
|
a72e269a2e | ||
|
|
43229b05ce | ||
|
|
c5b53397c6 | ||
|
|
5ba0db7af4 | ||
|
|
5a7c74feac | ||
|
|
a29806d752 | ||
|
|
9ca43c452b | ||
|
|
06920f79f9 | ||
|
|
b502411884 | ||
|
|
16dc90e3bd | ||
|
|
6714973ffe | ||
|
|
1e5a1871e5 | ||
|
|
db6b4ab918 | ||
|
|
759a6cd345 | ||
|
|
7e3bb4016e | ||
|
|
1e09950ea7 | ||
|
|
74c7b10bc7 | ||
|
|
31a1c87db0 |
@@ -24,7 +24,7 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v2
|
||||
uses: actions/setup-go@a5f9b05d2d216f63e13859e0d847461041025775 # v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
id: go
|
||||
|
||||
@@ -23,10 +23,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.24'
|
||||
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
|
||||
- name: Upload test logs on failure
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ec-test-logs
|
||||
path: test/erasure_coding/admin_dockertest/tmp/logs/
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v2
|
||||
uses: actions/setup-go@a5f9b05d2d216f63e13859e0d847461041025775 # v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
id: go
|
||||
|
||||
@@ -141,3 +141,4 @@ test/s3/iam/.test_env
|
||||
/test/erasure_coding/admin_dockertest/tmp
|
||||
/test/erasure_coding/admin_dockertest/task_logs
|
||||
weed_bin
|
||||
.aider*
|
||||
|
||||
@@ -4,6 +4,7 @@ COPY ./weed /usr/bin/weed
|
||||
RUN chmod +x /usr/bin/weed && ls -la /usr/bin/weed
|
||||
RUN mkdir -p /etc/seaweedfs
|
||||
COPY ./filer.toml /etc/seaweedfs/filer.toml
|
||||
COPY ./security.toml.example /etc/seaweedfs/security.toml.example
|
||||
COPY ./entrypoint.sh /entrypoint.sh
|
||||
|
||||
# Install dependencies and create non-root user
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Put this file to one of the location, with descending priority
|
||||
# ./security.toml
|
||||
# $HOME/.seaweedfs/security.toml
|
||||
# /etc/seaweedfs/security.toml
|
||||
# this file is read by master, volume server, filer, and worker
|
||||
|
||||
# comma separated origins allowed to make requests to the filer and s3 gateway.
|
||||
# enter in this format: https://domain.com, or http://localhost:port
|
||||
[cors.allowed_origins]
|
||||
values = "*"
|
||||
|
||||
# this jwt signing key is read by master and volume server, and it is used for write operations:
|
||||
# - the Master server generates the JWT, which can be used to write a certain file on a volume server
|
||||
# - the Volume server validates the JWT on writing
|
||||
# the jwt defaults to expire after 10 seconds.
|
||||
[jwt.signing]
|
||||
key = "<REPLACE_AT_RUNTIME>"
|
||||
# this jwt signing key is read by master and volume server, and it is used for read operations:
|
||||
# - the Master server generates the JWT, which can be used to read a certain file on a volume server
|
||||
# - the Volume server validates the JWT on reading
|
||||
[jwt.signing.read]
|
||||
key = "<REPLACE_AT_RUNTIME>"
|
||||
# If this JWT key is configured, Filer only accepts writes over HTTP if they are signed with this JWT:
|
||||
# - f.e. the S3 API Shim generates the JWT
|
||||
# - the Filer server validates the JWT on writing
|
||||
# the jwt defaults to expire after 10 seconds.
|
||||
[jwt.filer_signing]
|
||||
key = "<REPLACE_AT_RUNTIME>"
|
||||
# If this JWT key is configured, Filer only accepts reads over HTTP if they are signed with this JWT:
|
||||
# - f.e. the S3 API Shim generates the JWT
|
||||
# - the Filer server validates the JWT on writing
|
||||
# the jwt defaults to expire after 10 seconds.
|
||||
[jwt.filer_signing.read]
|
||||
key = "<REPLACE_AT_RUNTIME>"
|
||||
@@ -39,7 +39,7 @@ require (
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.6
|
||||
github.com/jackc/pgx/v5 v5.8.0
|
||||
github.com/jcmturner/gofork v1.7.6 // indirect
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
@@ -92,12 +92,12 @@ require (
|
||||
gocloud.dev v0.44.0
|
||||
gocloud.dev/pubsub/natspubsub v0.44.0
|
||||
gocloud.dev/pubsub/rabbitpubsub v0.44.0
|
||||
golang.org/x/crypto v0.46.0
|
||||
golang.org/x/crypto v0.47.0
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546
|
||||
golang.org/x/image v0.35.0
|
||||
golang.org/x/net v0.48.0
|
||||
golang.org/x/net v0.49.0
|
||||
golang.org/x/oauth2 v0.34.0
|
||||
golang.org/x/sys v0.39.0
|
||||
golang.org/x/sys v0.40.0
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
golang.org/x/tools v0.40.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
@@ -109,7 +109,7 @@ require (
|
||||
modernc.org/b v1.0.0 // indirect
|
||||
modernc.org/mathutil v1.7.1
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.44.2
|
||||
modernc.org/sqlite v1.44.3
|
||||
modernc.org/strutil v1.2.1
|
||||
)
|
||||
|
||||
@@ -118,7 +118,7 @@ require (
|
||||
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
|
||||
github.com/a-h/templ v0.3.943
|
||||
github.com/a-h/templ v0.3.977
|
||||
github.com/apache/cassandra-gocql-driver/v2 v2.0.0
|
||||
github.com/apple/foundationdb/bindings/go v0.0.0-20250911184653-27f7192f47c3
|
||||
github.com/arangodb/go-driver v1.6.9
|
||||
@@ -157,7 +157,7 @@ require (
|
||||
github.com/tikv/client-go/v2 v2.0.7
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
github.com/ydb-platform/ydb-go-sdk-auth-environ v0.5.1
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.125.1
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.125.3
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.7
|
||||
go.uber.org/atomic v1.11.0
|
||||
golang.org/x/sync v0.19.0
|
||||
@@ -249,7 +249,7 @@ require (
|
||||
cloud.google.com/go/iam v1.5.3 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.2 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3
|
||||
@@ -291,7 +291,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
|
||||
github.com/aws/smithy-go v1.24.0 // indirect
|
||||
github.com/aws/smithy-go v1.24.0
|
||||
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
|
||||
@@ -460,7 +460,7 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/arch v0.20.0 // indirect
|
||||
golang.org/x/term v0.38.0 // indirect
|
||||
golang.org/x/term v0.39.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect
|
||||
|
||||
@@ -541,8 +541,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
|
||||
git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
|
||||
@@ -628,8 +628,8 @@ github.com/ThreeDotsLabs/watermill v1.5.1 h1:t5xMivyf9tpmU3iozPqyrCZXHvoV1XQDfih
|
||||
github.com/ThreeDotsLabs/watermill v1.5.1/go.mod h1:Uop10dA3VeJWsSvis9qO3vbVY892LARrKAdki6WtXS4=
|
||||
github.com/TomiHiltunen/geohash-golang v0.0.0-20150112065804-b3e4e625abfb h1:wumPkzt4zaxO4rHPBrjDK8iZMR41C1qs7njNqlacwQg=
|
||||
github.com/TomiHiltunen/geohash-golang v0.0.0-20150112065804-b3e4e625abfb/go.mod h1:QiYsIBRQEO+Z4Rz7GoI+dsHVneZNONvhczuA+llOZNM=
|
||||
github.com/a-h/templ v0.3.943 h1:o+mT/4yqhZ33F3ootBiHwaY4HM5EVaOJfIshvd5UNTY=
|
||||
github.com/a-h/templ v0.3.943/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
|
||||
github.com/a-h/templ v0.3.977 h1:kiKAPXTZE2Iaf8JbtM21r54A8bCNsncrfnokZZSrSDg=
|
||||
github.com/a-h/templ v0.3.977/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
|
||||
github.com/a1ex3/zstd-seekable-format-go/pkg v0.10.0 h1:iLDOF0rdGTrol/q8OfPIIs5kLD8XvA2q75o6Uq/tgak=
|
||||
github.com/a1ex3/zstd-seekable-format-go/pkg v0.10.0/go.mod h1:DrEWcQJjz7t5iF2duaiyhg4jyoF0kxOD6LtECNGkZ/Q=
|
||||
github.com/aalpar/deheap v0.0.0-20210914013432-0cc84d79dec3 h1:hhdWprfSpFbN7lz3W1gM40vOgvSh1WCSMxYD6gGB4Hs=
|
||||
@@ -1281,8 +1281,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
||||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo=
|
||||
github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jaegertracing/jaeger v1.47.0 h1:XXxTMO+GxX930gxKWsg90rFr6RswkCRIW0AgWFnTYsg=
|
||||
@@ -1820,8 +1820,8 @@ github.com/ydb-platform/ydb-go-sdk-auth-environ v0.5.1 h1:XaRxeVrOyl3y6v9CiYMWaF
|
||||
github.com/ydb-platform/ydb-go-sdk-auth-environ v0.5.1/go.mod h1:9YzkhlIymWaJGX6KMU3vh5sOf3UKbCXkG/ZdjaI3zNM=
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.44.0/go.mod h1:oSLwnuilwIpaF5bJJMAofnGgzPJusoI3zWMNb8I+GnM=
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.47.3/go.mod h1:bWnOIcUHd7+Sl7DN+yhyY1H/I61z53GczvwJgXMgvj0=
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.125.1 h1:YaqzRVbcncabB34YNjOl5ADomYUFva+6l74svIIIJUo=
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.125.1/go.mod h1:stS1mQYjbJvwwYaYzKyFY9eMiuVXWWXQA6T+SpOLg9c=
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.125.3 h1:hTwpF+PdbuR7vcixN+4AC6yu4asaUIAljQCxL51eDII=
|
||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.125.3/go.mod h1:stS1mQYjbJvwwYaYzKyFY9eMiuVXWWXQA6T+SpOLg9c=
|
||||
github.com/ydb-platform/ydb-go-yc v0.12.1 h1:qw3Fa+T81+Kpu5Io2vYHJOwcrYrVjgJlT6t/0dOXJrA=
|
||||
github.com/ydb-platform/ydb-go-yc v0.12.1/go.mod h1:t/ZA4ECdgPWjAb4jyDe8AzQZB5dhpGbi3iCahFaNwBY=
|
||||
github.com/ydb-platform/ydb-go-yc-metadata v0.6.1 h1:9E5q8Nsy2RiJMZDNVy0A3KUrIMBPakJ2VgloeWbcI84=
|
||||
@@ -1953,8 +1953,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
|
||||
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -2090,8 +2090,8 @@ golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -2248,8 +2248,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -2264,8 +2264,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
||||
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
|
||||
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -2748,8 +2748,8 @@ modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
|
||||
modernc.org/sqlite v1.44.2 h1:EdYqXeBpKFJjg8QYnw6E71MpANkoxyuYi+g68ugOL8g=
|
||||
modernc.org/sqlite v1.44.2/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=
|
||||
modernc.org/sqlite v1.44.3 h1:+39JvV/HWMcYslAwRxHb8067w+2zowvFOUrOWIy9PjY=
|
||||
modernc.org/sqlite v1.44.3/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=
|
||||
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
|
||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
||||
|
||||
@@ -24,7 +24,7 @@ helm install --values=values.yaml seaweedfs seaweedfs/seaweedfs
|
||||
* master/filer/volume are stateful sets with anti-affinity on the hostname,
|
||||
so your deployment will be spread/HA.
|
||||
* chart is using memsql(mysql) as the filer backend to enable HA (multiple filer instances) and backup/HA memsql can provide.
|
||||
* mysql user/password are created in a k8s secret (secret-seaweedfs-db.yaml) and injected to the filer with ENV.
|
||||
* mysql user/password are created in a k8s secret (default: `<release>-seaweedfs-db-secret`) and injected to the filer with ENV.
|
||||
* cert config exists and can be enabled, but not been tested, requires cert-manager to be installed.
|
||||
|
||||
## Prerequisites
|
||||
@@ -35,7 +35,9 @@ leveldb is the default database, this supports multiple filer replicas that will
|
||||
When the [limitations](https://github.com/seaweedfs/seaweedfs/wiki/Filer-Store-Replication#limitation) apply, or for a large number of filer replicas, an external datastore is recommended.
|
||||
|
||||
Such as MySQL-compatible database, as specified in the `values.yaml` at `filer.extraEnvironmentVars`.
|
||||
This database should be pre-configured and initialized by running:
|
||||
This database should be pre-configured and initialized. If using the default `db-init-config`, the configmap name is now dynamic (e.g., `<release>-seaweedfs-db-init-config`). You can override this name via `filer.dbInitConfigName`.
|
||||
|
||||
To initialize manually:
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS `filemeta` (
|
||||
`dirhash` BIGINT NOT NULL COMMENT 'first 64 bits of MD5 hash value of directory field',
|
||||
|
||||
@@ -8,7 +8,7 @@ apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-{{ template "seaweedfs.name" . }}-admin
|
||||
name: ingress-{{ include "seaweedfs.fullname" . }}-admin
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
{{- if and (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) .Values.admin.ingress.className }}
|
||||
@@ -42,11 +42,11 @@ spec:
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ template "seaweedfs.name" . }}-admin
|
||||
name: {{ include "seaweedfs.fullname" . }}-admin
|
||||
port:
|
||||
number: {{ .Values.admin.port }}
|
||||
{{- else }}
|
||||
serviceName: {{ template "seaweedfs.name" . }}-admin
|
||||
serviceName: {{ include "seaweedfs.fullname" . }}-admin
|
||||
servicePort: {{ .Values.admin.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: v1
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-admin-secret
|
||||
name: {{ include "seaweedfs.fullname" . }}-admin-secret
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/resource-policy": keep
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-admin
|
||||
name: {{ printf "%s-admin" (include "seaweedfs.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-admin
|
||||
name: {{ include "seaweedfs.fullname" . }}-admin
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -26,6 +26,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: admin
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-admin
|
||||
name: {{ include "seaweedfs.fullname" . }}-admin
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -21,7 +21,7 @@ metadata:
|
||||
{{- toYaml .Values.admin.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
serviceName: {{ template "seaweedfs.name" . }}-admin
|
||||
serviceName: {{ include "seaweedfs.fullname" . }}-admin
|
||||
podManagementPolicy: {{ .Values.admin.podManagementPolicy }}
|
||||
replicas: {{ .Values.admin.replicas }}
|
||||
selector:
|
||||
@@ -90,7 +90,7 @@ spec:
|
||||
{{- if and .Values.admin.secret.existingSecret (not .Values.admin.secret.pwKey) -}}
|
||||
{{- fail "admin.secret.pwKey must be set when admin.secret.existingSecret is provided" -}}
|
||||
{{- end -}}
|
||||
{{- $adminSecretName := .Values.admin.secret.existingSecret | default (printf "%s-admin-secret" (include "seaweedfs.name" .)) }}
|
||||
{{- $adminSecretName := .Values.admin.secret.existingSecret | default (printf "%s-admin-secret" (include "seaweedfs.fullname" .)) }}
|
||||
env:
|
||||
{{- if $adminAuthEnabled }}
|
||||
- name: SEAWEEDFS_ADMIN_USER
|
||||
@@ -117,7 +117,7 @@ spec:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: SEAWEEDFS_FULLNAME
|
||||
value: "{{ template "seaweedfs.name" . }}"
|
||||
value: "{{ include "seaweedfs.fullname" . }}"
|
||||
{{- if .Values.admin.extraEnvironmentVars }}
|
||||
{{- range $key, $value := .Values.admin.extraEnvironmentVars }}
|
||||
- name: {{ $key }}
|
||||
@@ -284,25 +284,25 @@ spec:
|
||||
{{- if .Values.global.enableSecurity }}
|
||||
- name: security-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-security-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-security-config
|
||||
- name: ca-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
- name: master-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-master-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-master-cert
|
||||
- name: volume-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-volume-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-volume-cert
|
||||
- name: filer-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-filer-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-filer-cert
|
||||
- name: client-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-client-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-client-cert
|
||||
- name: admin-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-admin-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-admin-cert
|
||||
{{- end }}
|
||||
{{ tpl .Values.admin.extraVolumes . | indent 8 | trim }}
|
||||
{{- if .Values.admin.nodeSelector }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-all-in-one
|
||||
name: {{ include "seaweedfs.fullname" . }}-all-in-one
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -98,7 +98,7 @@ spec:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: SEAWEEDFS_FULLNAME
|
||||
value: "{{ template "seaweedfs.name" . }}"
|
||||
value: "{{ include "seaweedfs.fullname" . }}"
|
||||
{{- if .Values.allInOne.extraEnvironmentVars }}
|
||||
{{- range $key, $value := .Values.allInOne.extraEnvironmentVars }}
|
||||
{{- if and (ne $key $clusterMasterKey) (ne $key $clusterFilerKey) }}
|
||||
@@ -421,7 +421,7 @@ spec:
|
||||
type: DirectoryOrCreate
|
||||
{{- else if eq .Values.allInOne.data.type "persistentVolumeClaim" }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ template "seaweedfs.name" . }}-all-in-one-data
|
||||
claimName: {{ include "seaweedfs.fullname" . }}-all-in-one-data
|
||||
{{- else if eq .Values.allInOne.data.type "existingClaim" }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.allInOne.data.claimName }}
|
||||
@@ -432,47 +432,47 @@ spec:
|
||||
- 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.fullname" .)) (or .Values.allInOne.s3.existingConfigSecret .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) }}
|
||||
secretName: {{ default (printf "%s-sftp-ssh-secret" (include "seaweedfs.fullname" .)) (or .Values.allInOne.sftp.existingSshConfigSecret .Values.sftp.existingSshConfigSecret) }}
|
||||
{{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }}
|
||||
- name: config-users
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: {{ default (printf "%s-sftp-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.sftp.existingConfigSecret .Values.sftp.existingConfigSecret) }}
|
||||
secretName: {{ default (printf "%s-sftp-secret" (include "seaweedfs.fullname" .)) (or .Values.allInOne.sftp.existingConfigSecret .Values.sftp.existingConfigSecret) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.filer.notificationConfig }}
|
||||
- name: notification-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-notification-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-notification-config
|
||||
{{- end }}
|
||||
- name: master-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-master-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-master-config
|
||||
{{- if .Values.global.enableSecurity }}
|
||||
- name: security-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-security-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-security-config
|
||||
- name: ca-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
- name: master-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-master-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-master-cert
|
||||
- name: volume-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-volume-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-volume-cert
|
||||
- name: filer-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-filer-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-filer-cert
|
||||
- name: client-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-client-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-client-cert
|
||||
{{- end }}
|
||||
{{ tpl .Values.allInOne.extraVolumes . | nindent 8 }}
|
||||
{{- if .Values.allInOne.nodeSelector }}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-all-in-one-data
|
||||
name: {{ include "seaweedfs.fullname" . }}-all-in-one-data
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-all-in-one
|
||||
name: {{ printf "%s-all-in-one" (include "seaweedfs.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -81,5 +81,6 @@ spec:
|
||||
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: seaweedfs-all-in-one
|
||||
{{- end }}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-all-in-one
|
||||
name: {{ include "seaweedfs.fullname" . }}-all-in-one
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -24,6 +24,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: seaweedfs-all-in-one
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }}
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-admin-cert
|
||||
name: {{ include "seaweedfs.fullname" . }}-admin-cert
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -15,19 +15,19 @@ metadata:
|
||||
{{- toYaml .Values.admin.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
secretName: {{ template "seaweedfs.name" . }}-admin-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-admin-cert
|
||||
issuerRef:
|
||||
name: {{ template "seaweedfs.name" . }}-ca-issuer
|
||||
name: {{ include "seaweedfs.fullname" . }}-ca-issuer
|
||||
kind: Issuer
|
||||
commonName: {{ .Values.certificates.commonName }}
|
||||
subject:
|
||||
organizations:
|
||||
- "SeaweedFS CA"
|
||||
dnsNames:
|
||||
- '*.{{ template "seaweedfs.name" . }}-admin'
|
||||
- '*.{{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}'
|
||||
- '*.{{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-admin'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-admin.{{ .Release.Namespace }}'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-admin.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-admin.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
{{- if .Values.certificates.ipAddresses }}
|
||||
ipAddresses:
|
||||
{{- range .Values.certificates.ipAddresses }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }}
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
name: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -10,8 +10,8 @@ metadata:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
secretName: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
commonName: "{{ template "seaweedfs.name" . }}-root-ca"
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
commonName: "{{ include "seaweedfs.fullname" . }}-root-ca"
|
||||
isCA: true
|
||||
{{- if .Values.certificates.ca.duration }}
|
||||
duration: {{ .Values.certificates.ca.duration }}
|
||||
@@ -20,6 +20,6 @@ spec:
|
||||
renewBefore: {{ .Values.certificates.ca.renewBefore }}
|
||||
{{- end }}
|
||||
issuerRef:
|
||||
name: {{ template "seaweedfs.name" . }}-issuer
|
||||
name: {{ include "seaweedfs.fullname" . }}-issuer
|
||||
kind: Issuer
|
||||
{{- end }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }}
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-ca-issuer
|
||||
name: {{ include "seaweedfs.fullname" . }}-ca-issuer
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -11,5 +11,5 @@ metadata:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
ca:
|
||||
secretName: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
{{- end }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }}
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-issuer
|
||||
name: {{ include "seaweedfs.fullname" . }}-issuer
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }}
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-client-cert
|
||||
name: {{ include "seaweedfs.fullname" . }}-client-cert
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -10,9 +10,9 @@ metadata:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
secretName: {{ template "seaweedfs.name" . }}-client-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-client-cert
|
||||
issuerRef:
|
||||
name: {{ template "seaweedfs.name" . }}-ca-issuer
|
||||
name: {{ include "seaweedfs.fullname" . }}-ca-issuer
|
||||
kind: Issuer
|
||||
commonName: {{ .Values.certificates.commonName }}
|
||||
subject:
|
||||
@@ -22,10 +22,10 @@ spec:
|
||||
- '*.{{ .Release.Namespace }}'
|
||||
- '*.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
{{- if .Values.certificates.ipAddresses }}
|
||||
ipAddresses:
|
||||
{{- range .Values.certificates.ipAddresses }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }}
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-filer-cert
|
||||
name: {{ include "seaweedfs.fullname" . }}-filer-cert
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -15,9 +15,9 @@ metadata:
|
||||
{{- toYaml .Values.filer.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
secretName: {{ template "seaweedfs.name" . }}-filer-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-filer-cert
|
||||
issuerRef:
|
||||
name: {{ template "seaweedfs.name" . }}-ca-issuer
|
||||
name: {{ include "seaweedfs.fullname" . }}-ca-issuer
|
||||
kind: Issuer
|
||||
commonName: {{ .Values.certificates.commonName }}
|
||||
subject:
|
||||
@@ -27,10 +27,10 @@ spec:
|
||||
- '*.{{ .Release.Namespace }}'
|
||||
- '*.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
{{- if .Values.certificates.ipAddresses }}
|
||||
ipAddresses:
|
||||
{{- range .Values.certificates.ipAddresses }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }}
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-master-cert
|
||||
name: {{ include "seaweedfs.fullname" . }}-master-cert
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -15,9 +15,9 @@ metadata:
|
||||
{{- toYaml .Values.master.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
secretName: {{ template "seaweedfs.name" . }}-master-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-master-cert
|
||||
issuerRef:
|
||||
name: {{ template "seaweedfs.name" . }}-ca-issuer
|
||||
name: {{ include "seaweedfs.fullname" . }}-ca-issuer
|
||||
kind: Issuer
|
||||
commonName: {{ .Values.certificates.commonName }}
|
||||
subject:
|
||||
@@ -27,10 +27,10 @@ spec:
|
||||
- '*.{{ .Release.Namespace }}'
|
||||
- '*.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
{{- if .Values.certificates.ipAddresses }}
|
||||
ipAddresses:
|
||||
{{- range .Values.certificates.ipAddresses }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }}
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-volume-cert
|
||||
name: {{ include "seaweedfs.fullname" . }}-volume-cert
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -15,9 +15,9 @@ metadata:
|
||||
{{- toYaml .Values.volume.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
secretName: {{ template "seaweedfs.name" . }}-volume-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-volume-cert
|
||||
issuerRef:
|
||||
name: {{ template "seaweedfs.name" . }}-ca-issuer
|
||||
name: {{ include "seaweedfs.fullname" . }}-ca-issuer
|
||||
kind: Issuer
|
||||
commonName: {{ .Values.certificates.commonName }}
|
||||
subject:
|
||||
@@ -27,10 +27,10 @@ spec:
|
||||
- '*.{{ .Release.Namespace }}'
|
||||
- '*.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-master.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
{{- if .Values.certificates.ipAddresses }}
|
||||
ipAddresses:
|
||||
{{- range .Values.certificates.ipAddresses }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }}
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-worker-cert
|
||||
name: {{ include "seaweedfs.fullname" . }}-worker-cert
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -15,19 +15,19 @@ metadata:
|
||||
{{- toYaml .Values.worker.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
secretName: {{ template "seaweedfs.name" . }}-worker-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-worker-cert
|
||||
issuerRef:
|
||||
name: {{ template "seaweedfs.name" . }}-ca-issuer
|
||||
name: {{ include "seaweedfs.fullname" . }}-ca-issuer
|
||||
kind: Issuer
|
||||
commonName: {{ .Values.certificates.commonName }}
|
||||
subject:
|
||||
organizations:
|
||||
- "SeaweedFS CA"
|
||||
dnsNames:
|
||||
- '*.{{ template "seaweedfs.name" . }}-worker'
|
||||
- '*.{{ template "seaweedfs.name" . }}-worker.{{ .Release.Namespace }}'
|
||||
- '*.{{ template "seaweedfs.name" . }}-worker.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ template "seaweedfs.name" . }}-worker.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-worker'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-worker.{{ .Release.Namespace }}'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-worker.{{ .Release.Namespace }}.svc'
|
||||
- '*.{{ include "seaweedfs.fullname" . }}-worker.{{ .Release.Namespace }}.svc.cluster.local'
|
||||
{{- if .Values.certificates.ipAddresses }}
|
||||
ipAddresses:
|
||||
{{- range .Values.certificates.ipAddresses }}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: {{ .Values.global.serviceAccountName }}-objectstorage-provisioner
|
||||
name: {{ include "seaweedfs.fullname" . }}-objectstorage-provisioner
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
@@ -52,7 +52,7 @@ rules:
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: {{ .Values.global.serviceAccountName }}-objectstorage-provisioner
|
||||
name: {{ include "seaweedfs.fullname" . }}-objectstorage-provisioner
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
@@ -64,6 +64,6 @@ subjects:
|
||||
namespace: {{ .Release.Namespace }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: {{ .Values.global.serviceAccountName }}-objectstorage-provisioner
|
||||
name: {{ include "seaweedfs.fullname" . }}-objectstorage-provisioner
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
{{- end }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-objectstorage-provisioner
|
||||
name: {{ include "seaweedfs.fullname" . }}-objectstorage-provisioner
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -78,16 +78,16 @@ spec:
|
||||
{{- else if .Values.s3.ingress.enabled }}
|
||||
value: "{{ printf "https://%s" .Values.s3.ingress.host }}"
|
||||
{{- else if .Values.s3.enabled }}
|
||||
value: "{{ printf "https://%s-s3.%s.svc" (include "seaweedfs.name" .) .Release.Namespace }}"
|
||||
value: "{{ printf "https://%s-s3.%s.svc" (include "seaweedfs.fullname" .) .Release.Namespace }}"
|
||||
{{- else }}
|
||||
value: "{{ printf "https://%s-filer.%s.svc" (include "seaweedfs.name" .) .Release.Namespace }}"
|
||||
value: "{{ printf "https://%s-filer.%s.svc" (include "seaweedfs.fullname" .) .Release.Namespace }}"
|
||||
{{- end }}
|
||||
{{- with .Values.cosi.region }}
|
||||
- name: REGION
|
||||
value: "{{ . }}"
|
||||
{{- end }}
|
||||
- name: SEAWEEDFS_FILER
|
||||
value: "{{ template "seaweedfs.name" . }}-filer:{{ .Values.filer.grpcPort }}"
|
||||
value: "{{ include "seaweedfs.fullname" . }}-filer:{{ .Values.filer.grpcPort }}"
|
||||
{{- if .Values.global.enableSecurity }}
|
||||
- name: WEED_GRPC_CLIENT_KEY
|
||||
value: /usr/local/share/ca-certificates/client/tls.key
|
||||
@@ -185,28 +185,28 @@ spec:
|
||||
{{- if .Values.cosi.existingConfigSecret }}
|
||||
secretName: {{ .Values.cosi.existingConfigSecret }}
|
||||
{{- else }}
|
||||
secretName: seaweedfs-s3-secret
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-s3-secret
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.global.enableSecurity }}
|
||||
- name: security-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-security-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-security-config
|
||||
- name: ca-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
- name: master-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-master-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-master-cert
|
||||
- name: volume-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-volume-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-volume-cert
|
||||
- name: filer-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-filer-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-filer-cert
|
||||
- name: client-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-client-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-client-cert
|
||||
{{- end }}
|
||||
{{ tpl .Values.cosi.extraVolumes . | indent 8 | trim }}
|
||||
{{- if .Values.cosi.nodeSelector }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{{- $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 }}
|
||||
{{- $serviceName := ternary (printf "%s-all-in-one" (include "seaweedfs.fullname" .)) (printf "%s-filer" (include "seaweedfs.fullname" .)) .Values.allInOne.enabled }}
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
@@ -12,7 +12,7 @@ apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-{{ template "seaweedfs.name" . }}-filer
|
||||
name: ingress-{{ include "seaweedfs.fullname" . }}-filer
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- with .Values.filer.ingress.annotations }}
|
||||
annotations:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-filer-client
|
||||
name: {{ printf "%s-filer-client" (include "seaweedfs.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -36,5 +36,6 @@ spec:
|
||||
{{- end }}
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: filer
|
||||
{{- end }}
|
||||
|
||||
@@ -4,7 +4,7 @@ kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
name: {{ template "seaweedfs.name" . }}-filer
|
||||
name: {{ printf "%s-filer" (include "seaweedfs.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -48,5 +48,6 @@ spec:
|
||||
{{- end }}
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: filer
|
||||
{{- end }}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-filer
|
||||
name: {{ include "seaweedfs.fullname" . }}-filer
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -27,6 +27,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: filer
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-filer
|
||||
name: {{ include "seaweedfs.fullname" . }}-filer
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -15,7 +15,7 @@ metadata:
|
||||
{{- toYaml .Values.filer.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
serviceName: {{ template "seaweedfs.name" . }}-filer
|
||||
serviceName: {{ include "seaweedfs.fullname" . }}-filer
|
||||
podManagementPolicy: {{ .Values.filer.podManagementPolicy }}
|
||||
replicas: {{ .Values.filer.replicas }}
|
||||
{{- if (gt (int .Values.filer.updatePartition) 0) }}
|
||||
@@ -70,7 +70,7 @@ spec:
|
||||
{{ tpl .Values.filer.tolerations . | nindent 8 | trim }}
|
||||
{{- end }}
|
||||
{{- include "seaweedfs.imagePullSecrets" . | nindent 6 }}
|
||||
serviceAccountName: {{ .Values.filer.serviceAccountName | default .Values.global.serviceAccountName | quote }} # for deleting statefulset pods after migration
|
||||
serviceAccountName: {{ .Values.filer.serviceAccountName | default (include "seaweedfs.serviceAccountName" .) | quote }} # for deleting statefulset pods after migration
|
||||
terminationGracePeriodSeconds: 60
|
||||
{{- if .Values.filer.priorityClassName }}
|
||||
priorityClassName: {{ .Values.filer.priorityClassName | quote }}
|
||||
@@ -103,17 +103,17 @@ spec:
|
||||
- name: WEED_MYSQL_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: secret-seaweedfs-db
|
||||
name: {{ include "seaweedfs.fullname" . }}-db-secret
|
||||
key: user
|
||||
optional: true
|
||||
- name: WEED_MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: secret-seaweedfs-db
|
||||
name: {{ include "seaweedfs.fullname" . }}-db-secret
|
||||
key: password
|
||||
optional: true
|
||||
- name: SEAWEEDFS_FULLNAME
|
||||
value: "{{ template "seaweedfs.name" . }}"
|
||||
value: "{{ include "seaweedfs.fullname" . }}"
|
||||
{{- if .Values.filer.extraEnvironmentVars }}
|
||||
{{- range $key, $value := .Values.filer.extraEnvironmentVars }}
|
||||
- name: {{ $key }}
|
||||
@@ -359,7 +359,7 @@ spec:
|
||||
{{- end }}
|
||||
- name: db-schema-config-volume
|
||||
configMap:
|
||||
name: seaweedfs-db-init-config
|
||||
name: {{ default (printf "%s-db-init-config" (include "seaweedfs.fullname" .)) .Values.filer.dbInitConfigName }}
|
||||
{{- if and .Values.filer.s3.enabled .Values.filer.s3.enableAuth }}
|
||||
- name: config-users
|
||||
secret:
|
||||
@@ -367,33 +367,33 @@ spec:
|
||||
{{- if .Values.filer.s3.existingConfigSecret }}
|
||||
secretName: {{ .Values.filer.s3.existingConfigSecret }}
|
||||
{{- else }}
|
||||
secretName: seaweedfs-s3-secret
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-s3-secret
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.filer.notificationConfig }}
|
||||
- name: notification-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-notification-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-notification-config
|
||||
{{- end }}
|
||||
{{- if .Values.global.enableSecurity }}
|
||||
- name: security-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-security-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-security-config
|
||||
- name: ca-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
- name: master-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-master-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-master-cert
|
||||
- name: volume-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-volume-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-volume-cert
|
||||
- name: filer-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-filer-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-filer-cert
|
||||
- name: client-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-client-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-client-cert
|
||||
{{- end }}
|
||||
{{ tpl .Values.filer.extraVolumes . | indent 8 | trim }}
|
||||
{{- if .Values.filer.nodeSelector }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-master-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-master-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
|
||||
@@ -9,7 +9,7 @@ apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-{{ template "seaweedfs.name" . }}-master
|
||||
name: ingress-{{ include "seaweedfs.fullname" . }}-master
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- with .Values.master.ingress.annotations }}
|
||||
annotations:
|
||||
@@ -33,12 +33,12 @@ spec:
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ template "seaweedfs.name" . }}-master
|
||||
name: {{ include "seaweedfs.fullname" . }}-master
|
||||
port:
|
||||
number: {{ .Values.master.port }}
|
||||
#name:
|
||||
{{- else }}
|
||||
serviceName: {{ template "seaweedfs.name" . }}-master
|
||||
serviceName: {{ include "seaweedfs.fullname" . }}-master
|
||||
servicePort: {{ .Values.master.port }}
|
||||
{{- end }}
|
||||
{{- if .Values.filer.ingress.host }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-master
|
||||
name: {{ printf "%s-master" (include "seaweedfs.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -34,5 +34,6 @@ spec:
|
||||
{{- end }}
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: master
|
||||
{{- end }}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-master
|
||||
name: {{ include "seaweedfs.fullname" . }}-master
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -27,6 +27,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: master
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-master
|
||||
name: {{ include "seaweedfs.fullname" . }}-master
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -15,7 +15,7 @@ metadata:
|
||||
{{- toYaml .Values.master.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
serviceName: {{ template "seaweedfs.name" . }}-master
|
||||
serviceName: {{ include "seaweedfs.fullname" . }}-master
|
||||
podManagementPolicy: {{ .Values.master.podManagementPolicy }}
|
||||
replicas: {{ .Values.master.replicas }}
|
||||
{{- if (gt (int .Values.master.updatePartition) 0) }}
|
||||
@@ -70,7 +70,7 @@ spec:
|
||||
{{- end }}
|
||||
enableServiceLinks: false
|
||||
{{- if .Values.global.createClusterRole }}
|
||||
serviceAccountName: {{ .Values.master.serviceAccountName | default .Values.global.serviceAccountName | quote }} # for deleting statefulset pods after migration
|
||||
serviceAccountName: {{ .Values.master.serviceAccountName | default (include "seaweedfs.serviceAccountName" .) | quote }} # for deleting statefulset pods after migration
|
||||
{{- end }}
|
||||
{{- if .Values.master.initContainers }}
|
||||
initContainers:
|
||||
@@ -97,7 +97,7 @@ spec:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: SEAWEEDFS_FULLNAME
|
||||
value: "{{ template "seaweedfs.name" . }}"
|
||||
value: "{{ include "seaweedfs.fullname" . }}"
|
||||
{{- if .Values.master.extraEnvironmentVars }}
|
||||
{{- range $key, $value := .Values.master.extraEnvironmentVars }}
|
||||
- name: {{ $key }}
|
||||
@@ -297,26 +297,26 @@ spec:
|
||||
{{- end }}
|
||||
- name: master-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-master-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-master-config
|
||||
{{- if .Values.global.enableSecurity }}
|
||||
- name: security-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-security-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-security-config
|
||||
- name: ca-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
- name: master-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-master-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-master-cert
|
||||
- name: volume-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-volume-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-volume-cert
|
||||
- name: filer-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-filer-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-filer-cert
|
||||
- name: client-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-client-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-client-cert
|
||||
{{- end }}
|
||||
{{ tpl .Values.master.extraVolumes . | indent 8 | trim }}
|
||||
{{- if .Values.master.nodeSelector }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-s3
|
||||
name: {{ include "seaweedfs.fullname" . }}-s3
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -89,7 +89,7 @@ spec:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: SEAWEEDFS_FULLNAME
|
||||
value: "{{ template "seaweedfs.name" . }}"
|
||||
value: "{{ include "seaweedfs.fullname" . }}"
|
||||
{{- if .Values.s3.extraEnvironmentVars }}
|
||||
{{- range $key, $value := .Values.s3.extraEnvironmentVars }}
|
||||
- name: {{ $key }}
|
||||
@@ -149,7 +149,7 @@ spec:
|
||||
{{- if .Values.s3.auditLogConfig }}
|
||||
-auditLogConfig=/etc/sw/s3_auditLogConfig.json \
|
||||
{{- end }}
|
||||
-filer={{ template "seaweedfs.name" . }}-filer-client.{{ .Release.Namespace }}:{{ .Values.filer.port }} \
|
||||
-filer={{ include "seaweedfs.fullname" . }}-filer-client.{{ .Release.Namespace }}:{{ .Values.filer.port }} \
|
||||
{{- range .Values.s3.extraArgs }}
|
||||
{{ . }} \
|
||||
{{- end }}
|
||||
@@ -238,7 +238,7 @@ spec:
|
||||
{{- if .Values.s3.existingConfigSecret }}
|
||||
secretName: {{ .Values.s3.existingConfigSecret }}
|
||||
{{- else }}
|
||||
secretName: seaweedfs-s3-secret
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-s3-secret
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if eq .Values.s3.logs.type "hostPath" }}
|
||||
@@ -254,22 +254,22 @@ spec:
|
||||
{{- if .Values.global.enableSecurity }}
|
||||
- name: security-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-security-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-security-config
|
||||
- name: ca-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
- name: master-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-master-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-master-cert
|
||||
- name: volume-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-volume-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-volume-cert
|
||||
- name: filer-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-filer-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-filer-cert
|
||||
- name: client-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-client-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-client-cert
|
||||
{{- end }}
|
||||
{{ tpl .Values.s3.extraVolumes . | indent 8 | trim }}
|
||||
{{- if .Values.s3.nodeSelector }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{{- $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 }}
|
||||
{{- $serviceName := ternary (printf "%s-all-in-one" (include "seaweedfs.fullname" .)) (printf "%s-s3" (include "seaweedfs.fullname" .)) .Values.allInOne.enabled }}
|
||||
{{- $s3Port := .Values.allInOne.s3.port | default .Values.s3.port }}
|
||||
{{- /* Build hosts list - support both legacy .host (string) and new .hosts (array) for backwards compatibility */}}
|
||||
{{- $hosts := list }}
|
||||
@@ -20,7 +20,7 @@ apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-{{ template "seaweedfs.name" . }}-s3
|
||||
name: ingress-{{ include "seaweedfs.fullname" . }}-s3
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- with .Values.s3.ingress.annotations }}
|
||||
annotations:
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
{{- if or (and (or .Values.s3.enabled .Values.allInOne.enabled) .Values.s3.enableAuth (not .Values.s3.existingConfigSecret)) (and .Values.filer.s3.enabled .Values.filer.s3.enableAuth (not .Values.filer.s3.existingConfigSecret)) }}
|
||||
{{- $access_key_admin := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-s3-secret" "key" "admin_access_key_id" "length" 20) -}}
|
||||
{{- $secret_key_admin := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-s3-secret" "key" "admin_secret_access_key" "length" 40) -}}
|
||||
{{- $access_key_read := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-s3-secret" "key" "read_access_key_id" "length" 20) -}}
|
||||
{{- $secret_key_read := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-s3-secret" "key" "read_secret_access_key" "length" 40) -}}
|
||||
{{- $secretName := printf "%s-s3-secret" (include "seaweedfs.fullname" .) }}
|
||||
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (default $secretName .Values.s3.legacySecretName) }}
|
||||
{{- $reuse := false }}
|
||||
{{- if and .Values.s3.reuseLegacySecret $existingSecret }}
|
||||
{{- $reuse = true }}
|
||||
{{- end }}
|
||||
{{- $access_key_admin := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" $secretName "key" "admin_access_key_id" "length" 20 "existingSecret" (ternary $existingSecret nil $reuse)) -}}
|
||||
{{- $secret_key_admin := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" $secretName "key" "admin_secret_access_key" "length" 40 "existingSecret" (ternary $existingSecret nil $reuse)) -}}
|
||||
{{- $access_key_read := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" $secretName "key" "read_access_key_id" "length" 20 "existingSecret" (ternary $existingSecret nil $reuse)) -}}
|
||||
{{- $secret_key_read := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" $secretName "key" "read_secret_access_key" "length" 40 "existingSecret" (ternary $existingSecret nil $reuse)) -}}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
metadata:
|
||||
name: seaweedfs-s3-secret
|
||||
name: {{ $secretName }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/resource-policy": keep
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-s3
|
||||
name: {{ printf "%s-s3" (include "seaweedfs.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -34,5 +34,6 @@ spec:
|
||||
{{- end }}
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: {{ if .Values.s3.enabled }}s3{{ else }}filer{{ end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-s3
|
||||
name: {{ include "seaweedfs.fullname" . }}-s3
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -27,6 +27,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: s3
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-sftp
|
||||
name: {{ include "seaweedfs.fullname" . }}-sftp
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -89,7 +89,7 @@ spec:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: SEAWEEDFS_FULLNAME
|
||||
value: "{{ template "seaweedfs.name" . }}"
|
||||
value: "{{ include "seaweedfs.fullname" . }}"
|
||||
{{- if .Values.sftp.extraEnvironmentVars }}
|
||||
{{- range $key, $value := .Values.sftp.extraEnvironmentVars }}
|
||||
- name: {{ $key }}
|
||||
@@ -171,7 +171,7 @@ spec:
|
||||
-key.file=/usr/local/share/ca-certificates/client/tls.key \
|
||||
{{- end }}
|
||||
-userStoreFile=/etc/sw/seaweedfs_sftp_config \
|
||||
-filer={{ template "seaweedfs.name" . }}-filer-client.{{ .Release.Namespace }}:{{ .Values.filer.port }}
|
||||
-filer={{ include "seaweedfs.fullname" . }}-filer-client.{{ .Release.Namespace }}:{{ .Values.filer.port }}
|
||||
volumeMounts:
|
||||
{{- if or (eq .Values.sftp.logs.type "hostPath") (eq .Values.sftp.logs.type "emptyDir") }}
|
||||
- name: logs
|
||||
@@ -252,7 +252,7 @@ spec:
|
||||
{{- if .Values.sftp.existingConfigSecret }}
|
||||
secretName: {{ .Values.sftp.existingConfigSecret }}
|
||||
{{- else }}
|
||||
secretName: seaweedfs-sftp-secret
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-sftp-secret
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
- name: config-ssh
|
||||
@@ -261,7 +261,7 @@ spec:
|
||||
{{- if .Values.sftp.existingSshConfigSecret }}
|
||||
secretName: {{ .Values.sftp.existingSshConfigSecret }}
|
||||
{{- else }}
|
||||
secretName: seaweedfs-sftp-ssh-secret
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-sftp-ssh-secret
|
||||
{{- end }}
|
||||
{{- if eq .Values.sftp.logs.type "hostPath" }}
|
||||
- name: logs
|
||||
@@ -276,22 +276,22 @@ spec:
|
||||
{{- if .Values.global.enableSecurity }}
|
||||
- name: security-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-security-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-security-config
|
||||
- name: ca-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
- name: master-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-master-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-master-cert
|
||||
- name: volume-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-volume-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-volume-cert
|
||||
- name: filer-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-filer-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-filer-cert
|
||||
- name: client-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-client-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-client-cert
|
||||
{{- end }}
|
||||
{{ tpl .Values.sftp.extraVolumes . | indent 8 | trim }}
|
||||
{{- if .Values.sftp.nodeSelector }}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
{{- if or .Values.sftp.enabled .Values.allInOne.enabled }}
|
||||
{{- $admin_pwd := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-sftp-secret" "key" "admin_password" 20) -}}
|
||||
{{- $read_user_pwd := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-sftp-secret" "key" "readonly_password" 20) -}}
|
||||
{{- $public_user_pwd := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-sftp-secret" "key" "public_user_password" 20) -}}
|
||||
{{- $secretName := printf "%s-sftp-secret" (include "seaweedfs.fullname" .) }}
|
||||
{{- $admin_pwd := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" $secretName "key" "admin_password" 20) -}}
|
||||
{{- $read_user_pwd := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" $secretName "key" "readonly_password" 20) -}}
|
||||
{{- $public_user_pwd := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" $secretName "key" "public_user_password" 20) -}}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
metadata:
|
||||
name: seaweedfs-sftp-secret
|
||||
name: {{ $secretName }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/resource-policy": keep
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-sftp
|
||||
name: {{ printf "%s-sftp" (include "seaweedfs.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -28,5 +28,6 @@ spec:
|
||||
{{- end }}
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: sftp
|
||||
{{- end }}
|
||||
@@ -4,7 +4,7 @@
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-sftp
|
||||
name: {{ include "seaweedfs.fullname" . }}-sftp
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -27,6 +27,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: sftp
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -244,7 +244,7 @@ or generate a new random password if it doesn't exist.
|
||||
{{- $key := $params.key -}}
|
||||
{{- $length := default 16 $params.length -}}
|
||||
|
||||
{{- $existingSecret := lookup "v1" "Secret" $namespace $secretName -}}
|
||||
{{- $existingSecret := default (lookup "v1" "Secret" $namespace $secretName) $params.existingSecret -}}
|
||||
{{- if and $existingSecret (index $existingSecret.data $key) -}}
|
||||
{{- index $existingSecret.data $key | b64dec -}}
|
||||
{{- else -}}
|
||||
@@ -261,7 +261,7 @@ If allInOne is enabled, point to the all-in-one service; otherwise, point to the
|
||||
{{- if .Values.allInOne.enabled -}}
|
||||
{{- $serviceNameSuffix = "-all-in-one" -}}
|
||||
{{- end -}}
|
||||
{{- printf "%s%s.%s:%d" (include "seaweedfs.name" .) $serviceNameSuffix .Release.Namespace (int .Values.master.port) -}}
|
||||
{{- printf "%s%s.%s:%d" (include "seaweedfs.fullname" .) $serviceNameSuffix .Release.Namespace (int .Values.master.port) -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
@@ -273,7 +273,7 @@ If allInOne is enabled, point to the all-in-one service; otherwise, point to the
|
||||
{{- if .Values.allInOne.enabled -}}
|
||||
{{- $serviceNameSuffix = "-all-in-one" -}}
|
||||
{{- end -}}
|
||||
{{- printf "%s%s.%s:%d" (include "seaweedfs.name" .) $serviceNameSuffix .Release.Namespace (int .Values.filer.port) -}}
|
||||
{{- printf "%s%s.%s:%d" (include "seaweedfs.fullname" .) $serviceNameSuffix .Release.Namespace (int .Values.filer.port) -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
@@ -282,7 +282,7 @@ 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" . -}}
|
||||
{{- $fullname := include "seaweedfs.fullname" . -}}
|
||||
{{- range $index := until (.Values.master.replicas | int) -}}
|
||||
{{- if $index }},{{ end -}}
|
||||
${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}
|
||||
@@ -300,3 +300,10 @@ Usage: {{ include "seaweedfs.masterServerArg" . }}
|
||||
{{- include "seaweedfs.masterServers" . -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "seaweedfs.serviceAccountName" -}}
|
||||
{{- .Values.global.serviceAccountName | default "seaweedfs" -}}
|
||||
{{- end -}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: {{ .Values.global.serviceAccountName }}-rw-cr
|
||||
name: {{ include "seaweedfs.fullname" . }}-rw-cr
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
@@ -18,7 +18,7 @@ rules:
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: system:serviceaccount:{{ .Values.global.serviceAccountName }}:default
|
||||
name: {{ include "seaweedfs.fullname" . }}-rw-crb
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
@@ -26,10 +26,10 @@ metadata:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ .Values.global.serviceAccountName }}
|
||||
name: {{ include "seaweedfs.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ .Values.global.serviceAccountName }}-rw-cr
|
||||
name: {{ include "seaweedfs.fullname" . }}-rw-cr
|
||||
{{- end }}
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-notification-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-notification-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
|
||||
@@ -74,7 +74,7 @@ spec:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: SEAWEEDFS_FULLNAME
|
||||
value: "{{ template "seaweedfs.name" . }}"
|
||||
value: "{{ include "seaweedfs.fullname" . }}"
|
||||
command:
|
||||
- "/bin/sh"
|
||||
- "-ec"
|
||||
@@ -145,7 +145,7 @@ spec:
|
||||
{{- if $existingConfigSecret }}
|
||||
secretName: {{ $existingConfigSecret }}
|
||||
{{- else }}
|
||||
secretName: {{ template "seaweedfs.name" . }}-s3-secret
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-s3-secret
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ printf "%s" $dashboardName | lower | replace "_" "-" }}
|
||||
name: {{ include "seaweedfs.fullname" $ }}-{{ printf "%s" $dashboardName | lower | replace "_" "-" }}
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
grafana_dashboard: "1"
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: v1
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
metadata:
|
||||
name: secret-seaweedfs-db
|
||||
name: {{ include "seaweedfs.fullname" . }}-db-secret
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/resource-policy": keep
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-security-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-security-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -10,7 +10,13 @@ metadata:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
data:
|
||||
{{- $existing := (lookup "v1" "ConfigMap" .Release.Namespace (printf "%s-security-config" (include "seaweedfs.name" .))) }}
|
||||
{{- $fullname := include "seaweedfs.fullname" . }}
|
||||
{{- $securityConfigName := printf "%s-security-config" $fullname }}
|
||||
{{- $existing := lookup "v1" "ConfigMap" .Release.Namespace $securityConfigName }}
|
||||
{{- if not $existing }}
|
||||
{{- $legacyName := printf "%s-%s" (include "seaweedfs.name" .) "security-config" }}
|
||||
{{- $existing = lookup "v1" "ConfigMap" .Release.Namespace $legacyName }}
|
||||
{{- end }}
|
||||
{{- $securityConfig := fromToml (dig "data" "security.toml" "" $existing) }}
|
||||
security.toml: |-
|
||||
# this file is read by master, volume server, and filer
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ .Values.global.serviceAccountName }}
|
||||
name: {{ include "seaweedfs.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
|
||||
@@ -8,7 +8,7 @@ apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-{{ template "seaweedfs.name" . }}-volume
|
||||
name: ingress-{{ include "seaweedfs.fullname" . }}-volume
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
{{- if and (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) .Values.volume.ingress.className }}
|
||||
@@ -42,11 +42,11 @@ spec:
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ template "seaweedfs.name" . }}-volume
|
||||
name: {{ include "seaweedfs.fullname" . }}-volume
|
||||
port:
|
||||
number: {{ .Values.volume.port }}
|
||||
{{- else }}
|
||||
serviceName: {{ template "seaweedfs.name" . }}-volume
|
||||
serviceName: {{ include "seaweedfs.fullname" . }}-volume
|
||||
servicePort: {{ .Values.volume.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{- $seaweedfsName := include "seaweedfs.name" $ }}
|
||||
{{- $seaweedfsName := include "seaweedfs.fullname" $ }}
|
||||
{{- $volumes := deepCopy .Values.volumes | mergeOverwrite (dict "" .Values.volume) }}
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" $ }}-{{ $volumeName }}
|
||||
name: {{ printf "%s-%s" (include "seaweedfs.fullname" $) $volumeName | trunc 63 | trimSuffix "-" }}
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" $ }}
|
||||
@@ -39,6 +39,7 @@ spec:
|
||||
{{- end }}
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" $ }}
|
||||
app.kubernetes.io/instance: {{ $.Release.Name }}
|
||||
app.kubernetes.io/component: {{ $volumeName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" $ }}-{{ $volumeName }}
|
||||
name: {{ include "seaweedfs.fullname" $ }}-{{ $volumeName }}
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" $ }}
|
||||
@@ -33,6 +33,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" $ }}
|
||||
app.kubernetes.io/instance: {{ $.Release.Name }}
|
||||
app.kubernetes.io/component: {{ $volumeName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" $ }}-{{ $volumeName }}
|
||||
name: {{ include "seaweedfs.fullname" $ }}-{{ $volumeName }}
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" $ }}
|
||||
@@ -21,7 +21,7 @@ metadata:
|
||||
{{- toYaml $volume.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
serviceName: {{ template "seaweedfs.name" $ }}-{{ $volumeName }}
|
||||
serviceName: {{ include "seaweedfs.fullname" $ }}-{{ $volumeName }}
|
||||
replicas: {{ $volume.replicas }}
|
||||
podManagementPolicy: {{ $volume.podManagementPolicy }}
|
||||
selector:
|
||||
@@ -70,7 +70,7 @@ spec:
|
||||
{{- end }}
|
||||
enableServiceLinks: false
|
||||
{{- if $.Values.global.createClusterRole }}
|
||||
serviceAccountName: {{ $volume.serviceAccountName | default $.Values.global.serviceAccountName | quote }} # for deleting statefulset pods after migration
|
||||
serviceAccountName: {{ $volume.serviceAccountName | default (include "seaweedfs.serviceAccountName" $) | quote }} # for deleting statefulset pods after migration
|
||||
{{- end }}
|
||||
{{- $initContainers_exists := include "volume.initContainers_exists" $ -}}
|
||||
{{- if $initContainers_exists }}
|
||||
@@ -117,7 +117,7 @@ spec:
|
||||
fieldRef:
|
||||
fieldPath: status.hostIP
|
||||
- name: SEAWEEDFS_FULLNAME
|
||||
value: "{{ template "seaweedfs.name" $ }}"
|
||||
value: "{{ include "seaweedfs.fullname" $ }}"
|
||||
{{- if $volume.extraEnvironmentVars }}
|
||||
{{- range $key, $value := $volume.extraEnvironmentVars }}
|
||||
- name: {{ $key }}
|
||||
@@ -343,22 +343,22 @@ spec:
|
||||
{{- if $.Values.global.enableSecurity }}
|
||||
- name: security-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" $ }}-security-config
|
||||
name: {{ include "seaweedfs.fullname" $ }}-security-config
|
||||
- name: ca-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" $ }}-ca-cert
|
||||
secretName: {{ include "seaweedfs.fullname" $ }}-ca-cert
|
||||
- name: master-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" $ }}-master-cert
|
||||
secretName: {{ include "seaweedfs.fullname" $ }}-master-cert
|
||||
- name: volume-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" $ }}-volume-cert
|
||||
secretName: {{ include "seaweedfs.fullname" $ }}-volume-cert
|
||||
- name: filer-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" $ }}-filer-cert
|
||||
secretName: {{ include "seaweedfs.fullname" $ }}-filer-cert
|
||||
- name: client-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" $ }}-client-cert
|
||||
secretName: {{ include "seaweedfs.fullname" $ }}-client-cert
|
||||
{{- end }}
|
||||
{{- if $volume.extraVolumes }}
|
||||
{{ tpl $volume.extraVolumes $ | indent 8 | trim }}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-worker
|
||||
name: {{ include "seaweedfs.fullname" . }}-worker
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -92,7 +92,7 @@ spec:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: SEAWEEDFS_FULLNAME
|
||||
value: "{{ template "seaweedfs.name" . }}"
|
||||
value: "{{ include "seaweedfs.fullname" . }}"
|
||||
{{- if .Values.worker.extraEnvironmentVars }}
|
||||
{{- range $key, $value := .Values.worker.extraEnvironmentVars }}
|
||||
- name: {{ $key }}
|
||||
@@ -260,25 +260,25 @@ spec:
|
||||
{{- if .Values.global.enableSecurity }}
|
||||
- name: security-config
|
||||
configMap:
|
||||
name: {{ template "seaweedfs.name" . }}-security-config
|
||||
name: {{ include "seaweedfs.fullname" . }}-security-config
|
||||
- name: ca-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-ca-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-ca-cert
|
||||
- name: master-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-master-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-master-cert
|
||||
- name: volume-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-volume-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-volume-cert
|
||||
- name: filer-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-filer-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-filer-cert
|
||||
- name: client-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-client-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-client-cert
|
||||
- name: worker-cert
|
||||
secret:
|
||||
secretName: {{ template "seaweedfs.name" . }}-worker-cert
|
||||
secretName: {{ include "seaweedfs.fullname" . }}-worker-cert
|
||||
{{- end }}
|
||||
{{ tpl .Values.worker.extraVolumes . | indent 8 | trim }}
|
||||
{{- if .Values.worker.nodeSelector }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-worker
|
||||
name: {{ printf "%s-worker" (include "seaweedfs.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "seaweedfs.name" . }}-worker
|
||||
name: {{ include "seaweedfs.fullname" . }}-worker
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
@@ -27,6 +27,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "seaweedfs.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: worker
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.24.2</version>
|
||||
<version>3.27.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -37,274 +37,6 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"iam": {
|
||||
"enabled": true,
|
||||
"sts": {
|
||||
"tokenDuration": "15m",
|
||||
"issuer": "seaweedfs-sts",
|
||||
"signingKey": "dGVzdC1zaWduaW5nLWtleS0zMi1jaGFyYWN0ZXJzLWxvbmc="
|
||||
},
|
||||
"policy": {
|
||||
"defaultEffect": "Deny"
|
||||
},
|
||||
"providers": {
|
||||
"oidc": {
|
||||
"test-oidc": {
|
||||
"issuer": "http://localhost:8080/.well-known/openid_configuration",
|
||||
"clientId": "test-client-id",
|
||||
"jwksUri": "http://localhost:8080/jwks",
|
||||
"userInfoUri": "http://localhost:8080/userinfo",
|
||||
"roleMapping": {
|
||||
"rules": [
|
||||
{
|
||||
"claim": "groups",
|
||||
"claimValue": "admins",
|
||||
"roleName": "S3AdminRole"
|
||||
},
|
||||
{
|
||||
"claim": "groups",
|
||||
"claimValue": "users",
|
||||
"roleName": "S3ReadOnlyRole"
|
||||
},
|
||||
{
|
||||
"claim": "groups",
|
||||
"claimValue": "writers",
|
||||
"roleName": "S3WriteOnlyRole"
|
||||
}
|
||||
]
|
||||
},
|
||||
"claimsMapping": {
|
||||
"email": "email",
|
||||
"displayName": "name",
|
||||
"groups": "groups"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ldap": {
|
||||
"test-ldap": {
|
||||
"server": "ldap://localhost:389",
|
||||
"baseDN": "dc=example,dc=com",
|
||||
"bindDN": "cn=admin,dc=example,dc=com",
|
||||
"bindPassword": "admin-password",
|
||||
"userFilter": "(uid=%s)",
|
||||
"groupFilter": "(memberUid=%s)",
|
||||
"attributes": {
|
||||
"email": "mail",
|
||||
"displayName": "cn",
|
||||
"groups": "memberOf"
|
||||
},
|
||||
"roleMapping": {
|
||||
"rules": [
|
||||
{
|
||||
"claim": "groups",
|
||||
"claimValue": "cn=admins,ou=groups,dc=example,dc=com",
|
||||
"roleName": "S3AdminRole"
|
||||
},
|
||||
{
|
||||
"claim": "groups",
|
||||
"claimValue": "cn=users,ou=groups,dc=example,dc=com",
|
||||
"roleName": "S3ReadOnlyRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"policyStore": {}
|
||||
},
|
||||
"roles": {
|
||||
"S3AdminRole": {
|
||||
"trustPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": [
|
||||
"test-oidc",
|
||||
"test-ldap"
|
||||
]
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"attachedPolicies": [
|
||||
"S3AdminPolicy"
|
||||
],
|
||||
"description": "Full administrative access to S3 resources"
|
||||
},
|
||||
"S3ReadOnlyRole": {
|
||||
"trustPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": [
|
||||
"test-oidc",
|
||||
"test-ldap"
|
||||
]
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"attachedPolicies": [
|
||||
"S3ReadOnlyPolicy"
|
||||
],
|
||||
"description": "Read-only access to S3 resources"
|
||||
},
|
||||
"S3WriteOnlyRole": {
|
||||
"trustPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": [
|
||||
"test-oidc",
|
||||
"test-ldap"
|
||||
]
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"attachedPolicies": [
|
||||
"S3WriteOnlyPolicy"
|
||||
],
|
||||
"description": "Write-only access to S3 resources"
|
||||
}
|
||||
},
|
||||
"policies": {
|
||||
"S3AdminPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:*",
|
||||
"iam:*"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*",
|
||||
"arn:aws:s3:::*/*",
|
||||
"arn:aws:iam:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"S3ReadOnlyPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetObject",
|
||||
"s3:GetObjectVersion",
|
||||
"s3:ListBucket",
|
||||
"s3:ListBucketVersions",
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetBucketVersioning"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*",
|
||||
"arn:aws:s3:::*/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"S3WriteOnlyPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:PutObject",
|
||||
"s3:PutObjectAcl",
|
||||
"s3:DeleteObject",
|
||||
"s3:DeleteObjectVersion",
|
||||
"s3:InitiateMultipartUpload",
|
||||
"s3:UploadPart",
|
||||
"s3:CompleteMultipartUpload",
|
||||
"s3:AbortMultipartUpload",
|
||||
"s3:ListMultipartUploadParts"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"S3BucketManagementPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:CreateBucket",
|
||||
"s3:DeleteBucket",
|
||||
"s3:GetBucketPolicy",
|
||||
"s3:PutBucketPolicy",
|
||||
"s3:DeleteBucketPolicy",
|
||||
"s3:GetBucketVersioning",
|
||||
"s3:PutBucketVersioning"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"S3IPRestrictedPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:*"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*",
|
||||
"arn:aws:s3:::*/*"
|
||||
],
|
||||
"Condition": {
|
||||
"IpAddress": {
|
||||
"aws:SourceIp": [
|
||||
"192.168.1.0/24",
|
||||
"10.0.0.0/8"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"S3TimeBasedPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetObject",
|
||||
"s3:ListBucket"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*",
|
||||
"arn:aws:s3:::*/*"
|
||||
],
|
||||
"Condition": {
|
||||
"DateGreaterThan": {
|
||||
"aws:CurrentTime": "2023-01-01T00:00:00Z"
|
||||
},
|
||||
"DateLessThan": {
|
||||
"aws:CurrentTime": "2025-12-31T23:59:59Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"bucketPolicyExamples": {
|
||||
"PublicReadPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
|
||||
@@ -56,72 +56,33 @@ func NewCredentialStorePolicyManager(credentialManager *credential.CredentialMan
|
||||
}
|
||||
|
||||
// GetPolicies retrieves all IAM policies via credential store
|
||||
// Deprecated: This method delegates to the credential manager and will be moved/removed in a future release.
|
||||
func (cspm *CredentialStorePolicyManager) GetPolicies(ctx context.Context) (map[string]policy_engine.PolicyDocument, error) {
|
||||
// Get policies from credential store
|
||||
// We'll use the credential store to access the filer indirectly
|
||||
// Since policies are stored separately, we need to access the underlying store
|
||||
store := cspm.credentialManager.GetStore()
|
||||
glog.V(1).Infof("Getting policies from credential store: %T", store)
|
||||
|
||||
// Check if the store supports policy management
|
||||
if policyStore, ok := store.(credential.PolicyManager); ok {
|
||||
glog.V(1).Infof("Store supports policy management, calling GetPolicies")
|
||||
policies, err := policyStore.GetPolicies(ctx)
|
||||
if err != nil {
|
||||
glog.Errorf("Error getting policies from store: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
glog.V(1).Infof("Got %d policies from store", len(policies))
|
||||
return policies, nil
|
||||
} else {
|
||||
// Fallback: use empty policies for stores that don't support policies
|
||||
glog.V(1).Infof("Credential store doesn't support policy management, returning empty policies")
|
||||
return make(map[string]policy_engine.PolicyDocument), nil
|
||||
}
|
||||
return cspm.credentialManager.GetPolicies(ctx)
|
||||
}
|
||||
|
||||
// CreatePolicy creates a new IAM policy via credential store
|
||||
// Deprecated: This method delegates to the credential manager and will be moved/removed in a future release.
|
||||
func (cspm *CredentialStorePolicyManager) CreatePolicy(ctx context.Context, name string, document policy_engine.PolicyDocument) error {
|
||||
store := cspm.credentialManager.GetStore()
|
||||
|
||||
if policyStore, ok := store.(credential.PolicyManager); ok {
|
||||
return policyStore.CreatePolicy(ctx, name, document)
|
||||
}
|
||||
|
||||
return fmt.Errorf("credential store doesn't support policy creation")
|
||||
return cspm.credentialManager.CreatePolicy(ctx, name, document)
|
||||
}
|
||||
|
||||
// UpdatePolicy updates an existing IAM policy via credential store
|
||||
// Deprecated: This method delegates to the credential manager and will be moved/removed in a future release.
|
||||
func (cspm *CredentialStorePolicyManager) UpdatePolicy(ctx context.Context, name string, document policy_engine.PolicyDocument) error {
|
||||
store := cspm.credentialManager.GetStore()
|
||||
|
||||
if policyStore, ok := store.(credential.PolicyManager); ok {
|
||||
return policyStore.UpdatePolicy(ctx, name, document)
|
||||
}
|
||||
|
||||
return fmt.Errorf("credential store doesn't support policy updates")
|
||||
return cspm.credentialManager.UpdatePolicy(ctx, name, document)
|
||||
}
|
||||
|
||||
// DeletePolicy deletes an IAM policy via credential store
|
||||
// Deprecated: This method delegates to the credential manager and will be moved/removed in a future release.
|
||||
func (cspm *CredentialStorePolicyManager) DeletePolicy(ctx context.Context, name string) error {
|
||||
store := cspm.credentialManager.GetStore()
|
||||
|
||||
if policyStore, ok := store.(credential.PolicyManager); ok {
|
||||
return policyStore.DeletePolicy(ctx, name)
|
||||
}
|
||||
|
||||
return fmt.Errorf("credential store doesn't support policy deletion")
|
||||
return cspm.credentialManager.DeletePolicy(ctx, name)
|
||||
}
|
||||
|
||||
// GetPolicy retrieves a specific IAM policy via credential store
|
||||
// Deprecated: This method delegates to the credential manager and will be moved/removed in a future release.
|
||||
func (cspm *CredentialStorePolicyManager) GetPolicy(ctx context.Context, name string) (*policy_engine.PolicyDocument, error) {
|
||||
store := cspm.credentialManager.GetStore()
|
||||
|
||||
if policyStore, ok := store.(credential.PolicyManager); ok {
|
||||
return policyStore.GetPolicy(ctx, name)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("credential store doesn't support policy retrieval")
|
||||
return cspm.credentialManager.GetPolicy(ctx, name)
|
||||
}
|
||||
|
||||
// AdminServer policy management methods using credential.PolicyManager
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package dash
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
|
||||
)
|
||||
|
||||
// identityToServiceAccount converts an IAM identity to a ServiceAccount struct
|
||||
// This helper reduces code duplication across GetServiceAccounts, GetServiceAccountDetails,
|
||||
// UpdateServiceAccount, and GetServiceAccountByAccessKey
|
||||
func identityToServiceAccount(identity *iam_pb.Identity) (*ServiceAccount, error) {
|
||||
if identity == nil {
|
||||
return nil, fmt.Errorf("identity cannot be nil")
|
||||
}
|
||||
if !strings.HasPrefix(identity.GetName(), serviceAccountPrefix) {
|
||||
return nil, fmt.Errorf("not a service account: %s", identity.GetName())
|
||||
}
|
||||
|
||||
parts := strings.SplitN(identity.GetName(), ":", 3)
|
||||
if len(parts) < 3 {
|
||||
return nil, fmt.Errorf("invalid service account ID format")
|
||||
}
|
||||
|
||||
sa := &ServiceAccount{
|
||||
ID: identity.GetName(),
|
||||
ParentUser: parts[1],
|
||||
Status: StatusActive,
|
||||
CreateDate: getCreationDate(identity.GetActions()),
|
||||
Expiration: getExpiration(identity.GetActions()),
|
||||
}
|
||||
|
||||
// Get description from account display name
|
||||
if identity.Account != nil {
|
||||
sa.Description = identity.Account.GetDisplayName()
|
||||
}
|
||||
|
||||
// Get access key from credentials
|
||||
if len(identity.Credentials) > 0 {
|
||||
sa.AccessKeyId = identity.Credentials[0].GetAccessKey()
|
||||
}
|
||||
|
||||
// Check if disabled
|
||||
for _, action := range identity.GetActions() {
|
||||
if action == disabledAction {
|
||||
sa.Status = StatusInactive
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return sa, nil
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -18,140 +17,57 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
createdAtActionPrefix = "createdAt:"
|
||||
expirationActionPrefix = "expiresAt:"
|
||||
disabledAction = "__disabled__"
|
||||
serviceAccountPrefix = "sa:"
|
||||
accessKeyPrefix = "ABIA" // Service account access keys use ABIA prefix
|
||||
serviceAccountPrefix = "sa:"
|
||||
accessKeyPrefix = "ABIA" // Service account access keys use ABIA prefix
|
||||
|
||||
// Status constants
|
||||
StatusActive = "Active"
|
||||
StatusInactive = "Inactive"
|
||||
)
|
||||
|
||||
// Helper functions for managing creation timestamps in actions
|
||||
func getCreationDate(actions []string) time.Time {
|
||||
for _, action := range actions {
|
||||
if strings.HasPrefix(action, createdAtActionPrefix) {
|
||||
timestampStr := strings.TrimPrefix(action, createdAtActionPrefix)
|
||||
if timestamp, err := strconv.ParseInt(timestampStr, 10, 64); err == nil {
|
||||
return time.Unix(timestamp, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
return time.Time{} // Return zero time for legacy service accounts without stored creation date
|
||||
}
|
||||
|
||||
func setCreationDate(actions []string, createDate time.Time) []string {
|
||||
// Remove any existing createdAt action
|
||||
filtered := make([]string, 0, len(actions)+1)
|
||||
for _, action := range actions {
|
||||
if !strings.HasPrefix(action, createdAtActionPrefix) {
|
||||
filtered = append(filtered, action)
|
||||
}
|
||||
}
|
||||
// Add new createdAt action
|
||||
filtered = append(filtered, fmt.Sprintf("%s%d", createdAtActionPrefix, createDate.Unix()))
|
||||
return filtered
|
||||
}
|
||||
|
||||
// Helper functions for managing expiration timestamps in actions
|
||||
func getExpiration(actions []string) time.Time {
|
||||
for _, action := range actions {
|
||||
if strings.HasPrefix(action, expirationActionPrefix) {
|
||||
timestampStr := strings.TrimPrefix(action, expirationActionPrefix)
|
||||
if timestamp, err := strconv.ParseInt(timestampStr, 10, 64); err == nil {
|
||||
return time.Unix(timestamp, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
return time.Time{} // No expiration set
|
||||
}
|
||||
|
||||
func setExpiration(actions []string, expiration time.Time) []string {
|
||||
// Remove any existing expiration action
|
||||
filtered := make([]string, 0, len(actions)+1)
|
||||
for _, action := range actions {
|
||||
if !strings.HasPrefix(action, expirationActionPrefix) {
|
||||
filtered = append(filtered, action)
|
||||
}
|
||||
}
|
||||
// Add new expiration action if not zero
|
||||
if !expiration.IsZero() {
|
||||
filtered = append(filtered, fmt.Sprintf("%s%d", expirationActionPrefix, expiration.Unix()))
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
// GetServiceAccounts returns all service accounts, optionally filtered by parent user
|
||||
// NOTE: Service accounts are stored as special identities with "sa:" prefix
|
||||
func (s *AdminServer) GetServiceAccounts(ctx context.Context, parentUser string) ([]ServiceAccount, error) {
|
||||
if s.credentialManager == nil {
|
||||
return nil, fmt.Errorf("credential manager not available")
|
||||
}
|
||||
|
||||
// Load the current configuration to find service account identities
|
||||
config, err := s.credentialManager.LoadConfiguration(ctx)
|
||||
pbAccounts, err := s.credentialManager.ListServiceAccounts(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load configuration: %w", err)
|
||||
return nil, fmt.Errorf("failed to list service accounts: %w", err)
|
||||
}
|
||||
|
||||
var accounts []ServiceAccount
|
||||
|
||||
// Service accounts are stored as identities with "sa:" prefix in their name
|
||||
// Format: "sa:<parent_user>:<uuid>"
|
||||
for _, identity := range config.GetIdentities() {
|
||||
if !strings.HasPrefix(identity.GetName(), serviceAccountPrefix) {
|
||||
for _, sa := range pbAccounts {
|
||||
if sa == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.SplitN(identity.GetName(), ":", 3)
|
||||
if len(parts) < 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
parent := parts[1]
|
||||
saId := identity.GetName()
|
||||
|
||||
// Filter by parent user if specified
|
||||
if parentUser != "" && parent != parentUser {
|
||||
if parentUser != "" && sa.ParentUser != parentUser {
|
||||
continue
|
||||
}
|
||||
|
||||
// Extract description from account display name if available
|
||||
description := ""
|
||||
status := StatusActive
|
||||
if identity.Account != nil {
|
||||
description = identity.Account.GetDisplayName()
|
||||
if sa.Disabled {
|
||||
status = StatusInactive
|
||||
}
|
||||
|
||||
// Get access key from credentials
|
||||
accessKey := ""
|
||||
if len(identity.Credentials) > 0 {
|
||||
accessKey = identity.Credentials[0].GetAccessKey()
|
||||
// Service accounts use ABIA prefix
|
||||
if !strings.HasPrefix(accessKey, accessKeyPrefix) {
|
||||
continue // Not a service account
|
||||
}
|
||||
}
|
||||
|
||||
// Check if disabled (stored in actions)
|
||||
for _, action := range identity.GetActions() {
|
||||
if action == disabledAction {
|
||||
status = StatusInactive
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
accounts = append(accounts, ServiceAccount{
|
||||
ID: saId,
|
||||
ParentUser: parent,
|
||||
Description: description,
|
||||
AccessKeyId: accessKey,
|
||||
account := ServiceAccount{
|
||||
ID: sa.Id,
|
||||
ParentUser: sa.ParentUser,
|
||||
Description: sa.Description,
|
||||
Status: status,
|
||||
CreateDate: getCreationDate(identity.GetActions()),
|
||||
Expiration: getExpiration(identity.GetActions()),
|
||||
})
|
||||
CreateDate: time.Unix(sa.CreatedAt, 0),
|
||||
}
|
||||
|
||||
if sa.Expiration > 0 {
|
||||
account.Expiration = time.Unix(sa.Expiration, 0)
|
||||
}
|
||||
|
||||
if sa.Credential != nil {
|
||||
account.AccessKeyId = sa.Credential.AccessKey
|
||||
}
|
||||
|
||||
accounts = append(accounts, account)
|
||||
}
|
||||
|
||||
return accounts, nil
|
||||
@@ -163,43 +79,33 @@ func (s *AdminServer) GetServiceAccountDetails(ctx context.Context, id string) (
|
||||
return nil, fmt.Errorf("credential manager not available")
|
||||
}
|
||||
|
||||
// Get the identity
|
||||
identity, err := s.credentialManager.GetUser(ctx, id)
|
||||
sa, err := s.credentialManager.GetServiceAccount(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrServiceAccountNotFound, id)
|
||||
return nil, fmt.Errorf("failed to get service account: %w", err)
|
||||
}
|
||||
if sa == nil {
|
||||
return nil, ErrServiceAccountNotFound
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(identity.GetName(), serviceAccountPrefix) {
|
||||
return nil, fmt.Errorf("%w: not a service account: %s", ErrServiceAccountNotFound, id)
|
||||
}
|
||||
|
||||
parts := strings.SplitN(identity.GetName(), ":", 3)
|
||||
if len(parts) < 3 {
|
||||
return nil, fmt.Errorf("invalid service account ID format")
|
||||
status := StatusActive
|
||||
if sa.Disabled {
|
||||
status = StatusInactive
|
||||
}
|
||||
|
||||
account := &ServiceAccount{
|
||||
ID: id,
|
||||
ParentUser: parts[1],
|
||||
Status: StatusActive,
|
||||
CreateDate: getCreationDate(identity.GetActions()),
|
||||
Expiration: getExpiration(identity.GetActions()),
|
||||
ID: sa.Id,
|
||||
ParentUser: sa.ParentUser,
|
||||
Description: sa.Description,
|
||||
Status: status,
|
||||
CreateDate: time.Unix(sa.CreatedAt, 0),
|
||||
}
|
||||
|
||||
if identity.Account != nil {
|
||||
account.Description = identity.Account.GetDisplayName()
|
||||
if sa.Expiration > 0 {
|
||||
account.Expiration = time.Unix(sa.Expiration, 0)
|
||||
}
|
||||
|
||||
if len(identity.Credentials) > 0 {
|
||||
account.AccessKeyId = identity.Credentials[0].GetAccessKey()
|
||||
}
|
||||
|
||||
// Check if disabled
|
||||
for _, action := range identity.GetActions() {
|
||||
if action == disabledAction {
|
||||
account.Status = StatusInactive
|
||||
break
|
||||
}
|
||||
if sa.Credential != nil {
|
||||
account.AccessKeyId = sa.Credential.AccessKey
|
||||
}
|
||||
|
||||
return account, nil
|
||||
@@ -212,55 +118,48 @@ func (s *AdminServer) CreateServiceAccount(ctx context.Context, req CreateServic
|
||||
}
|
||||
|
||||
// Validate parent user exists
|
||||
_, err := s.credentialManager.GetUser(ctx, req.ParentUser)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parent user not found: %s", req.ParentUser)
|
||||
if _, err := s.credentialManager.GetUser(ctx, req.ParentUser); err != nil {
|
||||
return nil, fmt.Errorf("parent user lookup failed for %s: %w", req.ParentUser, err)
|
||||
}
|
||||
|
||||
// Generate unique ID and credentials
|
||||
uuid := generateAccountId()
|
||||
// Maintain consistent ID format: sa:<parent>:<uuid>
|
||||
saId := fmt.Sprintf("sa:%s:%s", req.ParentUser, uuid)
|
||||
accessKey := accessKeyPrefix + generateAccessKey()[len(accessKeyPrefix):] // Use ABIA prefix for service accounts
|
||||
|
||||
accessKey := accessKeyPrefix + generateAccessKey()[len(accessKeyPrefix):]
|
||||
secretKey := generateSecretKey()
|
||||
|
||||
// Create the service account as a special identity
|
||||
now := time.Now()
|
||||
|
||||
// Parse expiration if provided
|
||||
var expiration time.Time
|
||||
sa := &iam_pb.ServiceAccount{
|
||||
Id: saId,
|
||||
ParentUser: req.ParentUser,
|
||||
Description: req.Description,
|
||||
Credential: &iam_pb.Credential{
|
||||
AccessKey: accessKey,
|
||||
SecretKey: secretKey,
|
||||
Status: StatusActive,
|
||||
},
|
||||
CreatedAt: now.Unix(),
|
||||
Disabled: false,
|
||||
}
|
||||
|
||||
if req.Expiration != "" {
|
||||
var err error
|
||||
expiration, err = time.Parse(time.RFC3339, req.Expiration)
|
||||
exp, err := time.Parse(time.RFC3339, req.Expiration)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid expiration format: %w", err)
|
||||
}
|
||||
sa.Expiration = exp.Unix()
|
||||
}
|
||||
|
||||
identity := &iam_pb.Identity{
|
||||
Name: saId,
|
||||
Account: &iam_pb.Account{
|
||||
Id: uuid,
|
||||
DisplayName: req.Description,
|
||||
},
|
||||
Credentials: []*iam_pb.Credential{
|
||||
{
|
||||
AccessKey: accessKey,
|
||||
SecretKey: secretKey,
|
||||
},
|
||||
},
|
||||
// Store creation date and expiration in actions
|
||||
Actions: setExpiration(setCreationDate([]string{}, now), expiration),
|
||||
}
|
||||
|
||||
// Create the service account
|
||||
err = s.credentialManager.CreateUser(ctx, identity)
|
||||
if err != nil {
|
||||
if err := s.credentialManager.CreateServiceAccount(ctx, sa); err != nil {
|
||||
return nil, fmt.Errorf("failed to create service account: %w", err)
|
||||
}
|
||||
|
||||
glog.V(1).Infof("Created service account %s for user %s", saId, req.ParentUser)
|
||||
|
||||
return &ServiceAccount{
|
||||
resp := &ServiceAccount{
|
||||
ID: saId,
|
||||
ParentUser: req.ParentUser,
|
||||
Description: req.Description,
|
||||
@@ -268,8 +167,13 @@ func (s *AdminServer) CreateServiceAccount(ctx context.Context, req CreateServic
|
||||
SecretAccessKey: secretKey, // Only returned on creation
|
||||
Status: StatusActive,
|
||||
CreateDate: now,
|
||||
Expiration: expiration,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if sa.Expiration > 0 {
|
||||
resp.Expiration = time.Unix(sa.Expiration, 0)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// UpdateServiceAccount updates an existing service account
|
||||
@@ -278,85 +182,67 @@ func (s *AdminServer) UpdateServiceAccount(ctx context.Context, id string, req U
|
||||
return nil, fmt.Errorf("credential manager not available")
|
||||
}
|
||||
|
||||
// Get existing identity
|
||||
identity, err := s.credentialManager.GetUser(ctx, id)
|
||||
sa, err := s.credentialManager.GetServiceAccount(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrServiceAccountNotFound, id)
|
||||
return nil, fmt.Errorf("failed to get service account: %w", err)
|
||||
}
|
||||
if sa == nil {
|
||||
return nil, ErrServiceAccountNotFound
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(identity.GetName(), serviceAccountPrefix) {
|
||||
return nil, fmt.Errorf("%w: not a service account: %s", ErrServiceAccountNotFound, id)
|
||||
}
|
||||
|
||||
// Update description if provided
|
||||
if req.Description != "" {
|
||||
if identity.Account == nil {
|
||||
identity.Account = &iam_pb.Account{}
|
||||
}
|
||||
identity.Account.DisplayName = req.Description
|
||||
sa.Description = req.Description
|
||||
}
|
||||
|
||||
// Update status by adding/removing disabled action
|
||||
if req.Status != "" {
|
||||
// Remove existing disabled marker
|
||||
newActions := make([]string, 0, len(identity.Actions))
|
||||
for _, action := range identity.Actions {
|
||||
if action != disabledAction {
|
||||
newActions = append(newActions, action)
|
||||
}
|
||||
switch req.Status {
|
||||
case StatusInactive:
|
||||
sa.Disabled = true
|
||||
case StatusActive:
|
||||
sa.Disabled = false
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid status value: %s (must be %s or %s)", req.Status, StatusActive, StatusInactive)
|
||||
}
|
||||
// Add disabled action if setting to Inactive
|
||||
if req.Status == StatusInactive {
|
||||
newActions = append(newActions, disabledAction)
|
||||
}
|
||||
identity.Actions = newActions
|
||||
}
|
||||
|
||||
// Update expiration if provided
|
||||
if req.Expiration != "" {
|
||||
var expiration time.Time
|
||||
var err error
|
||||
expiration, err = time.Parse(time.RFC3339, req.Expiration)
|
||||
exp, err := time.Parse(time.RFC3339, req.Expiration)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid expiration format: %w", err)
|
||||
}
|
||||
identity.Actions = setExpiration(identity.Actions, expiration)
|
||||
sa.Expiration = exp.Unix()
|
||||
}
|
||||
|
||||
// Update the identity
|
||||
err = s.credentialManager.UpdateUser(ctx, id, identity)
|
||||
if err != nil {
|
||||
if err := s.credentialManager.UpdateServiceAccount(ctx, id, sa); err != nil {
|
||||
return nil, fmt.Errorf("failed to update service account: %w", err)
|
||||
}
|
||||
|
||||
glog.V(1).Infof("Updated service account %s", id)
|
||||
|
||||
// Build response
|
||||
parts := strings.SplitN(id, ":", 3)
|
||||
if len(parts) < 3 {
|
||||
return nil, fmt.Errorf("invalid service account ID format")
|
||||
status := StatusActive
|
||||
if sa.Disabled {
|
||||
status = StatusInactive
|
||||
}
|
||||
|
||||
result := &ServiceAccount{
|
||||
ID: id,
|
||||
ParentUser: parts[1],
|
||||
Description: identity.Account.GetDisplayName(),
|
||||
Status: StatusActive,
|
||||
CreateDate: getCreationDate(identity.Actions),
|
||||
accessKeyId := ""
|
||||
if sa.Credential != nil {
|
||||
accessKeyId = sa.Credential.AccessKey
|
||||
}
|
||||
|
||||
if len(identity.Credentials) > 0 {
|
||||
result.AccessKeyId = identity.Credentials[0].GetAccessKey()
|
||||
resp := &ServiceAccount{
|
||||
ID: sa.Id,
|
||||
ParentUser: sa.ParentUser,
|
||||
Description: sa.Description,
|
||||
Status: status,
|
||||
CreateDate: time.Unix(sa.CreatedAt, 0),
|
||||
AccessKeyId: accessKeyId,
|
||||
}
|
||||
|
||||
for _, action := range identity.Actions {
|
||||
if action == disabledAction {
|
||||
result.Status = StatusInactive
|
||||
break
|
||||
}
|
||||
if sa.Expiration > 0 {
|
||||
resp.Expiration = time.Unix(sa.Expiration, 0)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// DeleteServiceAccount deletes a service account
|
||||
@@ -365,19 +251,16 @@ func (s *AdminServer) DeleteServiceAccount(ctx context.Context, id string) error
|
||||
return fmt.Errorf("credential manager not available")
|
||||
}
|
||||
|
||||
// Verify it's a service account
|
||||
identity, err := s.credentialManager.GetUser(ctx, id)
|
||||
// Verify existence
|
||||
sa, err := s.credentialManager.GetServiceAccount(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrServiceAccountNotFound, id)
|
||||
return fmt.Errorf("failed to check service account: %w", err)
|
||||
}
|
||||
if sa == nil {
|
||||
return ErrServiceAccountNotFound
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(identity.GetName(), serviceAccountPrefix) {
|
||||
return fmt.Errorf("%w: not a service account: %s", ErrServiceAccountNotFound, id)
|
||||
}
|
||||
|
||||
// Delete the identity
|
||||
err = s.credentialManager.DeleteUser(ctx, id)
|
||||
if err != nil {
|
||||
if err := s.credentialManager.DeleteServiceAccount(ctx, id); err != nil {
|
||||
return fmt.Errorf("failed to delete service account: %w", err)
|
||||
}
|
||||
|
||||
@@ -395,40 +278,30 @@ func (s *AdminServer) GetServiceAccountByAccessKey(ctx context.Context, accessKe
|
||||
return nil, fmt.Errorf("credential manager not available")
|
||||
}
|
||||
|
||||
// Find identity by access key
|
||||
identity, err := s.credentialManager.GetUserByAccessKey(ctx, accessKey)
|
||||
// Efficient lookup is now supported by the interface and optimized stores
|
||||
sa, err := s.credentialManager.GetStore().GetServiceAccountByAccessKey(ctx, accessKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("service account not found for access key: %s", accessKey)
|
||||
return nil, fmt.Errorf("failed to find service account: %w", err)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(identity.GetName(), serviceAccountPrefix) {
|
||||
return nil, fmt.Errorf("not a service account")
|
||||
status := StatusActive
|
||||
if sa.Disabled {
|
||||
status = StatusInactive
|
||||
}
|
||||
|
||||
parts := strings.SplitN(identity.GetName(), ":", 3)
|
||||
if len(parts) < 3 {
|
||||
return nil, fmt.Errorf("invalid service account ID format")
|
||||
accessKeyId := ""
|
||||
if sa.Credential != nil {
|
||||
accessKeyId = sa.Credential.AccessKey
|
||||
}
|
||||
|
||||
account := &ServiceAccount{
|
||||
ID: identity.GetName(),
|
||||
ParentUser: parts[1],
|
||||
AccessKeyId: accessKey,
|
||||
Status: StatusActive,
|
||||
CreateDate: getCreationDate(identity.GetActions()),
|
||||
Expiration: getExpiration(identity.GetActions()),
|
||||
resp := &ServiceAccount{
|
||||
ID: sa.Id,
|
||||
ParentUser: sa.ParentUser,
|
||||
Description: sa.Description,
|
||||
AccessKeyId: accessKeyId,
|
||||
Status: status,
|
||||
CreateDate: time.Unix(sa.CreatedAt, 0),
|
||||
}
|
||||
|
||||
if identity.Account != nil {
|
||||
account.Description = identity.Account.GetDisplayName()
|
||||
if sa.Expiration > 0 {
|
||||
resp.Expiration = time.Unix(sa.Expiration, 0)
|
||||
}
|
||||
|
||||
for _, action := range identity.GetActions() {
|
||||
if action == disabledAction {
|
||||
account.Status = StatusInactive
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return account, nil
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/admin/view/layout"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/security"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/http/client"
|
||||
)
|
||||
@@ -121,7 +122,6 @@ func (h *FileBrowserHandlers) DeleteFile(c *gin.Context) {
|
||||
})
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete file: " + err.Error()})
|
||||
return
|
||||
@@ -228,7 +228,7 @@ func (h *FileBrowserHandlers) CreateFolder(c *gin.Context) {
|
||||
Name: filepath.Base(fullPath),
|
||||
IsDirectory: true,
|
||||
Attributes: &filer_pb.FuseAttributes{
|
||||
FileMode: uint32(0755 | os.ModeDir), // Directory mode
|
||||
FileMode: uint32(0o755 | os.ModeDir), // Directory mode
|
||||
Uid: filer_pb.OS_UID,
|
||||
Gid: filer_pb.OS_GID,
|
||||
Crtime: time.Now().Unix(),
|
||||
@@ -239,7 +239,6 @@ func (h *FileBrowserHandlers) CreateFolder(c *gin.Context) {
|
||||
})
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create folder: " + err.Error()})
|
||||
return
|
||||
@@ -364,6 +363,22 @@ func (h *FileBrowserHandlers) uploadFileToFiler(filePath string, fileHeader *mul
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Load security configuration
|
||||
v := util.GetViper()
|
||||
|
||||
// Read Filer JWT token from security.toml
|
||||
signingKey := security.SigningKey(v.GetString("jwt.filer_signing.key"))
|
||||
expiresAfterSec := v.GetInt("jwt.filer_signing.expires_after_seconds")
|
||||
|
||||
// Generate JWT token to authenticate with Filer
|
||||
var jwtToken security.EncodedJwt
|
||||
if len(signingKey) > 0 {
|
||||
jwtToken = security.GenJwtForFilerServer(signingKey, expiresAfterSec)
|
||||
glog.V(4).Infof("Generated JWT token for filer upload (expires in %d sec)", expiresAfterSec)
|
||||
} else {
|
||||
glog.V(2).Info("No JWT signing key configured, uploading without authentication")
|
||||
}
|
||||
|
||||
// Create multipart form data
|
||||
var body bytes.Buffer
|
||||
writer := multipart.NewWriter(&body)
|
||||
@@ -407,6 +422,12 @@ func (h *FileBrowserHandlers) uploadFileToFiler(filePath string, fileHeader *mul
|
||||
// Set content type with boundary
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
// Add JWT Token to Authorization Header
|
||||
if jwtToken != "" {
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(jwtToken)))
|
||||
glog.V(4).Infof("Added JWT authorization header")
|
||||
}
|
||||
|
||||
// Send request using TLS-aware HTTP client with 60s timeout for large file uploads
|
||||
// lgtm[go/ssrf]
|
||||
// Safe: filerAddress validated by validateFilerAddress() to match configured filer
|
||||
@@ -595,6 +616,29 @@ func (h *FileBrowserHandlers) DownloadFile(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
client := h.newClientWithTimeout(5 * time.Minute) // Longer timeout for large file downloads
|
||||
|
||||
// Load security configuration
|
||||
v := util.GetViper()
|
||||
|
||||
// Read Filer JWT token from security.toml
|
||||
signingKey := security.SigningKey(v.GetString("jwt.filer_signing.read.key"))
|
||||
expiresAfterSec := v.GetInt("jwt.filer_signing..read.expires_after_seconds")
|
||||
|
||||
// Generate JWT token to authenticate with Filer
|
||||
var jwtToken security.EncodedJwt
|
||||
if len(signingKey) > 0 {
|
||||
jwtToken = security.GenJwtForFilerServer(signingKey, expiresAfterSec)
|
||||
glog.V(4).Infof("Generated JWT token for filer download (expires in %d sec)", expiresAfterSec)
|
||||
} else {
|
||||
glog.V(2).Info("No JWT signing key configured, downloadading without authentication")
|
||||
}
|
||||
|
||||
// Add JWT Token to Authorization Header
|
||||
if jwtToken != "" {
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(jwtToken)))
|
||||
glog.V(4).Infof("Added JWT authorization header")
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadGateway, gin.H{"error": "Failed to fetch file from filer: " + err.Error()})
|
||||
@@ -687,7 +731,6 @@ func (h *FileBrowserHandlers) ViewFile(c *gin.Context) {
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get file metadata: " + err.Error()})
|
||||
return
|
||||
@@ -837,7 +880,6 @@ func (h *FileBrowserHandlers) GetFileProperties(c *gin.Context) {
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get file properties: " + err.Error()})
|
||||
return
|
||||
|
||||
+3
-3
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3
-3
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Shared IAM utility functions for the SeaweedFS Admin Dashboard.
|
||||
*/
|
||||
|
||||
// Delete user function
|
||||
async function deleteUser(username) {
|
||||
showDeleteConfirm(username, async function () {
|
||||
try {
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const response = await fetch(`/api/users/${encodedUsername}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
showAlert('User deleted successfully', 'success');
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
} else {
|
||||
const error = await response.json().catch(() => ({}));
|
||||
showAlert('Failed to delete user: ' + (error.error || 'Unknown error'), 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting user:', error);
|
||||
showAlert('Failed to delete user: ' + error.message, 'error');
|
||||
}
|
||||
}, 'Are you sure you want to delete this user? This action cannot be undone.');
|
||||
}
|
||||
|
||||
// Delete access key function
|
||||
async function deleteAccessKey(username, accessKey) {
|
||||
showDeleteConfirm(accessKey, async function () {
|
||||
try {
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const encodedAccessKey = encodeURIComponent(accessKey);
|
||||
const response = await fetch(`/api/users/${encodedUsername}/access-keys/${encodedAccessKey}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
showAlert('Access key deleted successfully', 'success');
|
||||
// If refreshAccessKeysList exists (in object_store_users.templ), use it
|
||||
if (typeof refreshAccessKeysList === 'function') {
|
||||
refreshAccessKeysList(username);
|
||||
} else {
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
}
|
||||
} else {
|
||||
const error = await response.json().catch(() => ({}));
|
||||
showAlert('Failed to delete access key: ' + (error.error || 'Unknown error'), 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting access key:', error);
|
||||
showAlert('Failed to delete access key: ' + error.message, 'error');
|
||||
}
|
||||
}, 'Are you sure you want to delete this access key?');
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
/**
|
||||
* Modal Alerts - Bootstrap Modal replacement for native alert() and confirm()
|
||||
* Fixes Chrome auto-dismiss issue with native dialogs
|
||||
*
|
||||
* Usage:
|
||||
* showAlert('Message', 'success');
|
||||
* showConfirm('Delete this?', function() { });
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// Create and inject modal HTML into page if not already present
|
||||
function ensureModalsExist() {
|
||||
if (document.getElementById('globalAlertModal')) {
|
||||
return; // Already exists
|
||||
}
|
||||
|
||||
const modalsHTML = `
|
||||
<!-- Global Alert Modal -->
|
||||
<div class="modal fade" id="globalAlertModal" tabindex="-1" aria-labelledby="globalAlertModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" id="globalAlertModalHeader">
|
||||
<h5 class="modal-title" id="globalAlertModalLabel">
|
||||
<i class="fas fa-info-circle me-2" id="globalAlertModalIcon"></i>
|
||||
<span id="globalAlertModalTitle">Notice</span>
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="globalAlertModalBody">
|
||||
<!-- Message will be inserted here -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Global Confirm Modal -->
|
||||
<div class="modal fade" id="globalConfirmModal" tabindex="-1" aria-labelledby="globalConfirmModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-warning">
|
||||
<h5 class="modal-title" id="globalConfirmModalLabel">
|
||||
<i class="fas fa-question-circle me-2"></i><span id="globalConfirmModalTitleText">Confirm Action</span>
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="globalConfirmModalBody">
|
||||
<!-- Message will be inserted here -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="globalConfirmCancelBtn">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="globalConfirmOkBtn">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Global Delete Confirm Modal -->
|
||||
<div class="modal fade" id="globalDeleteModal" tabindex="-1" aria-labelledby="globalDeleteModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5 class="modal-title" id="globalDeleteModalLabel">
|
||||
<i class="fas fa-exclamation-triangle me-2"></i>Confirm Delete
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="mb-2" id="globalDeleteModalMessage">Are you sure you want to delete this item?</p>
|
||||
<p class="mb-0"><strong id="globalDeleteModalItemName"></strong></p>
|
||||
<p class="text-muted small mt-2 mb-0">This action cannot be undone.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" id="globalDeleteConfirmBtn">
|
||||
<i class="fas fa-trash me-1"></i>Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Inject modals at end of body
|
||||
document.body.insertAdjacentHTML('beforeend', modalsHTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an alert message using Bootstrap modal
|
||||
* @param {string} message - The message to display
|
||||
* @param {string|object} typeOrOptions - Type ('success', 'error', 'warning', 'info') or options object
|
||||
* @param {string} title - Optional custom title
|
||||
*/
|
||||
window.showAlert = function (message, typeOrOptions, title) {
|
||||
ensureModalsExist();
|
||||
|
||||
let type = 'info';
|
||||
let isHtml = false;
|
||||
|
||||
if (typeof typeOrOptions === 'object' && typeOrOptions !== null) {
|
||||
type = typeOrOptions.type || 'info';
|
||||
isHtml = typeOrOptions.isHtml || false;
|
||||
title = typeOrOptions.title || title;
|
||||
} else if (typeof typeOrOptions === 'string') {
|
||||
type = typeOrOptions;
|
||||
}
|
||||
|
||||
const modal = document.getElementById('globalAlertModal');
|
||||
const header = document.getElementById('globalAlertModalHeader');
|
||||
const titleEl = document.getElementById('globalAlertModalTitle');
|
||||
const bodyEl = document.getElementById('globalAlertModalBody');
|
||||
const iconEl = document.getElementById('globalAlertModalIcon');
|
||||
|
||||
// Configuration for different types
|
||||
const types = {
|
||||
'success': {
|
||||
title: 'Success',
|
||||
icon: 'fa-check-circle',
|
||||
headerClass: 'bg-success text-white',
|
||||
btnClose: 'btn-close-white'
|
||||
},
|
||||
'error': {
|
||||
title: 'Error',
|
||||
icon: 'fa-exclamation-triangle',
|
||||
headerClass: 'bg-danger text-white',
|
||||
btnClose: 'btn-close-white'
|
||||
},
|
||||
'warning': {
|
||||
title: 'Warning',
|
||||
icon: 'fa-exclamation-circle',
|
||||
headerClass: 'bg-warning text-dark',
|
||||
btnClose: ''
|
||||
},
|
||||
'info': {
|
||||
title: 'Notice',
|
||||
icon: 'fa-info-circle',
|
||||
headerClass: 'bg-info text-white',
|
||||
btnClose: 'btn-close-white'
|
||||
}
|
||||
};
|
||||
|
||||
const config = types[type] || types['info'];
|
||||
|
||||
// Update header styling
|
||||
header.className = 'modal-header ' + config.headerClass;
|
||||
const closeBtn = header.querySelector('.btn-close');
|
||||
closeBtn.className = 'btn-close ' + config.btnClose;
|
||||
|
||||
// Update icon
|
||||
iconEl.className = 'fas ' + config.icon + ' me-2';
|
||||
|
||||
// Update title
|
||||
titleEl.textContent = title || config.title;
|
||||
|
||||
// Update body - support HTML or text
|
||||
if (isHtml || message.includes('<p>') || message.includes('<ul>')) {
|
||||
bodyEl.innerHTML = message;
|
||||
} else {
|
||||
bodyEl.innerHTML = '<p class="mb-0">' + escapeHtml(message) + '</p>';
|
||||
}
|
||||
|
||||
// Show modal
|
||||
const bsModal = new bootstrap.Modal(modal);
|
||||
bsModal.show();
|
||||
};
|
||||
|
||||
/**
|
||||
* Show a confirmation dialog using Bootstrap modal
|
||||
* @param {string} message - The confirmation message
|
||||
* @param {function} onConfirm - Callback function if user confirms
|
||||
* @param {function|object} onCancelOrOptions - Optional callback or options object
|
||||
* @param {string} title - Optional custom title
|
||||
*/
|
||||
window.showConfirm = function (message, onConfirm, onCancelOrOptions, title) {
|
||||
ensureModalsExist();
|
||||
|
||||
let onCancel = null;
|
||||
let isHtml = false;
|
||||
|
||||
if (typeof onCancelOrOptions === 'object' && onCancelOrOptions !== null) {
|
||||
onCancel = onCancelOrOptions.onCancel;
|
||||
isHtml = onCancelOrOptions.isHtml || false;
|
||||
title = onCancelOrOptions.title || null;
|
||||
} else {
|
||||
onCancel = onCancelOrOptions;
|
||||
}
|
||||
|
||||
const modalEl = document.getElementById('globalConfirmModal');
|
||||
const bodyEl = document.getElementById('globalConfirmModalBody');
|
||||
const titleEl = document.getElementById('globalConfirmModalTitleText');
|
||||
const okBtn = document.getElementById('globalConfirmOkBtn');
|
||||
const cancelBtn = document.getElementById('globalConfirmCancelBtn');
|
||||
|
||||
// Set title
|
||||
if (title) {
|
||||
titleEl.textContent = title;
|
||||
} else {
|
||||
titleEl.textContent = 'Confirm Action';
|
||||
}
|
||||
|
||||
// Set message
|
||||
if (isHtml || message.includes('<p>') || message.includes('<ul>')) {
|
||||
bodyEl.innerHTML = message;
|
||||
} else {
|
||||
bodyEl.innerHTML = '<p class="mb-0">' + escapeHtml(message) + '</p>';
|
||||
}
|
||||
|
||||
// Remove old event listeners by cloning buttons
|
||||
const newOkBtn = okBtn.cloneNode(true);
|
||||
const newCancelBtn = cancelBtn.cloneNode(true);
|
||||
okBtn.parentNode.replaceChild(newOkBtn, okBtn);
|
||||
cancelBtn.parentNode.replaceChild(newCancelBtn, cancelBtn);
|
||||
|
||||
const modal = new bootstrap.Modal(modalEl);
|
||||
|
||||
// Add event listeners
|
||||
newOkBtn.addEventListener('click', function () {
|
||||
modal.hide();
|
||||
if (typeof onConfirm === 'function') {
|
||||
onConfirm();
|
||||
}
|
||||
});
|
||||
|
||||
newCancelBtn.addEventListener('click', function () {
|
||||
modal.hide();
|
||||
if (typeof onCancel === 'function') {
|
||||
onCancel();
|
||||
}
|
||||
});
|
||||
|
||||
modal.show();
|
||||
};
|
||||
|
||||
/**
|
||||
* Show a delete confirmation dialog
|
||||
* @param {string} itemName - Name of the item to delete
|
||||
* @param {function} onConfirm - Callback function if user confirms deletion
|
||||
* @param {string} message - Optional custom message (default: "Are you sure you want to delete this item?")
|
||||
*/
|
||||
window.showDeleteConfirm = function (itemName, onConfirm, message) {
|
||||
ensureModalsExist();
|
||||
|
||||
const modalEl = document.getElementById('globalDeleteModal');
|
||||
const messageEl = document.getElementById('globalDeleteModalMessage');
|
||||
const itemNameEl = document.getElementById('globalDeleteModalItemName');
|
||||
const confirmBtn = document.getElementById('globalDeleteConfirmBtn');
|
||||
|
||||
// Set custom message if provided
|
||||
if (message) {
|
||||
messageEl.textContent = message;
|
||||
} else {
|
||||
messageEl.textContent = 'Are you sure you want to delete this item?';
|
||||
}
|
||||
|
||||
// Set item name
|
||||
itemNameEl.textContent = itemName;
|
||||
|
||||
// Remove old event listener by cloning button
|
||||
const newConfirmBtn = confirmBtn.cloneNode(true);
|
||||
confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);
|
||||
|
||||
const modal = new bootstrap.Modal(modalEl);
|
||||
|
||||
// Add new event listener
|
||||
newConfirmBtn.addEventListener('click', function () {
|
||||
modal.hide();
|
||||
if (typeof onConfirm === 'function') {
|
||||
onConfirm();
|
||||
}
|
||||
});
|
||||
|
||||
modal.show();
|
||||
};
|
||||
|
||||
/**
|
||||
* Escape HTML to prevent XSS
|
||||
*/
|
||||
function escapeHtml(text) {
|
||||
const map = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
};
|
||||
return text.replace(/[&<>"']/g, function (m) { return map[m]; });
|
||||
}
|
||||
|
||||
// Auto-initialize on DOMContentLoaded
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', ensureModalsExist);
|
||||
} else {
|
||||
ensureModalsExist();
|
||||
}
|
||||
|
||||
/**
|
||||
* AUTOMATIC OVERRIDE of native alert()
|
||||
* This makes ALL existing alert() calls automatically use Bootstrap modals
|
||||
*/
|
||||
window.alert = function (message) {
|
||||
// Auto-detect message type from content
|
||||
let type = 'info';
|
||||
const msg = String(message || '');
|
||||
const msgLower = msg.toLowerCase();
|
||||
|
||||
// Refined type inference to avoid false positives
|
||||
if (msgLower.includes('success') || msgLower.includes('successfully') || msgLower.includes('created') || msgLower.includes('updated') || msgLower.includes('saved')) {
|
||||
// Avoid "not successful"
|
||||
if (!msgLower.includes('not success')) {
|
||||
type = 'success';
|
||||
}
|
||||
}
|
||||
|
||||
if (type === 'info') {
|
||||
if (msgLower.includes('error') || msgLower.includes('failed') || msgLower.includes('invalid') || msgLower.includes('exception')) {
|
||||
type = 'error';
|
||||
} else if (msgLower.includes('warning') || msgLower.includes('required') || msgLower.includes('attention')) {
|
||||
type = 'warning';
|
||||
}
|
||||
}
|
||||
|
||||
showAlert(msg, type);
|
||||
};
|
||||
|
||||
console.log('Modal Alerts library loaded - native alert() overridden');
|
||||
console.log('For confirm(), use showConfirm() or showDeleteConfirm() instead of native confirm()');
|
||||
})();
|
||||
@@ -145,20 +145,6 @@ templ ClusterEcShards(data dash.ClusterEcShardsData) {
|
||||
</a>
|
||||
</th>
|
||||
}
|
||||
<th>
|
||||
<a href="#" onclick="sortBy('server')" class="text-dark text-decoration-none">
|
||||
Server
|
||||
if data.SortBy == "server" {
|
||||
if data.SortOrder == "asc" {
|
||||
<i class="fas fa-sort-up ms-1"></i>
|
||||
} else {
|
||||
<i class="fas fa-sort-down ms-1"></i>
|
||||
}
|
||||
} else {
|
||||
<i class="fas fa-sort ms-1 text-muted"></i>
|
||||
}
|
||||
</a>
|
||||
</th>
|
||||
if data.ShowDataCenterColumn {
|
||||
<th>
|
||||
<a href="#" onclick="sortBy('datacenter')" class="text-dark text-decoration-none">
|
||||
@@ -175,6 +161,20 @@ templ ClusterEcShards(data dash.ClusterEcShardsData) {
|
||||
</a>
|
||||
</th>
|
||||
}
|
||||
<th>
|
||||
<a href="#" onclick="sortBy('server')" class="text-dark text-decoration-none">
|
||||
Server
|
||||
if data.SortBy == "server" {
|
||||
if data.SortOrder == "asc" {
|
||||
<i class="fas fa-sort-up ms-1"></i>
|
||||
} else {
|
||||
<i class="fas fa-sort-down ms-1"></i>
|
||||
}
|
||||
} else {
|
||||
<i class="fas fa-sort ms-1 text-muted"></i>
|
||||
}
|
||||
</a>
|
||||
</th>
|
||||
if data.ShowRackColumn {
|
||||
<th>
|
||||
<a href="#" onclick="sortBy('rack')" class="text-dark text-decoration-none">
|
||||
@@ -215,14 +215,14 @@ templ ClusterEcShards(data dash.ClusterEcShardsData) {
|
||||
}
|
||||
</td>
|
||||
}
|
||||
<td>
|
||||
<code class="small">{shard.Server}</code>
|
||||
</td>
|
||||
if data.ShowDataCenterColumn {
|
||||
<td>
|
||||
<span class="badge bg-outline-primary">{shard.DataCenter}</span>
|
||||
</td>
|
||||
}
|
||||
<td>
|
||||
<code class="small">{shard.Server}</code>
|
||||
</td>
|
||||
if data.ShowRackColumn {
|
||||
<td>
|
||||
<span class="badge bg-outline-secondary">{shard.Rack}</span>
|
||||
@@ -341,10 +341,15 @@ templ ClusterEcShards(data dash.ClusterEcShardsData) {
|
||||
});
|
||||
}
|
||||
|
||||
function goToPage(event) {
|
||||
// Get data from the link element (not any child elements)
|
||||
const link = event.target.closest('a');
|
||||
const page = link.getAttribute('data-page');
|
||||
function goToPage(arg) {
|
||||
let page;
|
||||
if (typeof arg === 'number' || typeof arg === 'string') {
|
||||
page = arg;
|
||||
} else {
|
||||
// Get data from the link element (not any child elements)
|
||||
const link = arg.target.closest('a');
|
||||
page = link.getAttribute('data-page');
|
||||
}
|
||||
updateUrl({ page: page });
|
||||
}
|
||||
|
||||
@@ -387,7 +392,7 @@ templ ClusterEcShards(data dash.ClusterEcShardsData) {
|
||||
// Get data from the button element (not the icon inside it)
|
||||
const button = event.target.closest('button');
|
||||
const volumeId = button.getAttribute('data-volume-id');
|
||||
if (confirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`)) {
|
||||
showConfirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`, function() {
|
||||
fetch(`/api/storage/volumes/${volumeId}/repair`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -397,17 +402,18 @@ templ ClusterEcShards(data dash.ClusterEcShardsData) {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('Repair initiated successfully');
|
||||
showAlert('Repair initiated successfully', 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Failed to initiate repair: ' + data.error);
|
||||
showAlert('Failed to initiate repair: ' + data.error, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert('Error: ' + error.message);
|
||||
showAlert('Error: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
}
|
||||
|
||||
|
||||
@@ -218,60 +218,60 @@ func ClusterEcShards(data dash.ClusterEcShardsData) templ.Component {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<th><a href=\"#\" onclick=\"sortBy('server')\" class=\"text-dark text-decoration-none\">Server ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.SortBy == "server" {
|
||||
if data.SortOrder == "asc" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<i class=\"fas fa-sort-up ms-1\"></i>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<i class=\"fas fa-sort-down ms-1\"></i>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<i class=\"fas fa-sort ms-1 text-muted\"></i>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</a></th>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.ShowDataCenterColumn {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "<th><a href=\"#\" onclick=\"sortBy('datacenter')\" class=\"text-dark text-decoration-none\">Data Center ")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<th><a href=\"#\" onclick=\"sortBy('datacenter')\" class=\"text-dark text-decoration-none\">Data Center ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.SortBy == "datacenter" {
|
||||
if data.SortOrder == "asc" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<i class=\"fas fa-sort-up ms-1\"></i>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<i class=\"fas fa-sort-up ms-1\"></i>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "<i class=\"fas fa-sort-down ms-1\"></i>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<i class=\"fas fa-sort-down ms-1\"></i>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<i class=\"fas fa-sort ms-1 text-muted\"></i>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<i class=\"fas fa-sort ms-1 text-muted\"></i>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</a></th>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</a></th>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "<th><a href=\"#\" onclick=\"sortBy('server')\" class=\"text-dark text-decoration-none\">Server ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.SortBy == "server" {
|
||||
if data.SortOrder == "asc" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<i class=\"fas fa-sort-up ms-1\"></i>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "<i class=\"fas fa-sort-down ms-1\"></i>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<i class=\"fas fa-sort ms-1 text-muted\"></i>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</a></th>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.ShowRackColumn {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "<th><a href=\"#\" onclick=\"sortBy('rack')\" class=\"text-dark text-decoration-none\">Rack ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
@@ -356,42 +356,42 @@ func ClusterEcShards(data dash.ClusterEcShardsData) templ.Component {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "<td><code class=\"small\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(shard.Server)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 219, Col: 61}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</code></td>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.ShowDataCenterColumn {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "<td><span class=\"badge bg-outline-primary\">")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "<td><span class=\"badge bg-outline-primary\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 string
|
||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(shard.DataCenter)
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(shard.DataCenter)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 223, Col: 88}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 220, Col: 88}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "</span></td>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</span></td>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "<td><code class=\"small\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 string
|
||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(shard.Server)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 224, Col: 61}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "</code></td>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if data.ShowRackColumn {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "<td><span class=\"badge bg-outline-secondary\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
@@ -663,7 +663,7 @@ func ClusterEcShards(data dash.ClusterEcShardsData) templ.Component {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "<!-- JavaScript --><script>\n function sortBy(field) {\n const currentSort = \"{data.SortBy}\";\n const currentOrder = \"{data.SortOrder}\";\n let newOrder = 'asc';\n \n if (currentSort === field && currentOrder === 'asc') {\n newOrder = 'desc';\n }\n \n updateUrl({\n sortBy: field,\n sortOrder: newOrder,\n page: 1\n });\n }\n\n function goToPage(event) {\n // Get data from the link element (not any child elements)\n const link = event.target.closest('a');\n const page = link.getAttribute('data-page');\n updateUrl({ page: page });\n }\n\n function changePageSize() {\n const pageSize = document.getElementById('pageSizeSelect').value;\n updateUrl({ pageSize: pageSize, page: 1 });\n }\n\n function updateUrl(params) {\n const url = new URL(window.location);\n Object.keys(params).forEach(key => {\n if (params[key]) {\n url.searchParams.set(key, params[key]);\n } else {\n url.searchParams.delete(key);\n }\n });\n window.location.href = url.toString();\n }\n\n function exportEcShards() {\n const url = new URL('/api/storage/ec-shards/export', window.location.origin);\n const params = new URLSearchParams(window.location.search);\n params.forEach((value, key) => {\n url.searchParams.set(key, value);\n });\n window.open(url.toString(), '_blank');\n }\n\n function showShardDetails(event) {\n // Get data from the button element (not the icon inside it)\n const button = event.target.closest('button');\n const volumeId = button.getAttribute('data-volume-id');\n \n // Navigate to the EC volume details page\n window.location.href = `/storage/ec-volumes/${volumeId}`;\n }\n\n function repairVolume(event) {\n // Get data from the button element (not the icon inside it)\n const button = event.target.closest('button');\n const volumeId = button.getAttribute('data-volume-id');\n if (confirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`)) {\n fetch(`/api/storage/volumes/${volumeId}/repair`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n }\n })\n .then(response => response.json())\n .then(data => {\n if (data.success) {\n alert('Repair initiated successfully');\n location.reload();\n } else {\n alert('Failed to initiate repair: ' + data.error);\n }\n })\n .catch(error => {\n alert('Error: ' + error.message);\n });\n }\n }\n </script>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "<!-- JavaScript --><script>\n function sortBy(field) {\n const currentSort = \"{data.SortBy}\";\n const currentOrder = \"{data.SortOrder}\";\n let newOrder = 'asc';\n \n if (currentSort === field && currentOrder === 'asc') {\n newOrder = 'desc';\n }\n \n updateUrl({\n sortBy: field,\n sortOrder: newOrder,\n page: 1\n });\n }\n\n function goToPage(arg) {\n let page;\n if (typeof arg === 'number' || typeof arg === 'string') {\n page = arg;\n } else {\n // Get data from the link element (not any child elements)\n const link = arg.target.closest('a');\n page = link.getAttribute('data-page');\n }\n updateUrl({ page: page });\n }\n\n function changePageSize() {\n const pageSize = document.getElementById('pageSizeSelect').value;\n updateUrl({ pageSize: pageSize, page: 1 });\n }\n\n function updateUrl(params) {\n const url = new URL(window.location);\n Object.keys(params).forEach(key => {\n if (params[key]) {\n url.searchParams.set(key, params[key]);\n } else {\n url.searchParams.delete(key);\n }\n });\n window.location.href = url.toString();\n }\n\n function exportEcShards() {\n const url = new URL('/api/storage/ec-shards/export', window.location.origin);\n const params = new URLSearchParams(window.location.search);\n params.forEach((value, key) => {\n url.searchParams.set(key, value);\n });\n window.open(url.toString(), '_blank');\n }\n\n function showShardDetails(event) {\n // Get data from the button element (not the icon inside it)\n const button = event.target.closest('button');\n const volumeId = button.getAttribute('data-volume-id');\n \n // Navigate to the EC volume details page\n window.location.href = `/storage/ec-volumes/${volumeId}`;\n }\n\n function repairVolume(event) {\n // Get data from the button element (not the icon inside it)\n const button = event.target.closest('button');\n const volumeId = button.getAttribute('data-volume-id');\n showConfirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`, function() {\n fetch(`/api/storage/volumes/${volumeId}/repair`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n }\n })\n .then(response => response.json())\n .then(data => {\n if (data.success) {\n showAlert('Repair initiated successfully', 'success');\n location.reload();\n } else {\n showAlert('Failed to initiate repair: ' + data.error, 'error');\n }\n })\n .catch(error => {\n showAlert('Error: ' + error.message, 'error');\n });\n });\n }\n\n </script>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@@ -700,7 +700,7 @@ func displayShardDistribution(shard dash.EcShardWithInfo, allShards []dash.EcSha
|
||||
var templ_7745c5c3_Var24 string
|
||||
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(calculateDistributionSummary(shard.VolumeID, allShards))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 418, Col: 65}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 424, Col: 65}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
@@ -750,7 +750,7 @@ func displayVolumeStatus(shard dash.EcShardWithInfo) templ.Component {
|
||||
var templ_7745c5c3_Var26 string
|
||||
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", len(shard.MissingShards)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 428, Col: 129}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 434, Col: 129}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
@@ -768,7 +768,7 @@ func displayVolumeStatus(shard dash.EcShardWithInfo) templ.Component {
|
||||
var templ_7745c5c3_Var27 string
|
||||
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", len(shard.MissingShards)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 430, Col: 145}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 436, Col: 145}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
@@ -786,7 +786,7 @@ func displayVolumeStatus(shard dash.EcShardWithInfo) templ.Component {
|
||||
var templ_7745c5c3_Var28 string
|
||||
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", len(shard.MissingShards)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 432, Col: 138}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 438, Col: 138}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
@@ -804,7 +804,7 @@ func displayVolumeStatus(shard dash.EcShardWithInfo) templ.Component {
|
||||
var templ_7745c5c3_Var29 string
|
||||
templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", len(shard.MissingShards)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 434, Col: 137}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_shards.templ`, Line: 440, Col: 137}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
||||
@@ -378,7 +378,7 @@ templ ClusterEcVolumes(data dash.ClusterEcVolumesData) {
|
||||
|
||||
function repairVolume(event) {
|
||||
const volumeId = event.target.closest('button').getAttribute('data-volume-id');
|
||||
if (confirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`)) {
|
||||
showConfirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`, function() {
|
||||
fetch(`/api/storage/ec-volumes/${volumeId}/repair`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -393,16 +393,16 @@ templ ClusterEcVolumes(data dash.ClusterEcVolumesData) {
|
||||
})
|
||||
.then(data => {
|
||||
if (data && data.success) {
|
||||
alert('Repair initiated successfully');
|
||||
showAlert('Repair initiated successfully', 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Failed to initiate repair: ' + (data && data.error ? data.error : 'Unknown error'));
|
||||
showAlert('Failed to initiate repair: ' + (data && data.error ? data.error : 'Unknown error'), 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert('Error: ' + error.message);
|
||||
showAlert('Error: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
}
|
||||
|
||||
@@ -757,7 +757,7 @@ func ClusterEcVolumes(data dash.ClusterEcVolumesData) templ.Component {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "<!-- JavaScript --><script>\n function sortBy(field) {\n const currentSort = new URLSearchParams(window.location.search).get('sort_by');\n const currentOrder = new URLSearchParams(window.location.search).get('sort_order') || 'asc';\n \n let newOrder = 'asc';\n if (currentSort === field && currentOrder === 'asc') {\n newOrder = 'desc';\n }\n \n updateUrl({\n sort_by: field,\n sort_order: newOrder,\n page: 1\n });\n }\n\n function goToPage(event) {\n event.preventDefault();\n const page = event.target.closest('a').getAttribute('data-page');\n updateUrl({ page: page });\n }\n\n function changePageSize(newPageSize) {\n updateUrl({ page_size: newPageSize, page: 1 });\n }\n\n function updateUrl(params) {\n const url = new URL(window.location);\n Object.keys(params).forEach(key => {\n if (params[key] != null) {\n url.searchParams.set(key, params[key]);\n } else {\n url.searchParams.delete(key);\n }\n });\n window.location.href = url.toString();\n }\n\n function showVolumeDetails(event) {\n const volumeId = event.target.closest('button').getAttribute('data-volume-id');\n window.location.href = `/storage/ec-volumes/${volumeId}`;\n }\n\n function repairVolume(event) {\n const volumeId = event.target.closest('button').getAttribute('data-volume-id');\n if (confirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`)) {\n fetch(`/api/storage/ec-volumes/${volumeId}/repair`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n }\n })\n .then(response => {\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n return response.json();\n })\n .then(data => {\n if (data && data.success) {\n alert('Repair initiated successfully');\n location.reload();\n } else {\n alert('Failed to initiate repair: ' + (data && data.error ? data.error : 'Unknown error'));\n }\n })\n .catch(error => {\n alert('Error: ' + error.message);\n });\n }\n }\n </script>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "<!-- JavaScript --><script>\n function sortBy(field) {\n const currentSort = new URLSearchParams(window.location.search).get('sort_by');\n const currentOrder = new URLSearchParams(window.location.search).get('sort_order') || 'asc';\n \n let newOrder = 'asc';\n if (currentSort === field && currentOrder === 'asc') {\n newOrder = 'desc';\n }\n \n updateUrl({\n sort_by: field,\n sort_order: newOrder,\n page: 1\n });\n }\n\n function goToPage(event) {\n event.preventDefault();\n const page = event.target.closest('a').getAttribute('data-page');\n updateUrl({ page: page });\n }\n\n function changePageSize(newPageSize) {\n updateUrl({ page_size: newPageSize, page: 1 });\n }\n\n function updateUrl(params) {\n const url = new URL(window.location);\n Object.keys(params).forEach(key => {\n if (params[key] != null) {\n url.searchParams.set(key, params[key]);\n } else {\n url.searchParams.delete(key);\n }\n });\n window.location.href = url.toString();\n }\n\n function showVolumeDetails(event) {\n const volumeId = event.target.closest('button').getAttribute('data-volume-id');\n window.location.href = `/storage/ec-volumes/${volumeId}`;\n }\n\n function repairVolume(event) {\n const volumeId = event.target.closest('button').getAttribute('data-volume-id');\n showConfirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`, function() {\n fetch(`/api/storage/ec-volumes/${volumeId}/repair`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n }\n })\n .then(response => {\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n return response.json();\n })\n .then(data => {\n if (data && data.success) {\n showAlert('Repair initiated successfully', 'success');\n location.reload();\n } else {\n showAlert('Failed to initiate repair: ' + (data && data.error ? data.error : 'Unknown error'), 'error');\n }\n })\n .catch(error => {\n showAlert('Error: ' + error.message, 'error');\n });\n });\n }\n </script>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
@@ -372,10 +372,10 @@ templ CollectionDetails(data dash.CollectionDetailsData) {
|
||||
// Repair EC Volume
|
||||
function repairEcVolume(event) {
|
||||
const volumeId = event.target.closest('button').getAttribute('data-volume-id');
|
||||
if (confirm(`Are you sure you want to repair missing shards for EC volume ${volumeId}?`)) {
|
||||
showConfirm(`Are you sure you want to repair missing shards for EC volume ${volumeId}?`, function() {
|
||||
// TODO: Implement repair functionality
|
||||
alert('Repair functionality will be implemented soon.');
|
||||
}
|
||||
showAlert('Repair functionality will be implemented soon.', 'info');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
}
|
||||
}
|
||||
@@ -575,7 +575,7 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "<script>\n\t\t// Sorting functionality\n\t\tfunction sortBy(field) {\n\t\t\tconst currentSort = new URLSearchParams(window.location.search).get('sort_by');\n\t\t\tconst currentOrder = new URLSearchParams(window.location.search).get('sort_order') || 'asc';\n\t\t\t\n\t\t\tlet newOrder = 'asc';\n\t\t\tif (currentSort === field && currentOrder === 'asc') {\n\t\t\t\tnewOrder = 'desc';\n\t\t\t}\n\t\t\t\n\t\t\tconst url = new URL(window.location);\n\t\t\turl.searchParams.set('sort_by', field);\n\t\t\turl.searchParams.set('sort_order', newOrder);\n\t\t\turl.searchParams.set('page', '1'); // Reset to first page\n\t\t\twindow.location.href = url.toString();\n\t\t}\n\n\t\t// Pagination functionality\n\t\tfunction goToPage(event) {\n\t\t\tevent.preventDefault();\n\t\t\tconst page = event.target.closest('a').getAttribute('data-page');\n\t\t\tconst url = new URL(window.location);\n\t\t\turl.searchParams.set('page', page);\n\t\t\twindow.location.href = url.toString();\n\t\t}\n\n\t\t// Page size functionality\n\t\tfunction changePageSize(newPageSize) {\n\t\t\tconst url = new URL(window.location);\n\t\t\turl.searchParams.set('page_size', newPageSize);\n\t\t\turl.searchParams.set('page', '1'); // Reset to first page when changing page size\n\t\t\twindow.location.href = url.toString();\n\t\t}\n\n\t\t// Volume details\n\t\tfunction showVolumeDetails(event) {\n\t\t\tconst volumeId = event.target.closest('button').getAttribute('data-volume-id');\n\t\t\tconst server = event.target.closest('button').getAttribute('data-server');\n\t\t\twindow.location.href = `/storage/volumes/${volumeId}/${server}`;\n\t\t}\n\n\t\t// EC Volume details\n\t\tfunction showEcVolumeDetails(event) {\n\t\t\tconst volumeId = event.target.closest('button').getAttribute('data-volume-id');\n\t\t\twindow.location.href = `/storage/ec-volumes/${volumeId}`;\n\t\t}\n\n\t\t// Repair EC Volume\n\t\tfunction repairEcVolume(event) {\n\t\t\tconst volumeId = event.target.closest('button').getAttribute('data-volume-id');\n\t\t\tif (confirm(`Are you sure you want to repair missing shards for EC volume ${volumeId}?`)) {\n\t\t\t\t// TODO: Implement repair functionality\n\t\t\t\talert('Repair functionality will be implemented soon.');\n\t\t\t}\n\t\t}\n\t</script>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "<script>\n\t\t// Sorting functionality\n\t\tfunction sortBy(field) {\n\t\t\tconst currentSort = new URLSearchParams(window.location.search).get('sort_by');\n\t\t\tconst currentOrder = new URLSearchParams(window.location.search).get('sort_order') || 'asc';\n\t\t\t\n\t\t\tlet newOrder = 'asc';\n\t\t\tif (currentSort === field && currentOrder === 'asc') {\n\t\t\t\tnewOrder = 'desc';\n\t\t\t}\n\t\t\t\n\t\t\tconst url = new URL(window.location);\n\t\t\turl.searchParams.set('sort_by', field);\n\t\t\turl.searchParams.set('sort_order', newOrder);\n\t\t\turl.searchParams.set('page', '1'); // Reset to first page\n\t\t\twindow.location.href = url.toString();\n\t\t}\n\n\t\t// Pagination functionality\n\t\tfunction goToPage(event) {\n\t\t\tevent.preventDefault();\n\t\t\tconst page = event.target.closest('a').getAttribute('data-page');\n\t\t\tconst url = new URL(window.location);\n\t\t\turl.searchParams.set('page', page);\n\t\t\twindow.location.href = url.toString();\n\t\t}\n\n\t\t// Page size functionality\n\t\tfunction changePageSize(newPageSize) {\n\t\t\tconst url = new URL(window.location);\n\t\t\turl.searchParams.set('page_size', newPageSize);\n\t\t\turl.searchParams.set('page', '1'); // Reset to first page when changing page size\n\t\t\twindow.location.href = url.toString();\n\t\t}\n\n\t\t// Volume details\n\t\tfunction showVolumeDetails(event) {\n\t\t\tconst volumeId = event.target.closest('button').getAttribute('data-volume-id');\n\t\t\tconst server = event.target.closest('button').getAttribute('data-server');\n\t\t\twindow.location.href = `/storage/volumes/${volumeId}/${server}`;\n\t\t}\n\n\t\t// EC Volume details\n\t\tfunction showEcVolumeDetails(event) {\n\t\t\tconst volumeId = event.target.closest('button').getAttribute('data-volume-id');\n\t\t\twindow.location.href = `/storage/ec-volumes/${volumeId}`;\n\t\t}\n\n\t\t// Repair EC Volume\n\t\tfunction repairEcVolume(event) {\n\t\t\tconst volumeId = event.target.closest('button').getAttribute('data-volume-id');\n showConfirm(`Are you sure you want to repair missing shards for EC volume ${volumeId}?`, function() {\n\t\t\t\t// TODO: Implement repair functionality\n\t\t\t\tshowAlert('Repair functionality will be implemented soon.', 'info');\n\t\t\t});\n\t\t}\n\t</script>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
@@ -365,9 +365,10 @@ templ FileBrowser(data dash.FileBrowserData) {
|
||||
showFileProperties(path);
|
||||
break;
|
||||
case 'delete':
|
||||
if (confirm('Are you sure you want to delete "' + path + '"?')) {
|
||||
const fileName = path.split('/').pop();
|
||||
showDeleteConfirm(fileName, function() {
|
||||
deleteFile(path);
|
||||
}
|
||||
}, `Are you sure you want to delete "${fileName}"? This action cannot be undone.`);
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -395,14 +396,14 @@ templ FileBrowser(data dash.FileBrowserData) {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
alert('Error loading file properties: ' + data.error);
|
||||
showAlert('Error loading file properties: ' + data.error, 'error');
|
||||
} else {
|
||||
displayFileProperties(data);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching file properties:', error);
|
||||
alert('Error loading file properties: ' + error.message);
|
||||
showAlert('Error loading file properties: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -251,7 +251,7 @@ templ MaintenanceConfig(data *maintenance.MaintenanceConfigData) {
|
||||
}
|
||||
|
||||
function resetToDefaults() {
|
||||
if (confirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.')) {
|
||||
showConfirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.', function() {
|
||||
// Reset form to defaults (matching DefaultMaintenanceConfig values)
|
||||
document.getElementById('enabled').checked = false;
|
||||
document.getElementById('scanInterval').value = '30';
|
||||
@@ -261,7 +261,7 @@ templ MaintenanceConfig(data *maintenance.MaintenanceConfigData) {
|
||||
document.getElementById('maxRetries').value = '3';
|
||||
document.getElementById('retryDelay').value = '15';
|
||||
document.getElementById('taskRetention').value = '7';
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@@ -157,8 +157,10 @@ templ MaintenanceConfigSchema(data *maintenance.MaintenanceConfigData, schema *m
|
||||
})
|
||||
.then(response => {
|
||||
if (response.status === 401) {
|
||||
alert('Authentication required. Please log in first.');
|
||||
window.location.href = '/login';
|
||||
showAlert('Authentication required. Please log in first.', 'warning');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/login';
|
||||
}, 2000);
|
||||
return;
|
||||
}
|
||||
return response.json();
|
||||
@@ -166,20 +168,20 @@ templ MaintenanceConfigSchema(data *maintenance.MaintenanceConfigData, schema *m
|
||||
.then(data => {
|
||||
if (!data) return; // Skip if redirected to login
|
||||
if (data.success) {
|
||||
alert('Configuration saved successfully!');
|
||||
showAlert('Configuration saved successfully!', 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error saving configuration: ' + (data.error || 'Unknown error'));
|
||||
showAlert('Error saving configuration: ' + (data.error || 'Unknown error'), 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error saving configuration: ' + error.message);
|
||||
showAlert('Error saving configuration: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
|
||||
function resetToDefaults() {
|
||||
if (confirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.')) {
|
||||
showConfirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.', function() {
|
||||
fetch('/maintenance/config/defaults', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -189,17 +191,17 @@ templ MaintenanceConfigSchema(data *maintenance.MaintenanceConfigData, schema *m
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('Configuration reset to defaults!');
|
||||
showAlert('Configuration reset to defaults!', 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error resetting configuration: ' + (data.error || 'Unknown error'));
|
||||
showAlert('Error resetting configuration: ' + (data.error || 'Unknown error'), 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error resetting configuration: ' + error.message);
|
||||
showAlert('Error resetting configuration: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -273,7 +273,7 @@ func MaintenanceConfig(data *maintenance.MaintenanceConfigData) templ.Component
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</p></div></div></div></div></div></div></div></div><script>\n function saveConfiguration() {\n // First, get current configuration to preserve existing values\n fetch('/api/maintenance/config')\n .then(response => response.json())\n .then(currentConfig => {\n // Update only the fields from the form\n const updatedConfig = {\n ...currentConfig.config, // Preserve existing config\n enabled: document.getElementById('enabled').checked,\n scan_interval_seconds: parseInt(document.getElementById('scanInterval').value) * 60, // Convert to seconds\n worker_timeout_seconds: parseInt(document.getElementById('workerTimeout').value) * 60, // Convert to seconds\n task_timeout_seconds: parseInt(document.getElementById('taskTimeout').value) * 3600, // Convert to seconds\n retry_delay_seconds: parseInt(document.getElementById('retryDelay').value) * 60, // Convert to seconds\n max_retries: parseInt(document.getElementById('maxRetries').value),\n task_retention_seconds: parseInt(document.getElementById('taskRetention').value) * 24 * 3600, // Convert to seconds\n policy: {\n ...currentConfig.config.policy, // Preserve existing policy\n global_max_concurrent: parseInt(document.getElementById('globalMaxConcurrent').value)\n }\n };\n\n // Send the updated configuration\n return fetch('/api/maintenance/config', {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(updatedConfig)\n });\n })\n .then(response => response.json())\n .then(data => {\n if (data.success) {\n alert('Configuration saved successfully');\n location.reload(); // Reload to show updated values\n } else {\n alert('Failed to save configuration: ' + (data.error || 'Unknown error'));\n }\n })\n .catch(error => {\n alert('Error: ' + error.message);\n });\n }\n\n function resetToDefaults() {\n if (confirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.')) {\n // Reset form to defaults (matching DefaultMaintenanceConfig values)\n document.getElementById('enabled').checked = false;\n document.getElementById('scanInterval').value = '30';\n document.getElementById('workerTimeout').value = '5';\n document.getElementById('taskTimeout').value = '2';\n document.getElementById('globalMaxConcurrent').value = '4';\n document.getElementById('maxRetries').value = '3';\n document.getElementById('retryDelay').value = '15';\n document.getElementById('taskRetention').value = '7';\n }\n }\n </script>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</p></div></div></div></div></div></div></div></div><script>\n function saveConfiguration() {\n // First, get current configuration to preserve existing values\n fetch('/api/maintenance/config')\n .then(response => response.json())\n .then(currentConfig => {\n // Update only the fields from the form\n const updatedConfig = {\n ...currentConfig.config, // Preserve existing config\n enabled: document.getElementById('enabled').checked,\n scan_interval_seconds: parseInt(document.getElementById('scanInterval').value) * 60, // Convert to seconds\n worker_timeout_seconds: parseInt(document.getElementById('workerTimeout').value) * 60, // Convert to seconds\n task_timeout_seconds: parseInt(document.getElementById('taskTimeout').value) * 3600, // Convert to seconds\n retry_delay_seconds: parseInt(document.getElementById('retryDelay').value) * 60, // Convert to seconds\n max_retries: parseInt(document.getElementById('maxRetries').value),\n task_retention_seconds: parseInt(document.getElementById('taskRetention').value) * 24 * 3600, // Convert to seconds\n policy: {\n ...currentConfig.config.policy, // Preserve existing policy\n global_max_concurrent: parseInt(document.getElementById('globalMaxConcurrent').value)\n }\n };\n\n // Send the updated configuration\n return fetch('/api/maintenance/config', {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(updatedConfig)\n });\n })\n .then(response => response.json())\n .then(data => {\n if (data.success) {\n alert('Configuration saved successfully');\n location.reload(); // Reload to show updated values\n } else {\n alert('Failed to save configuration: ' + (data.error || 'Unknown error'));\n }\n })\n .catch(error => {\n alert('Error: ' + error.message);\n });\n }\n\n function resetToDefaults() {\n showConfirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.', function() {\n // Reset form to defaults (matching DefaultMaintenanceConfig values)\n document.getElementById('enabled').checked = false;\n document.getElementById('scanInterval').value = '30';\n document.getElementById('workerTimeout').value = '5';\n document.getElementById('taskTimeout').value = '2';\n document.getElementById('globalMaxConcurrent').value = '4';\n document.getElementById('maxRetries').value = '3';\n document.getElementById('retryDelay').value = '15';\n document.getElementById('taskRetention').value = '7';\n });\n }\n </script>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
@@ -247,7 +247,8 @@ templ MaintenanceWorkers(data *dash.MaintenanceWorkersData) {
|
||||
var modal = new bootstrap.Modal(document.getElementById('workerDetailsModal'));
|
||||
|
||||
// Load worker details
|
||||
fetch('/api/maintenance/workers/' + workerID)
|
||||
const encodedWorkerId = encodeURIComponent(workerID);
|
||||
fetch('/api/maintenance/workers/' + encodedWorkerId)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const content = document.getElementById('workerDetailsContent');
|
||||
@@ -275,7 +276,7 @@ templ MaintenanceWorkers(data *dash.MaintenanceWorkersData) {
|
||||
'</div>' +
|
||||
'<hr>' +
|
||||
'<h6>Current Tasks</h6>' +
|
||||
(data.current_tasks.length === 0 ?
|
||||
(data.current_tasks === null || data.current_tasks.length === 0 ?
|
||||
'<p class="text-muted">No current tasks</p>' :
|
||||
data.current_tasks.map(task =>
|
||||
'<div class="card mb-2">' +
|
||||
@@ -302,23 +303,27 @@ templ MaintenanceWorkers(data *dash.MaintenanceWorkersData) {
|
||||
function pauseWorker(event) {
|
||||
const workerID = event.target.closest('button').getAttribute('data-worker-id');
|
||||
|
||||
if (confirm('Are you sure you want to pause this worker?')) {
|
||||
fetch('/api/maintenance/workers/' + workerID + '/pause', {
|
||||
method: 'POST'
|
||||
showConfirm(`Are you sure you want to pause worker ${workerID}?`, function() {
|
||||
const encodedWorkerId = encodeURIComponent(workerID);
|
||||
fetch('/api/maintenance/workers/' + encodedWorkerId + '/pause', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Failed to pause worker: ' + data.error);
|
||||
showAlert('Failed to pause worker: ' + data.error, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error pausing worker:', error);
|
||||
alert('Failed to pause worker');
|
||||
showAlert('Failed to pause worker', 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function formatDuration(nanoseconds) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -516,11 +516,11 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
}
|
||||
} else {
|
||||
const error = await response.json().catch(() => ({}));
|
||||
showErrorMessage('Failed to load policies: ' + (error.error || 'Unknown error'));
|
||||
showAlert('Failed to load policies: ' + (error.error || 'Unknown error'), 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading policies:', error);
|
||||
showErrorMessage('Failed to load policies: ' + error.message);
|
||||
showAlert('Failed to load policies: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,25 +691,27 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
// Show user details modal
|
||||
async function showUserDetails(username) {
|
||||
try {
|
||||
const response = await fetch(`/api/users/${username}`);
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const response = await fetch(`/api/users/${encodedUsername}`);
|
||||
if (response.ok) {
|
||||
const user = await response.json();
|
||||
document.getElementById('userDetailsContent').innerHTML = createUserDetailsContent(user);
|
||||
const modal = new bootstrap.Modal(document.getElementById('userDetailsModal'));
|
||||
modal.show();
|
||||
} else {
|
||||
showErrorMessage('Failed to load user details');
|
||||
showAlert('Failed to load user details', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading user details:', error);
|
||||
showErrorMessage('Failed to load user details');
|
||||
showAlert('Failed to load user details', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Edit user function
|
||||
async function editUser(username) {
|
||||
try {
|
||||
const response = await fetch(`/api/users/${username}`);
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const response = await fetch(`/api/users/${encodedUsername}`);
|
||||
if (response.ok) {
|
||||
const user = await response.json();
|
||||
|
||||
@@ -773,18 +775,19 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
const modal = new bootstrap.Modal(document.getElementById('editUserModal'));
|
||||
modal.show();
|
||||
} else {
|
||||
showErrorMessage('Failed to load user details');
|
||||
showAlert('Failed to load user details', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading user:', error);
|
||||
showErrorMessage('Failed to load user details');
|
||||
showAlert('Failed to load user details', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Manage access keys function
|
||||
async function manageAccessKeys(username) {
|
||||
try {
|
||||
const response = await fetch(`/api/users/${username}`);
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const response = await fetch(`/api/users/${encodedUsername}`);
|
||||
if (response.ok) {
|
||||
const user = await response.json();
|
||||
document.getElementById('accessKeysUsername').textContent = username;
|
||||
@@ -792,19 +795,20 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
const modal = new bootstrap.Modal(document.getElementById('accessKeysModal'));
|
||||
modal.show();
|
||||
} else {
|
||||
showErrorMessage('Failed to load access keys');
|
||||
showAlert('Failed to load access keys', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading access keys:', error);
|
||||
showErrorMessage('Failed to load access keys');
|
||||
showAlert('Failed to load access keys', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Delete user function
|
||||
async function deleteUser(username) {
|
||||
if (confirm(`Are you sure you want to delete user "${username}"? This action cannot be undone.`)) {
|
||||
showDeleteConfirm(username, async function() {
|
||||
try {
|
||||
const response = await fetch(`/api/users/${username}`, {
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const response = await fetch(`/api/users/${encodedUsername}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
@@ -819,7 +823,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
console.error('Error deleting user:', error);
|
||||
showErrorMessage('Failed to delete user: ' + error.message);
|
||||
}
|
||||
}
|
||||
}, 'Are you sure you want to delete this user? This action cannot be undone.');
|
||||
}
|
||||
|
||||
// Handle create user form submission
|
||||
@@ -863,11 +867,11 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
} else {
|
||||
const error = await response.json();
|
||||
showErrorMessage('Failed to create user: ' + (error.error || 'Unknown error'));
|
||||
showAlert('Failed to create user: ' + (error.error || 'Unknown error'), 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating user:', error);
|
||||
showErrorMessage('Failed to create user: ' + error.message);
|
||||
showAlert('Failed to create user: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -876,7 +880,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
async function handleUpdateUser() {
|
||||
const username = document.getElementById('editUsername').value;
|
||||
if (!username) {
|
||||
showErrorMessage('Username is required');
|
||||
showAlert('Username is required', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -885,13 +889,13 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
|
||||
// Validate that permissions are not empty
|
||||
if (!allActions || allActions.length === 0) {
|
||||
showErrorMessage('At least one permission must be selected');
|
||||
showAlert('At least one permission must be selected', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for null (validation failure from buildBucketPermissionsNew)
|
||||
if (allActions === null) {
|
||||
showErrorMessage('Please select at least one bucket when using specific bucket permissions');
|
||||
showAlert('Please select at least one bucket when using specific bucket permissions', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -902,7 +906,8 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/users/${username}`, {
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const response = await fetch(`/api/users/${encodedUsername}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -919,11 +924,11 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
} else {
|
||||
const error = await response.json();
|
||||
showErrorMessage('Failed to update user: ' + (error.error || 'Unknown error'));
|
||||
showAlert('Failed to update user: ' + (error.error || 'Unknown error'), 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating user:', error);
|
||||
showErrorMessage('Failed to update user: ' + error.message);
|
||||
showAlert('Failed to update user: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1028,7 +1033,8 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
// Refresh access keys list content
|
||||
async function refreshAccessKeysList(username) {
|
||||
try {
|
||||
const response = await fetch(`/api/users/${username}`);
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const response = await fetch(`/api/users/${encodedUsername}`);
|
||||
if (response.ok) {
|
||||
const user = await response.json();
|
||||
document.getElementById('accessKeysContent').innerHTML = createAccessKeysContent(user);
|
||||
@@ -1055,12 +1061,12 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
refreshAccessKeysList(username);
|
||||
} else {
|
||||
const error = await response.json();
|
||||
showErrorMessage('Failed to update access key status: ' + (error.error || 'Unknown error'));
|
||||
showAlert('Failed to update access key status: ' + (error.error || 'Unknown error'), 'error');
|
||||
refreshAccessKeysList(username);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating access key status:', error);
|
||||
showErrorMessage('Failed to update access key status: ' + error.message);
|
||||
showAlert('Failed to update access key status: ' + error.message, 'error');
|
||||
refreshAccessKeysList(username);
|
||||
}
|
||||
}
|
||||
@@ -1070,7 +1076,8 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
const username = document.getElementById('accessKeysUsername').textContent;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/users/${username}/access-keys`, {
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const response = await fetch(`/api/users/${encodedUsername}/access-keys`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -1092,19 +1099,21 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
refreshAccessKeysList(username);
|
||||
} else {
|
||||
const error = await response.json();
|
||||
showErrorMessage('Failed to create access key: ' + (error.error || 'Unknown error'));
|
||||
showAlert('Failed to create access key: ' + (error.error || 'Unknown error'), 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating access key:', error);
|
||||
showErrorMessage('Failed to create access key: ' + error.message);
|
||||
showAlert('Failed to create access key: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Delete access key
|
||||
async function deleteAccessKey(username, accessKey) {
|
||||
if (confirm('Are you sure you want to delete this access key?')) {
|
||||
showDeleteConfirm(accessKey, async function() {
|
||||
try {
|
||||
const response = await fetch(`/api/users/${username}/access-keys/${accessKey}`, {
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const encodedAccessKey = encodeURIComponent(accessKey);
|
||||
const response = await fetch(`/api/users/${encodedUsername}/access-keys/${encodedAccessKey}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
@@ -1121,7 +1130,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
console.error('Error deleting access key:', error);
|
||||
showErrorMessage('Failed to delete access key: ' + error.message);
|
||||
}
|
||||
}
|
||||
}, 'Are you sure you want to delete this access key?');
|
||||
}
|
||||
|
||||
|
||||
@@ -1132,8 +1141,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
}
|
||||
|
||||
function showErrorMessage(message) {
|
||||
// Simple implementation - could be enhanced with toast notifications
|
||||
alert('Error: ' + message);
|
||||
showAlert(message, 'error');
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -351,7 +351,7 @@ templ Policies(data dash.PoliciesData) {
|
||||
const policyDocumentText = formData.get('document');
|
||||
|
||||
if (!policyName || !policyDocumentText) {
|
||||
alert('Please fill in all required fields');
|
||||
showAlert('Please fill in all required fields', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -359,7 +359,7 @@ templ Policies(data dash.PoliciesData) {
|
||||
try {
|
||||
policyDocument = JSON.parse(policyDocumentText);
|
||||
} catch (e) {
|
||||
alert('Invalid JSON in policy document: ' + e.message);
|
||||
showAlert('Invalid JSON in policy document: ' + e.message, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -378,17 +378,17 @@ templ Policies(data dash.PoliciesData) {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('Policy created successfully!');
|
||||
showAlert('Policy created successfully!', 'success');
|
||||
const modal = bootstrap.Modal.getInstance(document.getElementById('createPolicyModal'));
|
||||
if (modal) modal.hide();
|
||||
location.reload(); // Refresh the page to show the new policy
|
||||
} else {
|
||||
alert('Error creating policy: ' + (data.error || 'Unknown error'));
|
||||
showAlert('Error creating policy: ' + (data.error || 'Unknown error'), 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error creating policy: ' + error.message);
|
||||
showAlert('Error creating policy: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -507,7 +507,7 @@ templ Policies(data dash.PoliciesData) {
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error loading policy for editing: ' + error.message);
|
||||
showAlert('Error loading policy for editing: ' + error.message, 'error');
|
||||
const editModal = bootstrap.Modal.getInstance(document.getElementById('editPolicyModal'));
|
||||
if (editModal) editModal.hide();
|
||||
});
|
||||
@@ -518,7 +518,7 @@ templ Policies(data dash.PoliciesData) {
|
||||
const policyDocumentText = document.getElementById('editPolicyDocument').value;
|
||||
|
||||
if (!policyName || !policyDocumentText) {
|
||||
alert('Please fill in all required fields');
|
||||
showAlert('Please fill in all required fields', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -526,7 +526,7 @@ templ Policies(data dash.PoliciesData) {
|
||||
try {
|
||||
policyDocument = JSON.parse(policyDocumentText);
|
||||
} catch (e) {
|
||||
alert('Invalid JSON in policy document: ' + e.message);
|
||||
showAlert('Invalid JSON in policy document: ' + e.message, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -544,17 +544,17 @@ templ Policies(data dash.PoliciesData) {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('Policy updated successfully!');
|
||||
showAlert('Policy updated successfully!', 'success');
|
||||
const modal = bootstrap.Modal.getInstance(document.getElementById('editPolicyModal'));
|
||||
if (modal) modal.hide();
|
||||
location.reload(); // Refresh the page to show the updated policy
|
||||
} else {
|
||||
alert('Error updating policy: ' + (data.error || 'Unknown error'));
|
||||
showAlert('Error updating policy: ' + (data.error || 'Unknown error'), 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error updating policy: ' + error.message);
|
||||
showAlert('Error updating policy: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -610,7 +610,7 @@ templ Policies(data dash.PoliciesData) {
|
||||
|
||||
function validatePolicyJSON(policyText) {
|
||||
if (!policyText) {
|
||||
alert('Please enter a policy document first');
|
||||
showAlert('Please enter a policy document first', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -619,40 +619,40 @@ templ Policies(data dash.PoliciesData) {
|
||||
|
||||
// Basic validation
|
||||
if (!policy.Version) {
|
||||
alert('Policy must have a Version field');
|
||||
showAlert('Policy must have a Version field', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!policy.Statement || !Array.isArray(policy.Statement)) {
|
||||
alert('Policy must have a Statement array');
|
||||
showAlert('Policy must have a Statement array', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
alert('Policy document is valid JSON!');
|
||||
showAlert('Policy document is valid JSON!', 'success');
|
||||
} catch (e) {
|
||||
alert('Invalid JSON: ' + e.message);
|
||||
showAlert('Invalid JSON: ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
function deletePolicy(policyName) {
|
||||
if (confirm('Are you sure you want to delete policy "' + policyName + '"?')) {
|
||||
showDeleteConfirm(policyName, function() {
|
||||
fetch('/api/object-store/policies/' + encodeURIComponent(policyName), {
|
||||
method: 'DELETE'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('Policy deleted successfully!');
|
||||
location.reload(); // Refresh the page
|
||||
showAlert('Policy deleted successfully!', 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error deleting policy: ' + (data.error || 'Unknown error'));
|
||||
showAlert('Error deleting policy: ' + (data.error || 'Unknown error'), 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error deleting policy: ' + error.message);
|
||||
showAlert('Error deleting policy: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -335,7 +335,8 @@ templ ServiceAccounts(data dash.ServiceAccountsData) {
|
||||
|
||||
async function showSADetails(id) {
|
||||
try {
|
||||
const response = await fetch(`/api/service-accounts/${id}`);
|
||||
const encodedId = encodeURIComponent(id);
|
||||
const response = await fetch(`/api/service-accounts/${encodedId}`);
|
||||
if (response.ok) {
|
||||
const sa = await response.json();
|
||||
document.getElementById('saDetailsContent').innerHTML = createSADetailsContent(sa);
|
||||
@@ -353,7 +354,8 @@ templ ServiceAccounts(data dash.ServiceAccountsData) {
|
||||
async function toggleSAStatus(id, currentStatus) {
|
||||
const newStatus = currentStatus === 'Active' ? 'Inactive' : 'Active';
|
||||
try {
|
||||
const response = await fetch(`/api/service-accounts/${id}`, {
|
||||
const encodedId = encodeURIComponent(id);
|
||||
const response = await fetch(`/api/service-accounts/${encodedId}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ status: newStatus })
|
||||
@@ -373,9 +375,10 @@ templ ServiceAccounts(data dash.ServiceAccountsData) {
|
||||
}
|
||||
|
||||
async function deleteSA(id) {
|
||||
if (confirm('Are you sure you want to delete this service account? This action cannot be undone.')) {
|
||||
showDeleteConfirm(id, async function() {
|
||||
try {
|
||||
const response = await fetch(`/api/service-accounts/${id}`, {
|
||||
const encodedId = encodeURIComponent(id);
|
||||
const response = await fetch(`/api/service-accounts/${encodedId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
@@ -390,7 +393,7 @@ templ ServiceAccounts(data dash.ServiceAccountsData) {
|
||||
console.error('Error deleting service account:', error);
|
||||
showErrorMessage('Failed to delete: ' + error.message);
|
||||
}
|
||||
}
|
||||
}, 'Are you sure you want to delete this service account? This action cannot be undone.');
|
||||
}
|
||||
|
||||
async function handleCreateServiceAccount() {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -104,13 +104,13 @@ templ TaskConfig(data *maintenance.TaskConfigData) {
|
||||
|
||||
<script>
|
||||
function resetForm() {
|
||||
if (confirm('Are you sure you want to reset all settings to their default values?')) {
|
||||
showConfirm('Are you sure you want to reset all settings to their default values?', function() {
|
||||
// Find all form inputs and reset them
|
||||
const form = document.querySelector('form');
|
||||
if (form) {
|
||||
form.reset();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-save form data to localStorage for recovery
|
||||
|
||||
@@ -127,7 +127,7 @@ templ TaskConfigSchema(data *maintenance.TaskConfigData, schema *tasks.TaskConfi
|
||||
|
||||
<script>
|
||||
function resetToDefaults() {
|
||||
if (confirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.')) {
|
||||
showConfirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.', function() {
|
||||
// Reset form fields to their default values
|
||||
const form = document.getElementById('taskConfigForm');
|
||||
const schemaFields = window.taskConfigSchema ? window.taskConfigSchema.fields : {};
|
||||
@@ -154,7 +154,7 @@ templ TaskConfigSchema(data *maintenance.TaskConfigData, schema *tasks.TaskConfi
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function convertSecondsToTaskIntervalValueUnit(totalSeconds) {
|
||||
|
||||
@@ -170,7 +170,7 @@ func TaskConfigSchema(data *maintenance.TaskConfigData, schema *tasks.TaskConfig
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div></div></div></div></div></div><script>\n function resetToDefaults() {\n if (confirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.')) {\n // Reset form fields to their default values\n const form = document.getElementById('taskConfigForm');\n const schemaFields = window.taskConfigSchema ? window.taskConfigSchema.fields : {};\n \n Object.keys(schemaFields).forEach(fieldName => {\n const field = schemaFields[fieldName];\n const element = document.getElementById(fieldName);\n \n if (element && field.default_value !== undefined) {\n if (field.input_type === 'checkbox') {\n element.checked = field.default_value;\n } else if (field.input_type === 'interval') {\n // Handle interval fields with value and unit\n const valueElement = document.getElementById(fieldName + '_value');\n const unitElement = document.getElementById(fieldName + '_unit');\n if (valueElement && unitElement && field.default_value) {\n const defaultSeconds = field.default_value;\n const { value, unit } = convertSecondsToTaskIntervalValueUnit(defaultSeconds);\n valueElement.value = value;\n unitElement.value = unit;\n }\n } else {\n element.value = field.default_value;\n }\n }\n });\n }\n }\n\n function convertSecondsToTaskIntervalValueUnit(totalSeconds) {\n if (totalSeconds === 0) {\n return { value: 0, unit: 'minutes' };\n }\n\n // Check if it's evenly divisible by days\n if (totalSeconds % (24 * 3600) === 0) {\n return { value: totalSeconds / (24 * 3600), unit: 'days' };\n }\n\n // Check if it's evenly divisible by hours\n if (totalSeconds % 3600 === 0) {\n return { value: totalSeconds / 3600, unit: 'hours' };\n }\n\n // Default to minutes\n return { value: totalSeconds / 60, unit: 'minutes' };\n }\n\n // Store schema data for JavaScript access (moved to after div is created)\n </script><!-- Hidden element to store schema data --><div data-task-schema=\"")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div></div></div></div></div></div><script>\n function resetToDefaults() {\n showConfirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.', function() {\n // Reset form fields to their default values\n const form = document.getElementById('taskConfigForm');\n const schemaFields = window.taskConfigSchema ? window.taskConfigSchema.fields : {};\n \n Object.keys(schemaFields).forEach(fieldName => {\n const field = schemaFields[fieldName];\n const element = document.getElementById(fieldName);\n \n if (element && field.default_value !== undefined) {\n if (field.input_type === 'checkbox') {\n element.checked = field.default_value;\n } else if (field.input_type === 'interval') {\n // Handle interval fields with value and unit\n const valueElement = document.getElementById(fieldName + '_value');\n const unitElement = document.getElementById(fieldName + '_unit');\n if (valueElement && unitElement && field.default_value) {\n const defaultSeconds = field.default_value;\n const { value, unit } = convertSecondsToTaskIntervalValueUnit(defaultSeconds);\n valueElement.value = value;\n unitElement.value = unit;\n }\n } else {\n element.value = field.default_value;\n }\n }\n });\n });\n }\n\n function convertSecondsToTaskIntervalValueUnit(totalSeconds) {\n if (totalSeconds === 0) {\n return { value: 0, unit: 'minutes' };\n }\n\n // Check if it's evenly divisible by days\n if (totalSeconds % (24 * 3600) === 0) {\n return { value: totalSeconds / (24 * 3600), unit: 'days' };\n }\n\n // Check if it's evenly divisible by hours\n if (totalSeconds % 3600 === 0) {\n return { value: totalSeconds / 3600, unit: 'hours' };\n }\n\n // Default to minutes\n return { value: totalSeconds / 60, unit: 'minutes' };\n }\n\n // Store schema data for JavaScript access (moved to after div is created)\n </script><!-- Hidden element to store schema data --><div data-task-schema=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ func TaskConfig(data *maintenance.TaskConfigData) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</p></div></div></div></div></div></div></div><script>\n function resetForm() {\n if (confirm('Are you sure you want to reset all settings to their default values?')) {\n // Find all form inputs and reset them\n const form = document.querySelector('form');\n if (form) {\n form.reset();\n }\n }\n }\n\n // Auto-save form data to localStorage for recovery\n document.addEventListener('DOMContentLoaded', function() {\n const form = document.querySelector('form');\n if (form) {\n const taskType = '{string(data.TaskType)}';\n const storageKey = 'taskConfig_' + taskType;\n\n // Load saved data\n const savedData = localStorage.getItem(storageKey);\n if (savedData) {\n try {\n const data = JSON.parse(savedData);\n Object.keys(data).forEach(key => {\n const input = form.querySelector(`[name=\"${key}\"]`);\n if (input) {\n if (input.type === 'checkbox') {\n input.checked = data[key];\n } else {\n input.value = data[key];\n }\n }\n });\n } catch (e) {\n console.warn('Failed to load saved configuration:', e);\n }\n }\n\n // Save data on input change\n form.addEventListener('input', function() {\n const formData = new FormData(form);\n const data = {};\n for (let [key, value] of formData.entries()) {\n data[key] = value;\n }\n localStorage.setItem(storageKey, JSON.stringify(data));\n });\n\n // Clear saved data on successful submit\n form.addEventListener('submit', function() {\n localStorage.removeItem(storageKey);\n });\n }\n });\n </script>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</p></div></div></div></div></div></div></div><script>\n function resetForm() {\n showConfirm('Are you sure you want to reset all settings to their default values?', function() {\n // Find all form inputs and reset them\n const form = document.querySelector('form');\n if (form) {\n form.reset();\n }\n });\n }\n\n // Auto-save form data to localStorage for recovery\n document.addEventListener('DOMContentLoaded', function() {\n const form = document.querySelector('form');\n if (form) {\n const taskType = '{string(data.TaskType)}';\n const storageKey = 'taskConfig_' + taskType;\n\n // Load saved data\n const savedData = localStorage.getItem(storageKey);\n if (savedData) {\n try {\n const data = JSON.parse(savedData);\n Object.keys(data).forEach(key => {\n const input = form.querySelector(`[name=\"${key}\"]`);\n if (input) {\n if (input.type === 'checkbox') {\n input.checked = data[key];\n } else {\n input.value = data[key];\n }\n }\n });\n } catch (e) {\n console.warn('Failed to load saved configuration:', e);\n }\n }\n\n // Save data on input change\n form.addEventListener('input', function() {\n const formData = new FormData(form);\n const data = {};\n for (let [key, value] of formData.entries()) {\n data[key] = value;\n }\n localStorage.setItem(storageKey, JSON.stringify(data));\n });\n\n // Clear saved data on successful submit\n form.addEventListener('submit', function() {\n localStorage.removeItem(storageKey);\n });\n }\n });\n </script>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user