mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-28 00:29:56 -05:00
Compare commits
35 Commits
stable-4.0
...
v4.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86dbae6412 | ||
|
|
87257623c6 | ||
|
|
8aac5f6318 | ||
|
|
4dcecbf5c0 | ||
|
|
cffeb4a690 | ||
|
|
826640c2c5 | ||
|
|
8a4785e0e7 | ||
|
|
e7d8f3f446 | ||
|
|
b1c9159bd1 | ||
|
|
446ae35701 | ||
|
|
8f323c775a | ||
|
|
40d8aacea4 | ||
|
|
4c5d5fb218 | ||
|
|
ec30bcc030 | ||
|
|
61a591bcba | ||
|
|
fc9a62a2d8 | ||
|
|
b595461ae7 | ||
|
|
a3a1397e2d | ||
|
|
dbabedb90b | ||
|
|
dd4f2fe529 | ||
|
|
614d916978 | ||
|
|
ee16c0597c | ||
|
|
8e2fab3c9d | ||
|
|
c3a7892889 | ||
|
|
db7c0a88dd | ||
|
|
64119b3f8a | ||
|
|
6c171e11a2 | ||
|
|
7318fde6a0 | ||
|
|
6ce0cc6b1f | ||
|
|
3e81d1f1d8 | ||
|
|
d352d91210 | ||
|
|
434ba0a30a | ||
|
|
0f448f23a0 | ||
|
|
babb97f8a6 | ||
|
|
a6d637456d |
6
.backportrc.json
Normal file
6
.backportrc.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"repoOwner": "opencloud-eu",
|
||||
"repoName": "opencloud",
|
||||
"targetBranchChoices": ["main", "stable-2.0", "stable-4.0"],
|
||||
"fork": false
|
||||
}
|
||||
14
.make/go.mk
14
.make/go.mk
@@ -36,8 +36,18 @@ ifndef DATE
|
||||
DATE := $(shell date -u '+%Y%m%d')
|
||||
endif
|
||||
|
||||
LDFLAGS += -X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn -s -w -X "$(OC_REPO)/pkg/version.String=$(STRING)" -X "$(OC_REPO)/pkg/version.Tag=$(VERSION)" -X "$(OC_REPO)/pkg/version.Date=$(DATE)"
|
||||
DEBUG_LDFLAGS += -X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn -X "$(OC_REPO)/pkg/version.String=$(STRING)" -X "$(OC_REPO)/pkg/version.Tag=$(VERSION)" -X "$(OC_REPO)/pkg/version.Date=$(DATE)"
|
||||
LDFLAGS += -X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn -s -w \
|
||||
-X "$(OC_REPO)/pkg/version.Edition=$(EDITION)" \
|
||||
-X "$(OC_REPO)/pkg/version.String=$(STRING)" \
|
||||
-X "$(OC_REPO)/pkg/version.Tag=$(VERSION)" \
|
||||
-X "$(OC_REPO)/pkg/version.Date=$(DATE)"
|
||||
|
||||
DEBUG_LDFLAGS += -X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn \
|
||||
-X "$(OC_REPO)/pkg/version.Edition=$(EDITION)" \
|
||||
-X "$(OC_REPO)/pkg/version.String=$(STRING)" \
|
||||
-X "$(OC_REPO)/pkg/version.Tag=$(VERSION)" \
|
||||
-X "$(OC_REPO)/pkg/version.Date=$(DATE)"
|
||||
|
||||
DOCKER_LDFLAGS += -X "$(OC_REPO)/pkg/config/defaults.BaseDataPathType=path" -X "$(OC_REPO)/pkg/config/defaults.BaseDataPathValue=/var/lib/opencloud"
|
||||
DOCKER_LDFLAGS += -X "$(OC_REPO)/pkg/config/defaults.BaseConfigPathType=path" -X "$(OC_REPO)/pkg/config/defaults.BaseConfigPathValue=/etc/opencloud"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# The test runner source for UI tests
|
||||
WEB_COMMITID=50e3fff6a518361d59cba864a927470f313b6f91
|
||||
WEB_BRANCH=stable-4.2
|
||||
WEB_COMMITID=3120ea384c7a9d1f1ea0c328965951fc06d66900
|
||||
WEB_BRANCH=main
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ OC_CI_ALPINE = "owncloudci/alpine:latest"
|
||||
OC_CI_BAZEL_BUILDIFIER = "owncloudci/bazel-buildifier:latest"
|
||||
OC_CI_CLAMAVD = "owncloudci/clamavd"
|
||||
OC_CI_DRONE_ANSIBLE = "owncloudci/drone-ansible:latest"
|
||||
OC_CI_GOLANG = "docker.io/golang:1.24"
|
||||
OC_CI_GOLANG = "registry.heinlein.group/opencloud/golang-ci:1.25"
|
||||
OC_CI_NODEJS = "owncloudci/nodejs:%s"
|
||||
OC_CI_PHP = "owncloudci/php:%s"
|
||||
OC_CI_WAIT_FOR = "owncloudci/wait-for:latest"
|
||||
@@ -41,7 +41,6 @@ DEFAULT_PHP_VERSION = "8.2"
|
||||
DEFAULT_NODEJS_VERSION = "20"
|
||||
|
||||
CACHE_S3_SERVER = "https://s3.ci.opencloud.eu"
|
||||
INSTALL_LIBVIPS_COMMAND = "apt-get update; apt-get install libvips42 -y"
|
||||
|
||||
dirs = {
|
||||
"base": "/woodpecker/src/github.com/opencloud-eu/opencloud",
|
||||
@@ -389,6 +388,8 @@ config = {
|
||||
"production": {
|
||||
# NOTE: need to be updated if new production releases are determined
|
||||
"tags": ["2.0", "4.0"],
|
||||
# NOTE: need to be set to true if patch releases are made from stable-X-branches
|
||||
"skip_rolling": "false",
|
||||
"repo": docker_repo_slug,
|
||||
"build_type": "production",
|
||||
},
|
||||
@@ -480,6 +481,10 @@ def main(ctx):
|
||||
if ctx.build.event == "cron" and ctx.build.sender == "translation-sync":
|
||||
return translation_sync(ctx)
|
||||
|
||||
is_release_pr = (ctx.build.event == "pull_request" and ctx.build.sender == "openclouders" and "🎉 release" in ctx.build.title.lower())
|
||||
if is_release_pr:
|
||||
return [licenseCheck(ctx)]
|
||||
|
||||
build_release_helpers = \
|
||||
readyReleaseGo()
|
||||
|
||||
@@ -706,7 +711,7 @@ def restoreGoBinCache():
|
||||
"name": "extract-go-bin-cache",
|
||||
"image": OC_UBUNTU,
|
||||
"commands": [
|
||||
"tar -xmf %s -C /" % dirs["gobinTarPath"],
|
||||
"tar -xvmf %s -C /" % dirs["gobinTarPath"],
|
||||
],
|
||||
},
|
||||
]
|
||||
@@ -1609,31 +1614,40 @@ def uploadTracingResult(ctx):
|
||||
|
||||
def dockerReleases(ctx):
|
||||
pipelines = []
|
||||
docker_repos = []
|
||||
docker_releases = []
|
||||
build_type = ""
|
||||
|
||||
# only make realeases on tag events
|
||||
if ctx.build.event == "tag":
|
||||
tag = ctx.build.ref.replace("refs/tags/v", "").lower()
|
||||
|
||||
# iterate over production tags to see if this is a production release
|
||||
is_production = False
|
||||
skip_rolling = False
|
||||
for prod_tag in config["dockerReleases"]["production"]["tags"]:
|
||||
if tag.startswith(prod_tag):
|
||||
is_production = True
|
||||
skip_rolling = config["dockerReleases"]["production"]["skip_rolling"]
|
||||
break
|
||||
|
||||
if is_production:
|
||||
docker_repos.append(config["dockerReleases"]["production"]["repo"])
|
||||
build_type = config["dockerReleases"]["production"]["build_type"]
|
||||
docker_releases.append("production")
|
||||
|
||||
# a new production realease is also a rolling release
|
||||
# unless skip_rolling is set in the config, i.e. for patch-releases on stable-branch
|
||||
if not skip_rolling:
|
||||
docker_releases.append("rolling")
|
||||
|
||||
else:
|
||||
docker_repos.append(config["dockerReleases"]["rolling"]["repo"])
|
||||
build_type = config["dockerReleases"]["rolling"]["build_type"]
|
||||
docker_releases.append("rolling")
|
||||
|
||||
# on non tag events, do daily build
|
||||
else:
|
||||
docker_repos.append(config["dockerReleases"]["daily"]["repo"])
|
||||
build_type = config["dockerReleases"]["daily"]["build_type"]
|
||||
docker_releases.append("daily")
|
||||
|
||||
for repo in docker_repos:
|
||||
for releaseConfigName in docker_releases:
|
||||
repo = config["dockerReleases"][releaseConfigName]["repo"]
|
||||
build_type = config["dockerReleases"][releaseConfigName]["build_type"]
|
||||
repo_pipelines = []
|
||||
repo_pipelines.append(dockerRelease(ctx, repo, build_type))
|
||||
|
||||
@@ -1653,6 +1667,7 @@ def dockerRelease(ctx, repo, build_type):
|
||||
build_args = {
|
||||
"REVISION": "%s" % ctx.build.commit,
|
||||
"VERSION": "%s" % (ctx.build.ref.replace("refs/tags/", "") if ctx.build.event == "tag" else "daily"),
|
||||
"EDITION": "stable" if build_type == "production" else "rolling",
|
||||
}
|
||||
|
||||
# if no additional tag is given, the build-plugin adds latest
|
||||
@@ -1816,6 +1831,7 @@ def binaryRelease(ctx, arch, depends_on = []):
|
||||
"image": OC_CI_GOLANG,
|
||||
"environment": {
|
||||
"VERSION": (ctx.build.ref.replace("refs/tags/", "") if ctx.build.event == "tag" else "daily"),
|
||||
"EDITION": "rolling",
|
||||
"HTTP_PROXY": {
|
||||
"from_secret": "ci_http_proxy",
|
||||
},
|
||||
@@ -2061,7 +2077,9 @@ def notifyMatrix(ctx):
|
||||
},
|
||||
"QA_REPO": "https://github.com/opencloud-eu/qa.git",
|
||||
"QA_REPO_BRANCH": "main",
|
||||
"CI_WOODPECKER_URL": "https://ci.opencloud.eu/",
|
||||
"CI_WOODPECKER_URL": {
|
||||
"from_secret": "oc_ci_url",
|
||||
},
|
||||
"CI_REPO_ID": "3",
|
||||
"CI_WOODPECKER_TOKEN": "no-auth-needed-on-this-repo",
|
||||
},
|
||||
@@ -2223,9 +2241,6 @@ def opencloudServer(storage = "decomposed", accounts_hash_difficulty = 4, depend
|
||||
},
|
||||
},
|
||||
"commands": [
|
||||
"apt-get update",
|
||||
"apt-get install -y inotify-tools xattr",
|
||||
INSTALL_LIBVIPS_COMMAND,
|
||||
"%s init --insecure true" % dirs["opencloudBin"],
|
||||
"cat $OC_CONFIG_DIR/opencloud.yaml",
|
||||
"cp tests/config/woodpecker/app-registry.yaml $OC_CONFIG_DIR/app-registry.yaml",
|
||||
@@ -2269,7 +2284,6 @@ def startOpenCloudService(service = None, name = None, environment = {}):
|
||||
"detach": True,
|
||||
"environment": environment,
|
||||
"commands": [
|
||||
INSTALL_LIBVIPS_COMMAND,
|
||||
"%s %s server" % (dirs["opencloudBin"], service),
|
||||
],
|
||||
},
|
||||
@@ -2295,7 +2309,6 @@ def build():
|
||||
"name": "build",
|
||||
"image": OC_CI_GOLANG,
|
||||
"commands": [
|
||||
"apt-get update; apt-get install libvips-dev -y",
|
||||
"for i in $(seq 3); do make -C opencloud build ENABLE_VIPS=1 && break || sleep 1; done",
|
||||
],
|
||||
"environment": CI_HTTP_PROXY_ENV,
|
||||
@@ -2344,11 +2357,12 @@ def translation_sync(ctx):
|
||||
"image": OC_CI_GOLANG,
|
||||
"commands": [
|
||||
"make l10n-read",
|
||||
"mkdir tx && cd tx",
|
||||
"curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash",
|
||||
". ~/.profile",
|
||||
"export PATH=$PATH:$(pwd) && cd ..",
|
||||
"make l10n-push",
|
||||
"make l10n-pull",
|
||||
"rm tx",
|
||||
"rm -rf tx",
|
||||
"make l10n-clean",
|
||||
],
|
||||
"environment": {
|
||||
|
||||
36
CHANGELOG.md
36
CHANGELOG.md
@@ -1,5 +1,41 @@
|
||||
# Changelog
|
||||
|
||||
## [4.1.0](https://github.com/opencloud-eu/opencloud/releases/tag/v4.1.0) - 2025-12-15
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@JammingBen, @ScharfViktor, @Svanvith, @butonic, @flimmy, @fschade, @individual-it, @kulmann, @micbar, @prashant-gurung899, @saw-jan
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- fix typo [[#2024](https://github.com/opencloud-eu/opencloud/pull/2024)]
|
||||
- [docs] update policies link [[#1996](https://github.com/opencloud-eu/opencloud/pull/1996)]
|
||||
- fix the link in quickstart script for itself [[#1956](https://github.com/opencloud-eu/opencloud/pull/1956)]
|
||||
|
||||
### ✅ Tests
|
||||
|
||||
- [full-ci][tests-only] test: fix some test flakiness [[#2003](https://github.com/opencloud-eu/opencloud/pull/2003)]
|
||||
- [tests-only] Skip test related pipelines for ready-release-go PRs [[#2011](https://github.com/opencloud-eu/opencloud/pull/2011)]
|
||||
- [full-ci][tests-only] test: add test to check mismatch offset during TUS upload [[#1993](https://github.com/opencloud-eu/opencloud/pull/1993)]
|
||||
- [full-ci][tests-only] test: proper resource existence check [[#1990](https://github.com/opencloud-eu/opencloud/pull/1990)]
|
||||
- check propfing after renaming data in file system [[#1809](https://github.com/opencloud-eu/opencloud/pull/1809)]
|
||||
- fix-get-attribute-test [[#1974](https://github.com/opencloud-eu/opencloud/pull/1974)]
|
||||
|
||||
### 📈 Enhancement
|
||||
|
||||
- Show edition in opencloud version command [[#2019](https://github.com/opencloud-eu/opencloud/pull/2019)]
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- fix: enforce trailing slash for server url [[#1995](https://github.com/opencloud-eu/opencloud/pull/1995)]
|
||||
- fix: enhance resource creation with detailed process information [[#1978](https://github.com/opencloud-eu/opencloud/pull/1978)]
|
||||
|
||||
### 📦️ Dependencies
|
||||
|
||||
- chore: bump web to v4.3.0 [[#2030](https://github.com/opencloud-eu/opencloud/pull/2030)]
|
||||
- reva-bump-2.41.0 [[#2032](https://github.com/opencloud-eu/opencloud/pull/2032)]
|
||||
- build(deps): bump github.com/testcontainers/testcontainers-go from 0.39.0 to 0.40.0 [[#1931](https://github.com/opencloud-eu/opencloud/pull/1931)]
|
||||
|
||||
## [4.0.0](https://github.com/opencloud-eu/opencloud/releases/tag/v4.0.0) - 2025-12-01
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@@ -11,7 +11,7 @@ set -euo pipefail
|
||||
# OC_VERSION: Version to download, e.g. OC_VERSION="1.2.0"
|
||||
|
||||
# Call this script directly from opencloud:
|
||||
# curl -L https://opencloud.eu/quickinstall.sh | /bin/bash
|
||||
# curl -L https://opencloud.eu/install | /bin/bash
|
||||
|
||||
# This function is borrowed from openSUSEs /usr/bin/old, thanks.
|
||||
function backup_file () {
|
||||
|
||||
6
go.mod
6
go.mod
@@ -64,7 +64,7 @@ require (
|
||||
github.com/open-policy-agent/opa v1.10.1
|
||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
|
||||
github.com/opencloud-eu/reva/v2 v2.40.1
|
||||
github.com/opencloud-eu/reva/v2 v2.41.0
|
||||
github.com/opensearch-project/opensearch-go/v4 v4.5.0
|
||||
github.com/orcaman/concurrent-map v1.0.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
@@ -80,7 +80,7 @@ require (
|
||||
github.com/spf13/cobra v1.10.1
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/test-go/testify v1.1.4
|
||||
github.com/testcontainers/testcontainers-go v0.39.0
|
||||
github.com/testcontainers/testcontainers-go v0.40.0
|
||||
github.com/testcontainers/testcontainers-go/modules/opensearch v0.39.0
|
||||
github.com/theckman/yacspin v0.13.12
|
||||
github.com/thejerf/suture/v4 v4.0.6
|
||||
@@ -189,7 +189,7 @@ require (
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/docker/docker v28.3.3+incompatible // indirect
|
||||
github.com/docker/docker v28.5.1+incompatible // indirect
|
||||
github.com/docker/go-connections v0.6.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@@ -310,8 +310,8 @@ github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E
|
||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
||||
github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
|
||||
github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
|
||||
github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
@@ -963,8 +963,8 @@ github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9 h1:dIft
|
||||
github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9/go.mod h1:JWyDC6H+5oZRdUJUgKuaye+8Ph5hEs6HVzVoPKzWSGI=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 h1:vD/EdfDUrv4omSFjrinT8Mvf+8D7f9g4vgQ2oiDrVUI=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
|
||||
github.com/opencloud-eu/reva/v2 v2.40.1 h1:QwMkbGMhwDSwfk2WxbnTpIig2BugPBaVFjWcy2DSU3U=
|
||||
github.com/opencloud-eu/reva/v2 v2.40.1/go.mod h1:DGH08n2mvtsQLkt8o15FV6m51FwSJJGhjR8Ty+iIJww=
|
||||
github.com/opencloud-eu/reva/v2 v2.41.0 h1:oie8+sxcA+drREXRTqm0LmfUdy/mmaa6pA6wkdF6tF4=
|
||||
github.com/opencloud-eu/reva/v2 v2.41.0/go.mod h1:DGH08n2mvtsQLkt8o15FV6m51FwSJJGhjR8Ty+iIJww=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
@@ -1188,8 +1188,8 @@ github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhg
|
||||
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
|
||||
github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
|
||||
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
|
||||
github.com/testcontainers/testcontainers-go v0.39.0 h1:uCUJ5tA+fcxbFAB0uP3pIK3EJ2IjjDUHFSZ1H1UxAts=
|
||||
github.com/testcontainers/testcontainers-go v0.39.0/go.mod h1:qmHpkG7H5uPf/EvOORKvS6EuDkBUPE3zpVGaH9NL7f8=
|
||||
github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU=
|
||||
github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
|
||||
github.com/testcontainers/testcontainers-go/modules/opensearch v0.39.0 h1:IkJUhR8AigQxv7qHZho/OtTU6JtiSdBGVh76o175JGo=
|
||||
github.com/testcontainers/testcontainers-go/modules/opensearch v0.39.0/go.mod h1:B7AhrDmQ4QbpzA0BeWvqzaJ8vbwcdEQDzybr35sBRfw=
|
||||
github.com/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o=
|
||||
|
||||
@@ -3,6 +3,7 @@ ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG VERSION
|
||||
ARG STRING
|
||||
ARG EDITION
|
||||
|
||||
RUN apk add bash make git curl gcc musl-dev libc-dev binutils-gold inotify-tools vips-dev
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ func VersionCommand(cfg *config.Config) *cli.Command {
|
||||
Category: "info",
|
||||
Action: func(c *cli.Context) error {
|
||||
fmt.Println("Version: " + version.GetString())
|
||||
fmt.Printf("Edition: %s\n", version.Edition)
|
||||
fmt.Printf("Compiled: %s\n", version.Compiled())
|
||||
|
||||
if c.Bool(_skipServiceListingFlagName) {
|
||||
|
||||
@@ -105,9 +105,19 @@ func createResource(ctx context.Context, serviceName string) (*resource.Resource
|
||||
return resource.New(ctx,
|
||||
// Reads OTEL_RESOURCE_ATTRIBUTES and OTEL_SERVICE_NAME
|
||||
resource.WithFromEnv(),
|
||||
// Host and process information
|
||||
// Host Information
|
||||
resource.WithHost(),
|
||||
resource.WithProcess(),
|
||||
// Process Information
|
||||
// Resource WithProcessOwner is deliberately omitted because
|
||||
// inside containers where process might run as an arbitrary
|
||||
// uid without a username associated this would fail.
|
||||
resource.WithProcessPID(),
|
||||
resource.WithProcessCommandArgs(),
|
||||
resource.WithProcessExecutableName(),
|
||||
resource.WithProcessExecutablePath(),
|
||||
resource.WithProcessRuntimeDescription(),
|
||||
resource.WithProcessRuntimeName(),
|
||||
resource.WithProcessRuntimeVersion(),
|
||||
// Service attributes
|
||||
resource.WithAttributes(
|
||||
semconv.ServiceName(serviceName),
|
||||
|
||||
4
pkg/version/export_test.go
Normal file
4
pkg/version/export_test.go
Normal file
@@ -0,0 +1,4 @@
|
||||
package version
|
||||
|
||||
// InitEdition exports the private edition initialization func for testing
|
||||
var InitEdition = initEdition
|
||||
@@ -1,9 +1,27 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
// Dev is used as a placeholder.
|
||||
Dev = "dev"
|
||||
// EditionDev indicates the development build channel was used to build the binary.
|
||||
EditionDev = Dev
|
||||
// EditionRolling indicates the rolling release build channel was used to build the binary.
|
||||
EditionRolling = "rolling"
|
||||
// EditionStable indicates the stable release build channel was used to build the binary.
|
||||
EditionStable = "stable"
|
||||
// EditionLTS indicates the lts release build channel was used to build the binary.
|
||||
EditionLTS = "lts"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -21,17 +39,56 @@ var (
|
||||
// Date indicates the build date.
|
||||
// This has been removed, it looks like you can only replace static strings with recent go versions
|
||||
//Date = time.Now().Format("20060102")
|
||||
Date = "dev"
|
||||
Date = Dev
|
||||
|
||||
// Legacy defines the old long 4 number OpenCloud version needed for some clients
|
||||
Legacy = "0.1.0.0"
|
||||
// LegacyString defines the old OpenCloud version needed for some clients
|
||||
LegacyString = "0.1.0"
|
||||
|
||||
// Edition describes the build channel (stable, rolling, nightly, daily, dev)
|
||||
Edition = Dev // default for self-compiled builds
|
||||
)
|
||||
|
||||
func init() { //nolint:gochecknoinits
|
||||
if err := initEdition(); err != nil {
|
||||
logger.New().Error().Err(err).Msg("falling back to dev")
|
||||
}
|
||||
}
|
||||
|
||||
func initEdition() error {
|
||||
regularEditions := []string{EditionDev, EditionRolling, EditionStable}
|
||||
versionedEditions := []string{EditionLTS}
|
||||
if !slices.ContainsFunc(slices.Concat(regularEditions, versionedEditions), func(s string) bool {
|
||||
isRegularEdition := slices.Contains(regularEditions, Edition)
|
||||
if isRegularEdition && s == Edition {
|
||||
return true
|
||||
}
|
||||
|
||||
// handle editions with a version
|
||||
editionParts := strings.Split(Edition, "-")
|
||||
if len(editionParts) != 2 { // a versioned edition channel must consist of exactly 2 parts.
|
||||
return false
|
||||
}
|
||||
|
||||
isVersionedEdition := slices.Contains(versionedEditions, editionParts[0])
|
||||
if !isVersionedEdition { // not all channels can contain version information
|
||||
return false
|
||||
}
|
||||
|
||||
_, err := semver.NewVersion(editionParts[1])
|
||||
return err == nil
|
||||
}) {
|
||||
Edition = Dev
|
||||
return fmt.Errorf(`unknown edition channel "%s"`, Edition)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Compiled returns the compile time of this service.
|
||||
func Compiled() time.Time {
|
||||
if Date == "dev" {
|
||||
if Date == Dev {
|
||||
return time.Now()
|
||||
}
|
||||
t, _ := time.Parse("20060102", Date)
|
||||
|
||||
65
pkg/version/version_test.go
Normal file
65
pkg/version/version_test.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package version_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
)
|
||||
|
||||
func TestChannel(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
got string
|
||||
valid bool
|
||||
}{
|
||||
"no channel, defaults to dev": {
|
||||
got: "",
|
||||
valid: false,
|
||||
},
|
||||
"dev channel": {
|
||||
got: version.EditionDev,
|
||||
valid: true,
|
||||
},
|
||||
"rolling channel": {
|
||||
got: version.EditionRolling,
|
||||
valid: true,
|
||||
},
|
||||
"stable channel": {
|
||||
got: version.EditionStable,
|
||||
valid: true,
|
||||
},
|
||||
"lts channel without version": {
|
||||
got: version.EditionLTS,
|
||||
valid: false,
|
||||
},
|
||||
"lts-1.0.0 channel": {
|
||||
got: fmt.Sprintf("%s-1", version.EditionLTS),
|
||||
valid: true,
|
||||
},
|
||||
"lts-one invalid version": {
|
||||
got: fmt.Sprintf("%s-one", version.EditionLTS),
|
||||
valid: false,
|
||||
},
|
||||
"known channel with version": {
|
||||
got: fmt.Sprintf("%s-1", version.EditionStable),
|
||||
valid: false,
|
||||
},
|
||||
"unknown channel": {
|
||||
got: "foo",
|
||||
valid: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
version.Edition = test.got
|
||||
|
||||
switch err := version.InitEdition(); {
|
||||
case err != nil && !test.valid && version.Edition != version.Dev: // if a given edition is unknown, the value is always dev
|
||||
fallthrough
|
||||
case test.valid != (err == nil):
|
||||
t.Fatalf("invalid edition: %s", version.Edition)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-12 00:01+0000\n"
|
||||
"POT-Creation-Date: 2025-12-03 00:01+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Stephan Paternotte <stephan@paternottes.net>, 2025\n"
|
||||
"Language-Team: Dutch (https://app.transifex.com/opencloud-eu/teams/204053/nl/)\n"
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-17 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Mário Machado, 2025\n"
|
||||
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"
|
||||
|
||||
@@ -12,7 +12,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-12 00:01+0000\n"
|
||||
"POT-Creation-Date: 2025-12-03 00:01+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Lulufox, 2025\n"
|
||||
"Language-Team: Russian (https://app.transifex.com/opencloud-eu/teams/204053/ru/)\n"
|
||||
|
||||
@@ -33,7 +33,7 @@ type Config struct {
|
||||
EnableFederatedSharingIncoming bool `yaml:"enable_federated_sharing_incoming" env:"OC_ENABLE_OCM;FRONTEND_ENABLE_FEDERATED_SHARING_INCOMING" desc:"Changing this value is NOT supported. Enables support for incoming federated sharing for clients. The backend behaviour is not changed." introductionVersion:"1.0.0"`
|
||||
EnableFederatedSharingOutgoing bool `yaml:"enable_federated_sharing_outgoing" env:"OC_ENABLE_OCM;FRONTEND_ENABLE_FEDERATED_SHARING_OUTGOING" desc:"Changing this value is NOT supported. Enables support for outgoing federated sharing for clients. The backend behaviour is not changed." introductionVersion:"1.0.0"`
|
||||
SearchMinLength int `yaml:"search_min_length" env:"FRONTEND_SEARCH_MIN_LENGTH" desc:"Minimum number of characters to enter before a client should start a search for Share receivers. This setting can be used to customize the user experience if e.g too many results are displayed." introductionVersion:"1.0.0"`
|
||||
Edition string `yaml:"edition" env:"OC_EDITION;FRONTEND_EDITION" desc:"Edition of OpenCloud. Used for branding purposes." introductionVersion:"1.0.0"`
|
||||
Edition string `desc:"Edition of OpenCloud. Used for branding purposes." introductionVersion:"1.0.0"`
|
||||
DisableSSE bool `yaml:"disable_sse" env:"OC_DISABLE_SSE;FRONTEND_DISABLE_SSE" desc:"When set to true, clients are informed that the Server-Sent Events endpoint is not accessible." introductionVersion:"1.0.0"`
|
||||
DisableRadicale bool `yaml:"disable_radicale" env:"FRONTEND_DISABLE_RADICALE" desc:"When set to true, clients are informed that the Radicale (CalDAV/CardDAV) is not accessible." introductionVersion:"4.0.0"`
|
||||
DefaultLinkPermissions int `yaml:"default_link_permissions" env:"FRONTEND_DEFAULT_LINK_PERMISSIONS" desc:"Defines the default permissions a link is being created with. Possible values are 0 (= internal link, for instance members only) and 1 (= public link with viewer permissions). Defaults to 1." introductionVersion:"1.0.0"`
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
"github.com/opencloud-eu/opencloud/services/frontend/pkg/config"
|
||||
)
|
||||
|
||||
@@ -87,7 +88,7 @@ func DefaultConfig() *config.Config {
|
||||
DefaultUploadProtocol: "tus",
|
||||
DefaultLinkPermissions: 1,
|
||||
SearchMinLength: 3,
|
||||
Edition: "",
|
||||
Edition: version.Edition,
|
||||
CheckForUpdates: true,
|
||||
Checksums: config.Checksums{
|
||||
SupportedTypes: []string{"sha1", "md5", "adler32"},
|
||||
|
||||
@@ -346,7 +346,7 @@ func FrontendConfigFromStruct(cfg *config.Config, logger log.Logger) (map[string
|
||||
},
|
||||
"version": map[string]interface{}{
|
||||
"product": "OpenCloud",
|
||||
"edition": "",
|
||||
"edition": version.Edition,
|
||||
"major": version.ParsedLegacy().Major(),
|
||||
"minor": version.ParsedLegacy().Minor(),
|
||||
"micro": version.ParsedLegacy().Patch(),
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-15 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Stephan Paternotte <stephan@paternottes.net>, 2025\n"
|
||||
"Language-Team: Dutch (https://app.transifex.com/opencloud-eu/teams/204053/nl/)\n"
|
||||
|
||||
@@ -14,7 +14,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-15 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Radoslaw Posim, 2025\n"
|
||||
"Language-Team: Polish (https://app.transifex.com/opencloud-eu/teams/204053/pl/)\n"
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-17 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Mário Machado, 2025\n"
|
||||
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"
|
||||
|
||||
@@ -12,7 +12,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-21 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Lulufox, 2025\n"
|
||||
"Language-Team: Russian (https://app.transifex.com/opencloud-eu/teams/204053/ru/)\n"
|
||||
|
||||
@@ -12,7 +12,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-23 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: miguel tapias, 2025\n"
|
||||
"Language-Team: Spanish (https://app.transifex.com/opencloud-eu/teams/204053/es/)\n"
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-24 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-14 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>, 2025\n"
|
||||
"Language-Team: Finnish (https://app.transifex.com/opencloud-eu/teams/204053/fi/)\n"
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-15 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Stephan Paternotte <stephan@paternottes.net>, 2025\n"
|
||||
"Language-Team: Dutch (https://app.transifex.com/opencloud-eu/teams/204053/nl/)\n"
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-18 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Mário Machado, 2025\n"
|
||||
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"
|
||||
|
||||
@@ -12,7 +12,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-16 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Lulufox, 2025\n"
|
||||
"Language-Team: Russian (https://app.transifex.com/opencloud-eu/teams/204053/ru/)\n"
|
||||
|
||||
@@ -80,5 +80,5 @@ type Status struct {
|
||||
Product string
|
||||
ProductName string
|
||||
ProductVersion string
|
||||
Edition string `yaml:"edition" env:"OC_EDITION;OCDAV_EDITION" desc:"Edition of OpenCloud. Used for branding purposes." introductionVersion:"1.0.0"`
|
||||
Edition string `desc:"Edition of OpenCloud. Used for branding purposes." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func DefaultConfig() *config.Config {
|
||||
ProductVersion: version.GetString(),
|
||||
Product: "OpenCloud",
|
||||
ProductName: "OpenCloud",
|
||||
Edition: "",
|
||||
Edition: version.Edition,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,4 +164,4 @@ A good example of how such a file should be formatted can be found in the [Apach
|
||||
|
||||
## Example Policies
|
||||
|
||||
The policies service contains a set of preconfigured example policies. See the [deployment examples](https://github.com/opencloud-eu/opencloud/tree/main/deployments/examples) directory for details. The contained policies disallow OpenCloud to create certain file types, both via the proxy middleware and the events service via postprocessing.
|
||||
The policies service contains a set of preconfigured example policies. See the [devtools policie](https://github.com/opencloud-eu/opencloud/tree/main/devtools/deployments/service_policies/policies/) directory for details. The contained policies disallow OpenCloud to create certain file types, both via the proxy middleware and the events service via postprocessing.
|
||||
|
||||
@@ -7,5 +7,5 @@ type HTTP struct {
|
||||
Namespace string `yaml:"-"`
|
||||
TLSCert string `yaml:"tls_cert" env:"PROXY_TRANSPORT_TLS_CERT" desc:"Path/File name of the TLS server certificate (in PEM format) for the external http services. If not defined, the root directory derives from $OC_BASE_DATA_PATH/proxy." introductionVersion:"1.0.0"`
|
||||
TLSKey string `yaml:"tls_key" env:"PROXY_TRANSPORT_TLS_KEY" desc:"Path/File name for the TLS certificate key (in PEM format) for the server certificate to use for the external http services. If not defined, the root directory derives from $OC_BASE_DATA_PATH/proxy." introductionVersion:"1.0.0"`
|
||||
TLS bool `yaml:"tls" env:"PROXY_TLS" desc:"Enable/Disable HTTPS for external HTTP services. Must be set to 'true' if the built-in IDP service an no reverse proxy is used. See the text description for details." introductionVersion:"1.0.0"`
|
||||
TLS bool `yaml:"tls" env:"PROXY_TLS" desc:"Enable/Disable HTTPS for external HTTP services. Must be set to 'true' if the built-in IDP service and no reverse proxy is used. See the text description for details." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-24 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-14 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>, 2025\n"
|
||||
"Language-Team: Finnish (https://app.transifex.com/opencloud-eu/teams/204053/fi/)\n"
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-18 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: idoet <idoet@protonmail.ch>, 2025\n"
|
||||
"Language-Team: Indonesian (https://app.transifex.com/opencloud-eu/teams/204053/id/)\n"
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-12 00:01+0000\n"
|
||||
"POT-Creation-Date: 2025-12-03 00:01+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Stephan Paternotte <stephan@paternottes.net>, 2025\n"
|
||||
"Language-Team: Dutch (https://app.transifex.com/opencloud-eu/teams/204053/nl/)\n"
|
||||
|
||||
@@ -13,7 +13,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-15 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Radoslaw Posim, 2025\n"
|
||||
"Language-Team: Polish (https://app.transifex.com/opencloud-eu/teams/204053/pl/)\n"
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-17 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Mário Machado, 2025\n"
|
||||
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-15 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Stephan Paternotte <stephan@paternottes.net>, 2025\n"
|
||||
"Language-Team: Dutch (https://app.transifex.com/opencloud-eu/teams/204053/nl/)\n"
|
||||
|
||||
@@ -13,7 +13,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-15 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Radoslaw Posim, 2025\n"
|
||||
"Language-Team: Polish (https://app.transifex.com/opencloud-eu/teams/204053/pl/)\n"
|
||||
|
||||
@@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: EMAIL\n"
|
||||
"POT-Creation-Date: 2025-11-17 00:02+0000\n"
|
||||
"POT-Creation-Date: 2025-12-13 00:02+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
|
||||
"Last-Translator: Mário Machado, 2025\n"
|
||||
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
SHELL := bash
|
||||
NAME := web
|
||||
WEB_ASSETS_VERSION = v4.2.1
|
||||
WEB_ASSETS_VERSION = v4.3.0
|
||||
WEB_ASSETS_BRANCH = main
|
||||
|
||||
ifneq (, $(shell command -v go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
|
||||
|
||||
@@ -136,6 +136,9 @@ func (p Web) getPayload() (payload []byte, err error) {
|
||||
p.config.Web.Config.Apps = make([]string, 0)
|
||||
}
|
||||
|
||||
// ensure that the server url has a trailing slash
|
||||
p.config.Web.Config.Server = strings.TrimRight(p.config.Web.Config.Server, "/") + "/"
|
||||
|
||||
return json.Marshal(p.config.Web.Config)
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ use SimpleXMLElement;
|
||||
use Sabre\Xml\LibXMLException;
|
||||
use Sabre\Xml\Reader;
|
||||
use GuzzleHttp\Pool;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Helper for HTTP requests
|
||||
@@ -74,7 +75,6 @@ class HttpRequestHelper {
|
||||
* than download it all up-front.
|
||||
* @param int|null $timeout
|
||||
* @param Client|null $client
|
||||
* @param string|null $bearerToken
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
@@ -92,8 +92,42 @@ class HttpRequestHelper {
|
||||
bool $stream = false,
|
||||
?int $timeout = 0,
|
||||
?Client $client = null,
|
||||
?string $bearerToken = null
|
||||
): ResponseInterface {
|
||||
$bearerToken = null;
|
||||
if (TokenHelper::useBearerToken() && $user && $user !== 'public') {
|
||||
$bearerToken = TokenHelper::getTokens($user, $password, $url)['access_token'];
|
||||
// check token is still valid
|
||||
$parsedUrl = parse_url($url);
|
||||
$baseUrl = $parsedUrl['scheme'] . '://' . $parsedUrl['host'];
|
||||
$baseUrl .= isset($parsedUrl['port']) ? ':' . $parsedUrl['port'] : '';
|
||||
$testUrl = $baseUrl . "/graph/v1.0/use/$user";
|
||||
if (OcHelper::isTestingOnReva()) {
|
||||
$url = $baseUrl . "/ocs/v2.php/cloud/users/$user";
|
||||
}
|
||||
// check token validity with a GET request
|
||||
$c = self::createClient(
|
||||
$user,
|
||||
$password,
|
||||
$config,
|
||||
$cookies,
|
||||
$stream,
|
||||
$timeout,
|
||||
$bearerToken
|
||||
);
|
||||
$testReq = self::createRequest($testUrl, $xRequestId, 'GET');
|
||||
try {
|
||||
$testRes = $c->send($testReq);
|
||||
} catch (RequestException $ex) {
|
||||
$testRes = $ex->getResponse();
|
||||
if ($testRes && $testRes->getStatusCode() === Response::HTTP_UNAUTHORIZED) {
|
||||
// token is invalid or expired, get a new one
|
||||
echo "[INFO] Bearer token expired or invalid, getting a new one...\n";
|
||||
TokenHelper::clearAllTokens();
|
||||
$bearerToken = TokenHelper::getTokens($user, $password, $url)['access_token'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($client === null) {
|
||||
$client = self::createClient(
|
||||
$user,
|
||||
@@ -160,6 +194,24 @@ class HttpRequestHelper {
|
||||
}
|
||||
|
||||
HttpLogger::logResponse($response);
|
||||
|
||||
// wait for post-processing to finish if applicable
|
||||
if (WebdavHelper::isDAVRequest($url)
|
||||
&& \str_starts_with($url, OcHelper::getServerUrl())
|
||||
&& \in_array($method, ["PUT", "MOVE", "COPY"])
|
||||
&& \in_array($response->getStatusCode(), [Response::HTTP_CREATED, Response::HTTP_NO_CONTENT])
|
||||
&& OcConfigHelper::getPostProcessingDelay() === 0
|
||||
) {
|
||||
if (\in_array($method, ["MOVE", "COPY"])) {
|
||||
$url = $headers['Destination'];
|
||||
}
|
||||
WebDavHelper::waitForPostProcessingToFinish(
|
||||
$url,
|
||||
$user,
|
||||
$password,
|
||||
$headers,
|
||||
);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -203,13 +255,6 @@ class HttpRequestHelper {
|
||||
} else {
|
||||
$debugResponses = false;
|
||||
}
|
||||
// use basic auth for 'public' user or no user
|
||||
if ($user === 'public' || $user === null || $user === '') {
|
||||
$bearerToken = null;
|
||||
} else {
|
||||
$useBearerToken = TokenHelper::useBearerToken();
|
||||
$bearerToken = $useBearerToken ? TokenHelper::getTokens($user, $password, $url)['access_token'] : null;
|
||||
}
|
||||
|
||||
$sendRetryLimit = self::numRetriesOnHttpTooEarly();
|
||||
$sendCount = 0;
|
||||
@@ -228,7 +273,6 @@ class HttpRequestHelper {
|
||||
$stream,
|
||||
$timeout,
|
||||
$client,
|
||||
$bearerToken,
|
||||
);
|
||||
|
||||
if ($response->getStatusCode() >= 400
|
||||
@@ -256,7 +300,8 @@ class HttpRequestHelper {
|
||||
// we need to repeat the send request, because we got HTTP_TOO_EARLY or HTTP_CONFLICT
|
||||
// wait 1 second before sending again, to give the server some time
|
||||
// to finish whatever post-processing it might be doing.
|
||||
self::debugResponse($response);
|
||||
echo "[INFO] Received '" . $response->getStatusCode() .
|
||||
"' status code, retrying request ($sendCount)...\n";
|
||||
\sleep(1);
|
||||
}
|
||||
} while ($loopAgain);
|
||||
|
||||
@@ -30,6 +30,26 @@ use Psr\Http\Message\ResponseInterface;
|
||||
* A helper class for configuring OpenCloud server
|
||||
*/
|
||||
class OcConfigHelper {
|
||||
public static $postProcessingDelay = 0;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public static function getPostProcessingDelay(): int {
|
||||
return self::$postProcessingDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $postProcessingDelay
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setPostProcessingDelay(string $postProcessingDelay): void {
|
||||
// extract number from string
|
||||
$delay = (int) filter_var($postProcessingDelay, FILTER_SANITIZE_NUMBER_INT);
|
||||
self::$postProcessingDelay = $delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
|
||||
@@ -84,7 +84,9 @@ class TokenHelper {
|
||||
$tokenData = [
|
||||
'access_token' => $refreshedToken['access_token'],
|
||||
'refresh_token' => $refreshedToken['refresh_token'],
|
||||
'expires_at' => time() + 300 // 5 minutes
|
||||
// set expiry to 240 (4 minutes) seconds to allow for some buffer
|
||||
// token actually expires in 300 seconds (5 minutes)
|
||||
'expires_at' => time() + 240
|
||||
];
|
||||
self::$tokenCache[$cacheKey] = $tokenData;
|
||||
return $tokenData;
|
||||
@@ -100,7 +102,9 @@ class TokenHelper {
|
||||
$tokenData = [
|
||||
'access_token' => $tokens['access_token'],
|
||||
'refresh_token' => $tokens['refresh_token'],
|
||||
'expires_at' => time() + 290 // set expiry to 290 seconds to allow for some buffer
|
||||
// set expiry to 240 (4 minutes) seconds to allow for some buffer
|
||||
// token actually expires in 300 seconds (5 minutes)
|
||||
'expires_at' => time() + 240
|
||||
];
|
||||
|
||||
// Save to cache
|
||||
|
||||
@@ -923,4 +923,45 @@ class WebDavHelper {
|
||||
$mtime = new DateTime($xmlPart[0]->__toString());
|
||||
return $mtime->format('U');
|
||||
}
|
||||
|
||||
/**
|
||||
* wait until the reqeust doesn't return 425 anymore
|
||||
*
|
||||
* @param string $url
|
||||
* @param ?string $user
|
||||
* @param ?string $password
|
||||
* @param ?array $headers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function waitForPostProcessingToFinish(
|
||||
string $url,
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?array $headers = [],
|
||||
): void {
|
||||
$retried = 0;
|
||||
do {
|
||||
$response = HttpRequestHelper::sendRequest(
|
||||
$url,
|
||||
'check-425-status',
|
||||
'GET',
|
||||
$user,
|
||||
$password,
|
||||
$headers,
|
||||
);
|
||||
$statusCode = $response->getStatusCode();
|
||||
if ($statusCode !== 425) {
|
||||
return;
|
||||
}
|
||||
$tryAgain = $retried < HttpRequestHelper::numRetriesOnHttpTooEarly();
|
||||
if ($tryAgain) {
|
||||
$retried += 1;
|
||||
echo "[INFO] Waiting for post processing to finish, attempt ($retried)...\n";
|
||||
// wait 1s and try again
|
||||
\sleep(1);
|
||||
}
|
||||
} while ($tryAgain);
|
||||
echo "[ERROR] 10 seconds timeout! Post processing did not finish in time.\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,7 +904,7 @@ class CliContext implements Context {
|
||||
$userUuid = $this->featureContext->getAttributeOfCreatedUser($user, 'id');
|
||||
$storagePath = $this->getUsersStoragePath();
|
||||
$body = [
|
||||
"command" => "xattr -p -slz " . escapeshellarg($attribute) . " $storagePath/$userUuid/$file",
|
||||
"command" => "getfattr -n " . escapeshellarg($attribute) . " --only-values $storagePath/$userUuid/$file",
|
||||
"raw" => true
|
||||
];
|
||||
$this->featureContext->setResponse(CliHelper::runCommand($body));
|
||||
|
||||
@@ -2026,8 +2026,12 @@ class FeatureContext extends BehatVariablesContext {
|
||||
if ($response === null) {
|
||||
$response = $this->getResponse();
|
||||
}
|
||||
$body = (string)$response->getBody();
|
||||
if (!$body) {
|
||||
return [];
|
||||
}
|
||||
return \json_decode(
|
||||
(string)$response->getBody(),
|
||||
$body,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ class OcConfigContext implements Context {
|
||||
$response->getStatusCode(),
|
||||
"Failed to set async upload with delayed post processing"
|
||||
);
|
||||
OcConfigHelper::setPostProcessingDelay($delayTime);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +91,9 @@ class OcConfigContext implements Context {
|
||||
$response->getStatusCode(),
|
||||
"Failed to set config $configVariable=$configValue"
|
||||
);
|
||||
if ($configVariable === "POSTPROCESSING_DELAY") {
|
||||
OcConfigHelper::setPostProcessingDelay($configValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,6 +188,9 @@ class OcConfigContext implements Context {
|
||||
$envs = [];
|
||||
foreach ($table->getHash() as $row) {
|
||||
$envs[$row['config']] = $row['value'];
|
||||
if ($row['config'] === "POSTPROCESSING_DELAY") {
|
||||
OcConfigHelper::setPostProcessingDelay($row['value']);
|
||||
}
|
||||
}
|
||||
|
||||
$response = OcConfigHelper::reConfigureOc($envs);
|
||||
@@ -200,6 +207,7 @@ class OcConfigContext implements Context {
|
||||
* @return void
|
||||
*/
|
||||
public function rollbackOc(): void {
|
||||
OcConfigHelper::setPostProcessingDelay('0');
|
||||
$response = OcConfigHelper::rollbackOc();
|
||||
Assert::assertEquals(
|
||||
200,
|
||||
|
||||
@@ -607,7 +607,7 @@ trait Provisioning {
|
||||
Assert::assertEquals(
|
||||
201,
|
||||
$response->getStatusCode(),
|
||||
__METHOD__ . " cannot create user '$userName' using Graph API.\nResponse:" .
|
||||
__METHOD__ . " cannot create user '$userName'.\nResponse:" .
|
||||
json_encode($this->getJsonDecodedResponse($response))
|
||||
);
|
||||
|
||||
@@ -1083,7 +1083,7 @@ trait Provisioning {
|
||||
Assert::assertEquals(
|
||||
201,
|
||||
$response->getStatusCode(),
|
||||
__METHOD__ . " cannot create user '$user' using Graph API.\nResponse:" .
|
||||
__METHOD__ . " cannot create user '$user'.\nResponse:" .
|
||||
json_encode($this->getJsonDecodedResponse($response))
|
||||
);
|
||||
$userId = $this->getJsonDecodedResponse($response)['id'];
|
||||
|
||||
@@ -750,6 +750,9 @@ class SpacesContext implements Context {
|
||||
} else {
|
||||
$rawBody = $this->featureContext->getResponse()->getBody()->getContents();
|
||||
}
|
||||
if (!$rawBody) {
|
||||
throw new Exception(__METHOD__ . " - Response body is empty");
|
||||
}
|
||||
$drives = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
|
||||
if (isset($drives["value"])) {
|
||||
$drives = $drives["value"];
|
||||
|
||||
@@ -216,6 +216,44 @@ class TUSContext implements Context {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user sends a chunk to the last created TUS Location with offset :offset and data :data with retry on offset mismatch using the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $offset
|
||||
* @param string $data
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws GuzzleException
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function userSendsAChunkToTUSLocationWithOffsetAndDataWithRetryOnOffsetMismatch(
|
||||
string $user,
|
||||
string $offset,
|
||||
string $data,
|
||||
): void {
|
||||
$resourceLocation = $this->getLastTusResourceLocation();
|
||||
|
||||
$retried = 0;
|
||||
do {
|
||||
$tryAgain = false;
|
||||
$response = $this->uploadChunkToTUSLocation($user, $resourceLocation, $offset, $data);
|
||||
// retry on 409 Conflict (Offset mismatch during TUS upload)
|
||||
if ($response->getStatusCode() === 409) {
|
||||
$tryAgain = true;
|
||||
}
|
||||
$tryAgain = $tryAgain && $retried < HttpRequestHelper::numRetriesOnHttpTooEarly();
|
||||
if ($tryAgain) {
|
||||
$retried += 1;
|
||||
echo "Offset mismatch during TUS upload, retrying ($retried)...\n";
|
||||
// wait 1s and try again
|
||||
\sleep(1);
|
||||
}
|
||||
} while ($tryAgain);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user sends a chunk to the last created TUS Location with offset :offset and data :data using the WebDAV API
|
||||
*
|
||||
|
||||
@@ -25,6 +25,7 @@ use GuzzleHttp\Exception\GuzzleException;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use GuzzleHttp\Stream\StreamInterface;
|
||||
use TestHelpers\OcConfigHelper;
|
||||
use TestHelpers\OcHelper;
|
||||
use TestHelpers\UploadHelper;
|
||||
use TestHelpers\WebDavHelper;
|
||||
@@ -743,6 +744,7 @@ trait WebDav {
|
||||
|
||||
/**
|
||||
* @When the user waits for :time seconds for postprocessing to finish
|
||||
* @When the user waits for :time seconds
|
||||
*
|
||||
* @param int $time
|
||||
*
|
||||
@@ -973,6 +975,61 @@ trait WebDav {
|
||||
$this->checkDownloadedContentMatches($content, '', $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* check file content with retry
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $fileName
|
||||
* @param string $content
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkFileContentWithRetry(string $user, string $fileName, string $content): void {
|
||||
$retried = 0;
|
||||
do {
|
||||
$tryAgain = false;
|
||||
$response = $this->downloadFileAsUserUsingPassword($this->getActualUsername($user), $fileName);
|
||||
$status = $response->getStatusCode();
|
||||
$downloadedContent = $response->getBody()->getContents();
|
||||
if ($status !== 200) {
|
||||
$tryAgain = true;
|
||||
$message = "Expected '200' but got '$status'";
|
||||
} elseif ($downloadedContent !== $content) {
|
||||
$tryAgain = true;
|
||||
$message = "Expected content '$content' but got '$downloadedContent'";
|
||||
}
|
||||
$tryAgain = $tryAgain && $retried < HttpRequestHelper::numRetriesOnHttpTooEarly();
|
||||
if ($tryAgain) {
|
||||
$retried += 1;
|
||||
echo "[INFO] File content mismatch. $message, checking content again ($retried)...\n";
|
||||
|
||||
// break the loop if status is 425 as the request will already be retried
|
||||
if ($status === HttpRequestHelper::HTTP_TOO_EARLY) {
|
||||
break;
|
||||
}
|
||||
|
||||
// wait 1s and try again
|
||||
\sleep(1);
|
||||
}
|
||||
} while ($tryAgain);
|
||||
$this->theHTTPStatusCodeShouldBe(200, '', $response);
|
||||
$this->checkDownloadedContentMatches($content, '', $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then as :user the final content of file :fileName should be :content
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $fileName
|
||||
* @param string $content
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function asUserFinalContentOfFileShouldBe(string $user, string $fileName, string $content): void {
|
||||
$this->checkFileContentWithRetry($user, $fileName, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^the content of the following files for user "([^"]*)" should be "([^"]*)"$/
|
||||
*
|
||||
@@ -1264,20 +1321,18 @@ trait WebDav {
|
||||
$type
|
||||
);
|
||||
$statusCode = $response->getStatusCode();
|
||||
if ($statusCode < 400 || $statusCode > 499) {
|
||||
try {
|
||||
$responseXmlObject = HttpRequestHelper::getResponseXml(
|
||||
$response,
|
||||
__METHOD__
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
Assert::fail(
|
||||
"$entry '$path' should not exist. But API returned $statusCode without XML in the body"
|
||||
);
|
||||
}
|
||||
// when checking path with '..' it may return 405 Method Not Allowed
|
||||
if ($statusCode === 404 || $statusCode === 405) {
|
||||
return;
|
||||
}
|
||||
if ($statusCode === 207) {
|
||||
$responseXmlObject = HttpRequestHelper::getResponseXml(
|
||||
$response,
|
||||
__METHOD__
|
||||
);
|
||||
Assert::assertTrue(
|
||||
$this->isEtagValid($this->getEtagFromResponseXmlObject($responseXmlObject)),
|
||||
"$entry '$path' should not exist. But API returned $statusCode without an etag in the body"
|
||||
"$entry '$path' should not exist but found with invalid etag."
|
||||
);
|
||||
$isCollection = $responseXmlObject->xpath("//d:prop/d:resourcetype/d:collection");
|
||||
if (\count($isCollection) === 0) {
|
||||
@@ -1291,7 +1346,11 @@ trait WebDav {
|
||||
"$entry '$path' should not exist. But it does."
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Assert::fail(
|
||||
"$entry '$path' should not exist. But API returned $statusCode without XML in the body"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2270,6 +2329,11 @@ trait WebDav {
|
||||
"HTTP status code was not 201 or 204 while trying to upload file '$destination' for user '$user'",
|
||||
$response
|
||||
);
|
||||
|
||||
// check uploaded content only if post-processing delay is not configured
|
||||
if (OcConfigHelper::getPostProcessingDelay() === 0) {
|
||||
$this->checkFileContentWithRetry($user, $destination, $content);
|
||||
}
|
||||
return $response->getHeader('oc-fileid');
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ Feature: create a resources using collaborative posixfs
|
||||
Scenario: create file
|
||||
When the administrator creates the file "test.txt" with content "content" for user "Alice" on the POSIX filesystem
|
||||
Then the command should be successful
|
||||
And the content of file "/test.txt" for user "Alice" should be "content"
|
||||
And as "Alice" the final content of file "test.txt" should be "content"
|
||||
|
||||
|
||||
Scenario: create large file
|
||||
@@ -41,21 +41,22 @@ Feature: create a resources using collaborative posixfs
|
||||
Scenario: creates files sequentially in a folder
|
||||
When the administrator creates 50 files sequentially in the directory "firstFolder" for user "Alice" on the POSIX filesystem
|
||||
Then the command should be successful
|
||||
And the content of file "/firstFolder/file_1.txt" for user "Alice" should be "file 1 content"
|
||||
And the content of file "/firstFolder/file_50.txt" for user "Alice" should be "file 50 content"
|
||||
And as "Alice" the final content of file "/firstFolder/file_1.txt" should be "file 1 content"
|
||||
And as "Alice" the final content of file "/firstFolder/file_50.txt" should be "file 50 content"
|
||||
|
||||
|
||||
Scenario: creates files in parallel in a folder
|
||||
When the administrator creates 100 files in parallel in the directory "firstFolder" for user "Alice" on the POSIX filesystem
|
||||
Then the command should be successful
|
||||
And the content of file "/firstFolder/parallel_1.txt" for user "Alice" should be "parallel file 1 content"
|
||||
And the content of file "/firstFolder/parallel_100.txt" for user "Alice" should be "parallel file 100 content"
|
||||
And as "Alice" the final content of file "/firstFolder/parallel_1.txt" should be "parallel file 1 content"
|
||||
And as "Alice" the final content of file "/firstFolder/parallel_100.txt" should be "parallel file 100 content"
|
||||
|
||||
|
||||
Scenario: edit file
|
||||
Given user "Alice" has uploaded file with content "content" to "test.txt"
|
||||
When the administrator puts the content "new" into the file "test.txt" in the POSIX storage folder of user "Alice"
|
||||
Then the content of file "/test.txt" for user "Alice" should be "contentnew"
|
||||
Then the command should be successful
|
||||
And as "Alice" the final content of file "test.txt" should be "contentnew"
|
||||
|
||||
|
||||
Scenario: read file content
|
||||
@@ -68,28 +69,43 @@ Feature: create a resources using collaborative posixfs
|
||||
Given user "Alice" has uploaded file with content "content" to "test.txt"
|
||||
When the administrator copies the file "test.txt" to the folder "firstFolder" for user "Alice" on the POSIX filesystem
|
||||
Then the command should be successful
|
||||
And the content of file "/firstFolder/test.txt" for user "Alice" should be "content"
|
||||
And as "Alice" the final content of file "/firstFolder/test.txt" should be "content"
|
||||
|
||||
|
||||
Scenario: rename file
|
||||
Given user "Alice" has uploaded file with content "content" to "test.txt"
|
||||
When the administrator renames the file "test.txt" to "new-name.txt" for user "Alice" on the POSIX filesystem
|
||||
Then the command should be successful
|
||||
And the content of file "/new-name.txt" for user "Alice" should be "content"
|
||||
And as "Alice" the final content of file "/new-name.txt" should be "content"
|
||||
|
||||
|
||||
Scenario: check propfind after rename file
|
||||
Given user "Alice" has uploaded file with content "content" to "test.txt"
|
||||
When the administrator renames the file "test.txt" to "new-name.txt" for user "Alice" on the POSIX filesystem
|
||||
Then the command should be successful
|
||||
When user "Alice" sends PROPFIND request to space "Personal" using the WebDAV API
|
||||
Then the HTTP status code should be "207"
|
||||
And as user "Alice" the PROPFIND response should contain a resource "new-name.txt" with these key and value pairs:
|
||||
| key | value |
|
||||
| oc:fileid | %file_id_pattern% |
|
||||
| oc:name | new-name.txt |
|
||||
| oc:permissions | RDNVWZP |
|
||||
| oc:privatelink | %base_url%/f/[0-9a-z-$%]+ |
|
||||
| oc:size | 7 |
|
||||
|
||||
|
||||
Scenario: rename a created file
|
||||
Given the administrator has created the file "test.txt" with content "content" for user "Alice" on the POSIX filesystem
|
||||
When the administrator renames the file "test.txt" to "test.md" for user "Alice" on the POSIX filesystem
|
||||
Then the command should be successful
|
||||
And the content of file "/test.md" for user "Alice" should be "content"
|
||||
And as "Alice" the final content of file "/test.md" should be "content"
|
||||
|
||||
|
||||
Scenario: move file to folder
|
||||
Given user "Alice" has uploaded file with content "content" to "test.txt"
|
||||
When the administrator moves the file "test.txt" to the folder "firstFolder" for user "Alice" on the POSIX filesystem
|
||||
Then the command should be successful
|
||||
And the content of file "/firstFolder/test.txt" for user "Alice" should be "content"
|
||||
And as "Alice" the final content of file "/firstFolder/test.txt" should be "content"
|
||||
And as "Alice" file "/test.txt" should not exist
|
||||
|
||||
|
||||
@@ -187,4 +203,4 @@ Feature: create a resources using collaborative posixfs
|
||||
And the administrator renames the file "test.txt" to "renamed.txt" for user "Alice" on the POSIX filesystem
|
||||
And the administrator checks the attribute "user.oc.name" of file "renamed.txt" for user "Alice" on the POSIX filesystem
|
||||
Then the command output should contain "renamed.txt"
|
||||
And the content of file "/renamed.txt" for user "Alice" should be "content"
|
||||
And as "Alice" the final content of file "/renamed.txt" should be "content"
|
||||
|
||||
@@ -202,7 +202,7 @@ Feature: capabilities
|
||||
"properties": {
|
||||
"edition": {
|
||||
"type": "string",
|
||||
"enum": ["%edition%"]
|
||||
"enum": ["dev"]
|
||||
},
|
||||
"product": {
|
||||
"type": "string",
|
||||
@@ -240,7 +240,7 @@ Feature: capabilities
|
||||
},
|
||||
"edition": {
|
||||
"type": "string",
|
||||
"enum": ["%edition%"]
|
||||
"enum": ["dev"]
|
||||
},
|
||||
"product": {
|
||||
"type": "string",
|
||||
|
||||
@@ -58,7 +58,7 @@ Feature: default capabilities for normal user
|
||||
"const": "%versionstring%"
|
||||
},
|
||||
"edition": {
|
||||
"const": "%edition%"
|
||||
"const": "dev"
|
||||
},
|
||||
"productname": {
|
||||
"const": "%productname%"
|
||||
|
||||
@@ -50,8 +50,7 @@ Feature: low level tests for upload of chunks
|
||||
| Upload-Metadata | filename ZmlsZS50eHQ= |
|
||||
When user "Alice" sends a chunk to the last created TUS Location with offset "0" and data "123" using the WebDAV API
|
||||
And user "Alice" sends a chunk to the last created TUS Location with offset "3" and data "4567890" using the WebDAV API
|
||||
And the user waits for "2" seconds for postprocessing to finish
|
||||
And user "Alice" sends a chunk to the last created TUS Location with offset "3" and data "0000000" using the WebDAV API
|
||||
And user "Alice" sends a chunk to the last created TUS Location with offset "3" and data "0000000" with retry on offset mismatch using the WebDAV API
|
||||
Then the HTTP status code should be "404"
|
||||
And the content of file "/file.txt" for user "Alice" should be "1234567890"
|
||||
Examples:
|
||||
@@ -61,6 +60,22 @@ Feature: low level tests for upload of chunks
|
||||
| spaces |
|
||||
|
||||
|
||||
Scenario Outline: send last chunk with mismatch offset
|
||||
Given using <dav-path-version> DAV path
|
||||
And user "Alice" has created a new TUS resource on the WebDAV API with these headers:
|
||||
| Upload-Length | 10 |
|
||||
# ZmlsZS50eHQ= is the base64 encode of file.txt
|
||||
| Upload-Metadata | filename ZmlsZS50eHQ= |
|
||||
When user "Alice" sends a chunk to the last created TUS Location with offset "0" and data "123" using the WebDAV API
|
||||
And user "Alice" sends a chunk to the last created TUS Location with offset "2" and data "34567890" using the WebDAV API
|
||||
Then the HTTP status code should be "409"
|
||||
Examples:
|
||||
| dav-path-version |
|
||||
| old |
|
||||
| new |
|
||||
| spaces |
|
||||
|
||||
|
||||
Scenario Outline: start with uploading not at the beginning of the file
|
||||
Given using <dav-path-version> DAV path
|
||||
And user "Alice" has created a new TUS resource on the WebDAV API with these headers:
|
||||
|
||||
102
vendor/github.com/docker/docker/api/swagger.yaml
generated
vendored
102
vendor/github.com/docker/docker/api/swagger.yaml
generated
vendored
@@ -81,7 +81,6 @@ info:
|
||||
{
|
||||
"username": "string",
|
||||
"password": "string",
|
||||
"email": "string",
|
||||
"serveraddress": "string"
|
||||
}
|
||||
```
|
||||
@@ -637,6 +636,9 @@ definitions:
|
||||
by the default (runc) runtime.
|
||||
|
||||
This field is omitted when empty.
|
||||
|
||||
**Deprecated**: This field is deprecated as kernel 6.12 has deprecated `memory.kmem.tcp.limit_in_bytes` field
|
||||
for cgroups v1. This field will be removed in a future release.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
MemoryReservation:
|
||||
@@ -1531,37 +1533,6 @@ definitions:
|
||||
items:
|
||||
type: "string"
|
||||
example: ["/bin/sh", "-c"]
|
||||
# FIXME(thaJeztah): temporarily using a full example to remove some "omitempty" fields. Remove once the fields are removed.
|
||||
example:
|
||||
"User": "web:web"
|
||||
"ExposedPorts": {
|
||||
"80/tcp": {},
|
||||
"443/tcp": {}
|
||||
}
|
||||
"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]
|
||||
"Cmd": ["/bin/sh"]
|
||||
"Healthcheck": {
|
||||
"Test": ["string"],
|
||||
"Interval": 0,
|
||||
"Timeout": 0,
|
||||
"Retries": 0,
|
||||
"StartPeriod": 0,
|
||||
"StartInterval": 0
|
||||
}
|
||||
"ArgsEscaped": true
|
||||
"Volumes": {
|
||||
"/app/data": {},
|
||||
"/app/config": {}
|
||||
}
|
||||
"WorkingDir": "/public/"
|
||||
"Entrypoint": []
|
||||
"OnBuild": []
|
||||
"Labels": {
|
||||
"com.example.some-label": "some-value",
|
||||
"com.example.some-other-label": "some-other-value"
|
||||
}
|
||||
"StopSignal": "SIGTERM"
|
||||
"Shell": ["/bin/sh", "-c"]
|
||||
|
||||
NetworkingConfig:
|
||||
description: |
|
||||
@@ -1608,6 +1579,8 @@ definitions:
|
||||
Bridge:
|
||||
description: |
|
||||
Name of the default bridge interface when dockerd's --bridge flag is set.
|
||||
|
||||
Deprecated: This field is only set when the daemon is started with the --bridge flag specified.
|
||||
type: "string"
|
||||
example: "docker0"
|
||||
SandboxID:
|
||||
@@ -1965,6 +1938,11 @@ definitions:
|
||||
Depending on how the image was created, this field may be empty and
|
||||
is only set for images that were built/created locally. This field
|
||||
is empty if the image was pulled from an image registry.
|
||||
|
||||
> **Deprecated**: This field is only set when using the deprecated
|
||||
> legacy builder. It is included in API responses for informational
|
||||
> purposes, but should not be depended on as it will be omitted
|
||||
> once the legacy builder is removed.
|
||||
type: "string"
|
||||
x-nullable: false
|
||||
example: ""
|
||||
@@ -1990,6 +1968,11 @@ definitions:
|
||||
The version of Docker that was used to build the image.
|
||||
|
||||
Depending on how the image was created, this field may be empty.
|
||||
|
||||
> **Deprecated**: This field is only set when using the deprecated
|
||||
> legacy builder. It is included in API responses for informational
|
||||
> purposes, but should not be depended on as it will be omitted
|
||||
> once the legacy builder is removed.
|
||||
type: "string"
|
||||
x-nullable: false
|
||||
example: "27.0.1"
|
||||
@@ -2034,14 +2017,6 @@ definitions:
|
||||
format: "int64"
|
||||
x-nullable: false
|
||||
example: 1239828
|
||||
VirtualSize:
|
||||
description: |
|
||||
Total size of the image including all layers it is composed of.
|
||||
|
||||
Deprecated: this field is omitted in API v1.44, but kept for backward compatibility. Use Size instead.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
example: 1239828
|
||||
GraphDriver:
|
||||
$ref: "#/definitions/DriverData"
|
||||
RootFS:
|
||||
@@ -2174,14 +2149,6 @@ definitions:
|
||||
format: "int64"
|
||||
x-nullable: false
|
||||
example: 1239828
|
||||
VirtualSize:
|
||||
description: |-
|
||||
Total size of the image including all layers it is composed of.
|
||||
|
||||
Deprecated: this field is omitted in API v1.44, but kept for backward compatibility. Use Size instead.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
example: 172064416
|
||||
Labels:
|
||||
description: "User-defined key/value metadata."
|
||||
type: "object"
|
||||
@@ -2234,6 +2201,10 @@ definitions:
|
||||
password:
|
||||
type: "string"
|
||||
email:
|
||||
description: |
|
||||
Email is an optional value associated with the username.
|
||||
|
||||
> **Deprecated**: This field is deprecated since docker 1.11 (API v1.23) and will be removed in a future release.
|
||||
type: "string"
|
||||
serveraddress:
|
||||
type: "string"
|
||||
@@ -3171,10 +3142,15 @@ definitions:
|
||||
- Args
|
||||
properties:
|
||||
DockerVersion:
|
||||
description: "Docker Version used to create the plugin"
|
||||
description: |-
|
||||
Docker Version used to create the plugin.
|
||||
|
||||
Depending on how the plugin was created, this field may be empty or omitted.
|
||||
|
||||
Deprecated: this field is no longer set, and will be removed in the next API version.
|
||||
type: "string"
|
||||
x-nullable: false
|
||||
example: "17.06.0-ce"
|
||||
x-omitempty: true
|
||||
Description:
|
||||
type: "string"
|
||||
x-nullable: false
|
||||
@@ -4392,6 +4368,7 @@ definitions:
|
||||
A counter that triggers an update even if no relevant parameters have
|
||||
been changed.
|
||||
type: "integer"
|
||||
format: "uint64"
|
||||
Runtime:
|
||||
description: |
|
||||
Runtime is the type of runtime specified for the task executor.
|
||||
@@ -6375,6 +6352,8 @@ definitions:
|
||||
|
||||
Kernel memory TCP limits are not supported when using cgroups v2, which
|
||||
does not support the corresponding `memory.kmem.tcp.limit_in_bytes` cgroup.
|
||||
|
||||
**Deprecated**: This field is deprecated as kernel 6.12 has deprecated kernel memory TCP accounting.
|
||||
type: "boolean"
|
||||
example: true
|
||||
CpuCfsPeriod:
|
||||
@@ -6412,29 +6391,6 @@ definitions:
|
||||
description: "Indicates IPv4 forwarding is enabled."
|
||||
type: "boolean"
|
||||
example: true
|
||||
BridgeNfIptables:
|
||||
description: |
|
||||
Indicates if `bridge-nf-call-iptables` is available on the host when
|
||||
the daemon was started.
|
||||
|
||||
<p><br /></p>
|
||||
|
||||
> **Deprecated**: netfilter module is now loaded on-demand and no longer
|
||||
> during daemon startup, making this field obsolete. This field is always
|
||||
> `false` and will be removed in a API v1.49.
|
||||
type: "boolean"
|
||||
example: false
|
||||
BridgeNfIp6tables:
|
||||
description: |
|
||||
Indicates if `bridge-nf-call-ip6tables` is available on the host.
|
||||
|
||||
<p><br /></p>
|
||||
|
||||
> **Deprecated**: netfilter module is now loaded on-demand, and no longer
|
||||
> during daemon startup, making this field obsolete. This field is always
|
||||
> `false` and will be removed in a API v1.49.
|
||||
type: "boolean"
|
||||
example: false
|
||||
Debug:
|
||||
description: |
|
||||
Indicates if the daemon is running in debug-mode / with debug-level
|
||||
|
||||
2
vendor/github.com/docker/docker/api/types/build/disk_usage.go
generated
vendored
2
vendor/github.com/docker/docker/api/types/build/disk_usage.go
generated
vendored
@@ -1,6 +1,8 @@
|
||||
package build
|
||||
|
||||
// CacheDiskUsage contains disk usage for the build cache.
|
||||
//
|
||||
// Deprecated: this type is no longer used and will be removed in the next release.
|
||||
type CacheDiskUsage struct {
|
||||
TotalSize int64
|
||||
Reclaimable int64
|
||||
|
||||
2
vendor/github.com/docker/docker/api/types/container/disk_usage.go
generated
vendored
2
vendor/github.com/docker/docker/api/types/container/disk_usage.go
generated
vendored
@@ -1,6 +1,8 @@
|
||||
package container
|
||||
|
||||
// DiskUsage contains disk usage for containers.
|
||||
//
|
||||
// Deprecated: this type is no longer used and will be removed in the next release.
|
||||
type DiskUsage struct {
|
||||
TotalSize int64
|
||||
Reclaimable int64
|
||||
|
||||
7
vendor/github.com/docker/docker/api/types/container/hostconfig.go
generated
vendored
7
vendor/github.com/docker/docker/api/types/container/hostconfig.go
generated
vendored
@@ -394,7 +394,12 @@ type Resources struct {
|
||||
|
||||
// KernelMemory specifies the kernel memory limit (in bytes) for the container.
|
||||
// Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes.
|
||||
KernelMemory int64 `json:",omitempty"`
|
||||
KernelMemory int64 `json:",omitempty"`
|
||||
// Hard limit for kernel TCP buffer memory (in bytes).
|
||||
//
|
||||
// Deprecated: This field is deprecated and will be removed in the next release.
|
||||
// Starting with 6.12, the kernel has deprecated kernel memory tcp accounting
|
||||
// for cgroups v1.
|
||||
KernelMemoryTCP int64 `json:",omitempty"` // Hard limit for kernel TCP buffer memory (in bytes)
|
||||
MemoryReservation int64 // Memory soft limit (in bytes)
|
||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap
|
||||
|
||||
53
vendor/github.com/docker/docker/api/types/container/network_settings.go
generated
vendored
53
vendor/github.com/docker/docker/api/types/container/network_settings.go
generated
vendored
@@ -13,8 +13,11 @@ type NetworkSettings struct {
|
||||
}
|
||||
|
||||
// NetworkSettingsBase holds networking state for a container when inspecting it.
|
||||
//
|
||||
// Deprecated: Most fields in NetworkSettingsBase are deprecated. Fields which aren't deprecated will move to
|
||||
// NetworkSettings in v29.0, and this struct will be removed.
|
||||
type NetworkSettingsBase struct {
|
||||
Bridge string // Bridge contains the name of the default bridge interface iff it was set through the daemon --bridge flag.
|
||||
Bridge string // Deprecated: This field is only set when the daemon is started with the --bridge flag specified.
|
||||
SandboxID string // SandboxID uniquely represents a container's network stack
|
||||
SandboxKey string // SandboxKey identifies the sandbox
|
||||
Ports nat.PortMap // Ports is a collection of PortBinding indexed by Port
|
||||
@@ -35,18 +38,44 @@ type NetworkSettingsBase struct {
|
||||
SecondaryIPv6Addresses []network.Address // Deprecated: This field is never set and will be removed in a future release.
|
||||
}
|
||||
|
||||
// DefaultNetworkSettings holds network information
|
||||
// during the 2 release deprecation period.
|
||||
// It will be removed in Docker 1.11.
|
||||
// DefaultNetworkSettings holds the networking state for the default bridge, if the container is connected to that
|
||||
// network.
|
||||
//
|
||||
// Deprecated: this struct is deprecated since Docker v1.11 and will be removed in v29. You should look for the default
|
||||
// network in NetworkSettings.Networks instead.
|
||||
type DefaultNetworkSettings struct {
|
||||
EndpointID string // EndpointID uniquely represents a service endpoint in a Sandbox
|
||||
Gateway string // Gateway holds the gateway address for the network
|
||||
GlobalIPv6Address string // GlobalIPv6Address holds network's global IPv6 address
|
||||
GlobalIPv6PrefixLen int // GlobalIPv6PrefixLen represents mask length of network's global IPv6 address
|
||||
IPAddress string // IPAddress holds the IPv4 address for the network
|
||||
IPPrefixLen int // IPPrefixLen represents mask length of network's IPv4 address
|
||||
IPv6Gateway string // IPv6Gateway holds gateway address specific for IPv6
|
||||
MacAddress string // MacAddress holds the MAC address for the network
|
||||
// EndpointID uniquely represents a service endpoint in a Sandbox
|
||||
//
|
||||
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
|
||||
EndpointID string
|
||||
// Gateway holds the gateway address for the network
|
||||
//
|
||||
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
|
||||
Gateway string
|
||||
// GlobalIPv6Address holds network's global IPv6 address
|
||||
//
|
||||
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
|
||||
GlobalIPv6Address string
|
||||
// GlobalIPv6PrefixLen represents mask length of network's global IPv6 address
|
||||
//
|
||||
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
|
||||
GlobalIPv6PrefixLen int
|
||||
// IPAddress holds the IPv4 address for the network
|
||||
//
|
||||
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
|
||||
IPAddress string
|
||||
// IPPrefixLen represents mask length of network's IPv4 address
|
||||
//
|
||||
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
|
||||
IPPrefixLen int
|
||||
// IPv6Gateway holds gateway address specific for IPv6
|
||||
//
|
||||
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
|
||||
IPv6Gateway string
|
||||
// MacAddress holds the MAC address for the network
|
||||
//
|
||||
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
|
||||
MacAddress string
|
||||
}
|
||||
|
||||
// NetworkSettingsSummary provides a summary of container's networks
|
||||
|
||||
61
vendor/github.com/docker/docker/api/types/filters/filters_deprecated.go
generated
vendored
Normal file
61
vendor/github.com/docker/docker/api/types/filters/filters_deprecated.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package filters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
)
|
||||
|
||||
// ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22
|
||||
// then the encoded format will use an older legacy format where the values are a
|
||||
// list of strings, instead of a set.
|
||||
//
|
||||
// Deprecated: do not use in any new code; use ToJSON instead
|
||||
func ToParamWithVersion(version string, a Args) (string, error) {
|
||||
out, err := ToJSON(a)
|
||||
if out == "" || err != nil {
|
||||
return "", nil
|
||||
}
|
||||
if version != "" && versions.LessThan(version, "1.22") {
|
||||
return encodeLegacyFilters(out)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// encodeLegacyFilters encodes Args in the legacy format as used in API v1.21 and older.
|
||||
// where values are a list of strings, instead of a set.
|
||||
//
|
||||
// Don't use in any new code; use [filters.ToJSON]] instead.
|
||||
func encodeLegacyFilters(currentFormat string) (string, error) {
|
||||
// The Args.fields field is not exported, but used to marshal JSON,
|
||||
// so we'll marshal to the new format, then unmarshal to get the
|
||||
// fields, and marshal again.
|
||||
//
|
||||
// This is far from optimal, but this code is only used for deprecated
|
||||
// API versions, so should not be hit commonly.
|
||||
var argsFields map[string]map[string]bool
|
||||
err := json.Unmarshal([]byte(currentFormat), &argsFields)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(convertArgsToSlice(argsFields))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func convertArgsToSlice(f map[string]map[string]bool) map[string][]string {
|
||||
m := map[string][]string{}
|
||||
for k, v := range f {
|
||||
values := []string{}
|
||||
for kk := range v {
|
||||
if v[kk] {
|
||||
values = append(values, kk)
|
||||
}
|
||||
}
|
||||
m[k] = values
|
||||
}
|
||||
return m
|
||||
}
|
||||
34
vendor/github.com/docker/docker/api/types/filters/parse.go
generated
vendored
34
vendor/github.com/docker/docker/api/types/filters/parse.go
generated
vendored
@@ -8,8 +8,6 @@ import (
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
)
|
||||
|
||||
// Args stores a mapping of keys to a set of multiple values.
|
||||
@@ -63,24 +61,6 @@ func ToJSON(a Args) (string, error) {
|
||||
return string(buf), err
|
||||
}
|
||||
|
||||
// ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22
|
||||
// then the encoded format will use an older legacy format where the values are a
|
||||
// list of strings, instead of a set.
|
||||
//
|
||||
// Deprecated: do not use in any new code; use ToJSON instead
|
||||
func ToParamWithVersion(version string, a Args) (string, error) {
|
||||
if a.Len() == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if version != "" && versions.LessThan(version, "1.22") {
|
||||
buf, err := json.Marshal(convertArgsToSlice(a.fields))
|
||||
return string(buf), err
|
||||
}
|
||||
|
||||
return ToJSON(a)
|
||||
}
|
||||
|
||||
// FromJSON decodes a JSON encoded string into Args
|
||||
func FromJSON(p string) (Args, error) {
|
||||
args := NewArgs()
|
||||
@@ -320,17 +300,3 @@ func deprecatedArgs(d map[string][]string) map[string]map[string]bool {
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func convertArgsToSlice(f map[string]map[string]bool) map[string][]string {
|
||||
m := map[string][]string{}
|
||||
for k, v := range f {
|
||||
values := []string{}
|
||||
for kk := range v {
|
||||
if v[kk] {
|
||||
values = append(values, kk)
|
||||
}
|
||||
}
|
||||
m[k] = values
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
2
vendor/github.com/docker/docker/api/types/image/disk_usage.go
generated
vendored
2
vendor/github.com/docker/docker/api/types/image/disk_usage.go
generated
vendored
@@ -1,6 +1,8 @@
|
||||
package image
|
||||
|
||||
// DiskUsage contains disk usage for images.
|
||||
//
|
||||
// Deprecated: this type is no longer used and will be removed in the next release.
|
||||
type DiskUsage struct {
|
||||
TotalSize int64
|
||||
Reclaimable int64
|
||||
|
||||
4
vendor/github.com/docker/docker/api/types/image/image_inspect.go
generated
vendored
4
vendor/github.com/docker/docker/api/types/image/image_inspect.go
generated
vendored
@@ -48,6 +48,8 @@ type InspectResponse struct {
|
||||
// Depending on how the image was created, this field may be empty and
|
||||
// is only set for images that were built/created locally. This field
|
||||
// is empty if the image was pulled from an image registry.
|
||||
//
|
||||
// Deprecated: this field is deprecated, and will be removed in the next release.
|
||||
Parent string
|
||||
|
||||
// Comment is an optional message that can be set when committing or
|
||||
@@ -80,6 +82,8 @@ type InspectResponse struct {
|
||||
// DockerVersion is the version of Docker that was used to build the image.
|
||||
//
|
||||
// Depending on how the image was created, this field may be empty.
|
||||
//
|
||||
// Deprecated: this field is deprecated, and will be removed in the next release.
|
||||
DockerVersion string
|
||||
|
||||
// Author is the name of the author that was specified when committing the
|
||||
|
||||
6
vendor/github.com/docker/docker/api/types/network/endpoint.go
generated
vendored
6
vendor/github.com/docker/docker/api/types/network/endpoint.go
generated
vendored
@@ -4,8 +4,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/docker/docker/internal/multierror"
|
||||
)
|
||||
|
||||
// EndpointSettings stores the network endpoint details
|
||||
@@ -99,7 +97,7 @@ func (cfg *EndpointIPAMConfig) IsInRange(v4Subnets []NetworkSubnet, v6Subnets []
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
return multierror.Join(errs...)
|
||||
return errJoin(errs...)
|
||||
}
|
||||
|
||||
func validateEndpointIPAddress(epAddr string, ipamSubnets []NetworkSubnet) error {
|
||||
@@ -149,5 +147,5 @@ func (cfg *EndpointIPAMConfig) Validate() error {
|
||||
}
|
||||
}
|
||||
|
||||
return multierror.Join(errs...)
|
||||
return errJoin(errs...)
|
||||
}
|
||||
|
||||
45
vendor/github.com/docker/docker/api/types/network/ipam.go
generated
vendored
45
vendor/github.com/docker/docker/api/types/network/ipam.go
generated
vendored
@@ -4,8 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
|
||||
"github.com/docker/docker/internal/multierror"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IPAM represents IP Address Management
|
||||
@@ -72,7 +71,7 @@ func ValidateIPAM(ipam *IPAM, enableIPv6 bool) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := multierror.Join(errs...); err != nil {
|
||||
if err := errJoin(errs...); err != nil {
|
||||
return fmt.Errorf("invalid network config:\n%w", err)
|
||||
}
|
||||
|
||||
@@ -132,3 +131,43 @@ func validateAddress(address string, subnet netip.Prefix, subnetFamily ipFamily)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func errJoin(errs ...error) error {
|
||||
n := 0
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
n++
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
e := &joinError{
|
||||
errs: make([]error, 0, n),
|
||||
}
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
e.errs = append(e.errs, err)
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
type joinError struct {
|
||||
errs []error
|
||||
}
|
||||
|
||||
func (e *joinError) Error() string {
|
||||
if len(e.errs) == 1 {
|
||||
return strings.TrimSpace(e.errs[0].Error())
|
||||
}
|
||||
stringErrs := make([]string, 0, len(e.errs))
|
||||
for _, subErr := range e.errs {
|
||||
stringErrs = append(stringErrs, strings.ReplaceAll(subErr.Error(), "\n", "\n\t"))
|
||||
}
|
||||
return "* " + strings.Join(stringErrs, "\n* ")
|
||||
}
|
||||
|
||||
func (e *joinError) Unwrap() []error {
|
||||
return e.errs
|
||||
}
|
||||
|
||||
6
vendor/github.com/docker/docker/api/types/plugin.go
generated
vendored
6
vendor/github.com/docker/docker/api/types/plugin.go
generated
vendored
@@ -42,7 +42,11 @@ type PluginConfig struct {
|
||||
// Required: true
|
||||
Description string `json:"Description"`
|
||||
|
||||
// Docker Version used to create the plugin
|
||||
// Docker Version used to create the plugin.
|
||||
//
|
||||
// Depending on how the plugin was created, this field may be empty or omitted.
|
||||
//
|
||||
// Deprecated: this field is no longer set, and will be removed in the next API version.
|
||||
DockerVersion string `json:"DockerVersion,omitempty"`
|
||||
|
||||
// documentation
|
||||
|
||||
4
vendor/github.com/docker/docker/api/types/registry/authconfig.go
generated
vendored
4
vendor/github.com/docker/docker/api/types/registry/authconfig.go
generated
vendored
@@ -32,8 +32,8 @@ type AuthConfig struct {
|
||||
Auth string `json:"auth,omitempty"`
|
||||
|
||||
// Email is an optional value associated with the username.
|
||||
// This field is deprecated and will be removed in a later
|
||||
// version of docker.
|
||||
//
|
||||
// Deprecated: This field is deprecated since docker 1.11 (API v1.23) and will be removed in the next release.
|
||||
Email string `json:"email,omitempty"`
|
||||
|
||||
ServerAddress string `json:"serveraddress,omitempty"`
|
||||
|
||||
10
vendor/github.com/docker/docker/api/types/swarm/runtime.go
generated
vendored
10
vendor/github.com/docker/docker/api/types/swarm/runtime.go
generated
vendored
@@ -1,5 +1,7 @@
|
||||
package swarm
|
||||
|
||||
import "github.com/docker/docker/api/types/swarm/runtime"
|
||||
|
||||
// RuntimeType is the type of runtime used for the TaskSpec
|
||||
type RuntimeType string
|
||||
|
||||
@@ -25,3 +27,11 @@ const (
|
||||
type NetworkAttachmentSpec struct {
|
||||
ContainerID string
|
||||
}
|
||||
|
||||
// RuntimeSpec defines the base payload which clients can specify for creating
|
||||
// a service with the plugin runtime.
|
||||
type RuntimeSpec = runtime.PluginSpec
|
||||
|
||||
// RuntimePrivilege describes a permission the user has to accept
|
||||
// upon installing a plugin.
|
||||
type RuntimePrivilege = runtime.PluginPrivilege
|
||||
|
||||
3
vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go
generated
vendored
3
vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go
generated
vendored
@@ -1,3 +0,0 @@
|
||||
//go:generate protoc --gogofaster_out=import_path=github.com/docker/docker/api/types/swarm/runtime:. plugin.proto
|
||||
|
||||
package runtime
|
||||
808
vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go
generated
vendored
808
vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go
generated
vendored
@@ -1,808 +0,0 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: plugin.proto
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// PluginSpec defines the base payload which clients can specify for creating
|
||||
// a service with the plugin runtime.
|
||||
type PluginSpec struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Remote string `protobuf:"bytes,2,opt,name=remote,proto3" json:"remote,omitempty"`
|
||||
Privileges []*PluginPrivilege `protobuf:"bytes,3,rep,name=privileges,proto3" json:"privileges,omitempty"`
|
||||
Disabled bool `protobuf:"varint,4,opt,name=disabled,proto3" json:"disabled,omitempty"`
|
||||
Env []string `protobuf:"bytes,5,rep,name=env,proto3" json:"env,omitempty"`
|
||||
}
|
||||
|
||||
func (m *PluginSpec) Reset() { *m = PluginSpec{} }
|
||||
func (m *PluginSpec) String() string { return proto.CompactTextString(m) }
|
||||
func (*PluginSpec) ProtoMessage() {}
|
||||
func (*PluginSpec) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_22a625af4bc1cc87, []int{0}
|
||||
}
|
||||
func (m *PluginSpec) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *PluginSpec) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_PluginSpec.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *PluginSpec) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PluginSpec.Merge(m, src)
|
||||
}
|
||||
func (m *PluginSpec) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *PluginSpec) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PluginSpec.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PluginSpec proto.InternalMessageInfo
|
||||
|
||||
func (m *PluginSpec) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PluginSpec) GetRemote() string {
|
||||
if m != nil {
|
||||
return m.Remote
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PluginSpec) GetPrivileges() []*PluginPrivilege {
|
||||
if m != nil {
|
||||
return m.Privileges
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PluginSpec) GetDisabled() bool {
|
||||
if m != nil {
|
||||
return m.Disabled
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *PluginSpec) GetEnv() []string {
|
||||
if m != nil {
|
||||
return m.Env
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PluginPrivilege describes a permission the user has to accept
|
||||
// upon installing a plugin.
|
||||
type PluginPrivilege struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
|
||||
Value []string `protobuf:"bytes,3,rep,name=value,proto3" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (m *PluginPrivilege) Reset() { *m = PluginPrivilege{} }
|
||||
func (m *PluginPrivilege) String() string { return proto.CompactTextString(m) }
|
||||
func (*PluginPrivilege) ProtoMessage() {}
|
||||
func (*PluginPrivilege) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_22a625af4bc1cc87, []int{1}
|
||||
}
|
||||
func (m *PluginPrivilege) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *PluginPrivilege) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_PluginPrivilege.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *PluginPrivilege) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PluginPrivilege.Merge(m, src)
|
||||
}
|
||||
func (m *PluginPrivilege) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *PluginPrivilege) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PluginPrivilege.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PluginPrivilege proto.InternalMessageInfo
|
||||
|
||||
func (m *PluginPrivilege) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PluginPrivilege) GetDescription() string {
|
||||
if m != nil {
|
||||
return m.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PluginPrivilege) GetValue() []string {
|
||||
if m != nil {
|
||||
return m.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*PluginSpec)(nil), "PluginSpec")
|
||||
proto.RegisterType((*PluginPrivilege)(nil), "PluginPrivilege")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("plugin.proto", fileDescriptor_22a625af4bc1cc87) }
|
||||
|
||||
var fileDescriptor_22a625af4bc1cc87 = []byte{
|
||||
// 225 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0xc8, 0x29, 0x4d,
|
||||
0xcf, 0xcc, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x9a, 0xc1, 0xc8, 0xc5, 0x15, 0x00, 0x16,
|
||||
0x08, 0x2e, 0x48, 0x4d, 0x16, 0x12, 0xe2, 0x62, 0xc9, 0x4b, 0xcc, 0x4d, 0x95, 0x60, 0x54, 0x60,
|
||||
0xd4, 0xe0, 0x0c, 0x02, 0xb3, 0x85, 0xc4, 0xb8, 0xd8, 0x8a, 0x52, 0x73, 0xf3, 0x4b, 0x52, 0x25,
|
||||
0x98, 0xc0, 0xa2, 0x50, 0x9e, 0x90, 0x01, 0x17, 0x57, 0x41, 0x51, 0x66, 0x59, 0x66, 0x4e, 0x6a,
|
||||
0x7a, 0x6a, 0xb1, 0x04, 0xb3, 0x02, 0xb3, 0x06, 0xb7, 0x91, 0x80, 0x1e, 0xc4, 0xb0, 0x00, 0x98,
|
||||
0x44, 0x10, 0x92, 0x1a, 0x21, 0x29, 0x2e, 0x8e, 0x94, 0xcc, 0xe2, 0xc4, 0xa4, 0x9c, 0xd4, 0x14,
|
||||
0x09, 0x16, 0x05, 0x46, 0x0d, 0x8e, 0x20, 0x38, 0x5f, 0x48, 0x80, 0x8b, 0x39, 0x35, 0xaf, 0x4c,
|
||||
0x82, 0x55, 0x81, 0x59, 0x83, 0x33, 0x08, 0xc4, 0x54, 0x8a, 0xe5, 0xe2, 0x47, 0x33, 0x0c, 0xab,
|
||||
0xf3, 0x14, 0xb8, 0xb8, 0x53, 0x52, 0x8b, 0x93, 0x8b, 0x32, 0x0b, 0x4a, 0x32, 0xf3, 0xf3, 0xa0,
|
||||
0x6e, 0x44, 0x16, 0x12, 0x12, 0xe1, 0x62, 0x2d, 0x4b, 0xcc, 0x29, 0x4d, 0x05, 0xbb, 0x91, 0x33,
|
||||
0x08, 0xc2, 0x71, 0x92, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4,
|
||||
0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x24, 0x36,
|
||||
0x70, 0xd0, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x37, 0xea, 0xe2, 0xca, 0x2a, 0x01, 0x00,
|
||||
0x00,
|
||||
}
|
||||
|
||||
func (m *PluginSpec) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *PluginSpec) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *PluginSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Env) > 0 {
|
||||
for iNdEx := len(m.Env) - 1; iNdEx >= 0; iNdEx-- {
|
||||
i -= len(m.Env[iNdEx])
|
||||
copy(dAtA[i:], m.Env[iNdEx])
|
||||
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Env[iNdEx])))
|
||||
i--
|
||||
dAtA[i] = 0x2a
|
||||
}
|
||||
}
|
||||
if m.Disabled {
|
||||
i--
|
||||
if m.Disabled {
|
||||
dAtA[i] = 1
|
||||
} else {
|
||||
dAtA[i] = 0
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x20
|
||||
}
|
||||
if len(m.Privileges) > 0 {
|
||||
for iNdEx := len(m.Privileges) - 1; iNdEx >= 0; iNdEx-- {
|
||||
{
|
||||
size, err := m.Privileges[iNdEx].MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintPlugin(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x1a
|
||||
}
|
||||
}
|
||||
if len(m.Remote) > 0 {
|
||||
i -= len(m.Remote)
|
||||
copy(dAtA[i:], m.Remote)
|
||||
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Remote)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if len(m.Name) > 0 {
|
||||
i -= len(m.Name)
|
||||
copy(dAtA[i:], m.Name)
|
||||
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *PluginPrivilege) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *PluginPrivilege) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *PluginPrivilege) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Value) > 0 {
|
||||
for iNdEx := len(m.Value) - 1; iNdEx >= 0; iNdEx-- {
|
||||
i -= len(m.Value[iNdEx])
|
||||
copy(dAtA[i:], m.Value[iNdEx])
|
||||
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Value[iNdEx])))
|
||||
i--
|
||||
dAtA[i] = 0x1a
|
||||
}
|
||||
}
|
||||
if len(m.Description) > 0 {
|
||||
i -= len(m.Description)
|
||||
copy(dAtA[i:], m.Description)
|
||||
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Description)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if len(m.Name) > 0 {
|
||||
i -= len(m.Name)
|
||||
copy(dAtA[i:], m.Name)
|
||||
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintPlugin(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovPlugin(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *PluginSpec) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Name)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovPlugin(uint64(l))
|
||||
}
|
||||
l = len(m.Remote)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovPlugin(uint64(l))
|
||||
}
|
||||
if len(m.Privileges) > 0 {
|
||||
for _, e := range m.Privileges {
|
||||
l = e.Size()
|
||||
n += 1 + l + sovPlugin(uint64(l))
|
||||
}
|
||||
}
|
||||
if m.Disabled {
|
||||
n += 2
|
||||
}
|
||||
if len(m.Env) > 0 {
|
||||
for _, s := range m.Env {
|
||||
l = len(s)
|
||||
n += 1 + l + sovPlugin(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *PluginPrivilege) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Name)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovPlugin(uint64(l))
|
||||
}
|
||||
l = len(m.Description)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovPlugin(uint64(l))
|
||||
}
|
||||
if len(m.Value) > 0 {
|
||||
for _, s := range m.Value {
|
||||
l = len(s)
|
||||
n += 1 + l + sovPlugin(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovPlugin(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozPlugin(x uint64) (n int) {
|
||||
return sovPlugin(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *PluginSpec) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: PluginSpec: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: PluginSpec: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Name = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Remote", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Remote = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Privileges", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Privileges = append(m.Privileges, &PluginPrivilege{})
|
||||
if err := m.Privileges[len(m.Privileges)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Disabled", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
v |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.Disabled = bool(v != 0)
|
||||
case 5:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Env", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Env = append(m.Env, string(dAtA[iNdEx:postIndex]))
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipPlugin(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *PluginPrivilege) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: PluginPrivilege: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: PluginPrivilege: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Name = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Description = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Value = append(m.Value, string(dAtA[iNdEx:postIndex]))
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipPlugin(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipPlugin(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthPlugin
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupPlugin
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthPlugin
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthPlugin = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowPlugin = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupPlugin = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
19
vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto
generated
vendored
19
vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto
generated
vendored
@@ -1,19 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
// PluginSpec defines the base payload which clients can specify for creating
|
||||
// a service with the plugin runtime.
|
||||
message PluginSpec {
|
||||
string name = 1;
|
||||
string remote = 2;
|
||||
repeated PluginPrivilege privileges = 3;
|
||||
bool disabled = 4;
|
||||
repeated string env = 5;
|
||||
}
|
||||
|
||||
// PluginPrivilege describes a permission the user has to accept
|
||||
// upon installing a plugin.
|
||||
message PluginPrivilege {
|
||||
string name = 1;
|
||||
string description = 2;
|
||||
repeated string value = 3;
|
||||
}
|
||||
27
vendor/github.com/docker/docker/api/types/swarm/runtime/runtime.go
generated
vendored
Normal file
27
vendor/github.com/docker/docker/api/types/swarm/runtime/runtime.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package runtime
|
||||
|
||||
import "fmt"
|
||||
|
||||
// PluginSpec defines the base payload which clients can specify for creating
|
||||
// a service with the plugin runtime.
|
||||
type PluginSpec struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Remote string `json:"remote,omitempty"`
|
||||
Privileges []*PluginPrivilege `json:"privileges,omitempty"`
|
||||
Disabled bool `json:"disabled,omitempty"`
|
||||
Env []string `json:"env,omitempty"`
|
||||
}
|
||||
|
||||
// PluginPrivilege describes a permission the user has to accept
|
||||
// upon installing a plugin.
|
||||
type PluginPrivilege struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Value []string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthPlugin = fmt.Errorf("proto: negative length found during unmarshaling") // Deprecated: this error was only used internally and is no longer used.
|
||||
ErrIntOverflowPlugin = fmt.Errorf("proto: integer overflow") // Deprecated: this error was only used internally and is no longer used.
|
||||
ErrUnexpectedEndOfGroupPlugin = fmt.Errorf("proto: unexpected end of group") // Deprecated: this error was only used internally and is no longer used.
|
||||
)
|
||||
3
vendor/github.com/docker/docker/api/types/swarm/task.go
generated
vendored
3
vendor/github.com/docker/docker/api/types/swarm/task.go
generated
vendored
@@ -4,7 +4,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/swarm/runtime"
|
||||
)
|
||||
|
||||
// TaskState represents the state of a task.
|
||||
@@ -77,7 +76,7 @@ type TaskSpec struct {
|
||||
// NetworkAttachmentSpec is used if the `Runtime` field is set to
|
||||
// `attachment`.
|
||||
ContainerSpec *ContainerSpec `json:",omitempty"`
|
||||
PluginSpec *runtime.PluginSpec `json:",omitempty"`
|
||||
PluginSpec *RuntimeSpec `json:",omitempty"`
|
||||
NetworkAttachmentSpec *NetworkAttachmentSpec `json:",omitempty"`
|
||||
|
||||
Resources *ResourceRequirements `json:",omitempty"`
|
||||
|
||||
17
vendor/github.com/docker/docker/api/types/system/disk_usage.go
generated
vendored
17
vendor/github.com/docker/docker/api/types/system/disk_usage.go
generated
vendored
@@ -1,17 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/build"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
)
|
||||
|
||||
// DiskUsage contains response of Engine API for API 1.49 and greater:
|
||||
// GET "/system/df"
|
||||
type DiskUsage struct {
|
||||
Images *image.DiskUsage
|
||||
Containers *container.DiskUsage
|
||||
Volumes *volume.DiskUsage
|
||||
BuildCache *build.CacheDiskUsage
|
||||
}
|
||||
30
vendor/github.com/docker/docker/api/types/system/info.go
generated
vendored
30
vendor/github.com/docker/docker/api/types/system/info.go
generated
vendored
@@ -9,19 +9,23 @@ import (
|
||||
// Info contains response of Engine API:
|
||||
// GET "/info"
|
||||
type Info struct {
|
||||
ID string
|
||||
Containers int
|
||||
ContainersRunning int
|
||||
ContainersPaused int
|
||||
ContainersStopped int
|
||||
Images int
|
||||
Driver string
|
||||
DriverStatus [][2]string
|
||||
SystemStatus [][2]string `json:",omitempty"` // SystemStatus is only propagated by the Swarm standalone API
|
||||
Plugins PluginsInfo
|
||||
MemoryLimit bool
|
||||
SwapLimit bool
|
||||
KernelMemory bool `json:",omitempty"` // Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes
|
||||
ID string
|
||||
Containers int
|
||||
ContainersRunning int
|
||||
ContainersPaused int
|
||||
ContainersStopped int
|
||||
Images int
|
||||
Driver string
|
||||
DriverStatus [][2]string
|
||||
SystemStatus [][2]string `json:",omitempty"` // SystemStatus is only propagated by the Swarm standalone API
|
||||
Plugins PluginsInfo
|
||||
MemoryLimit bool
|
||||
SwapLimit bool
|
||||
KernelMemory bool `json:",omitempty"` // Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes
|
||||
// KernelMemoryLimit is not supported on cgroups v2.
|
||||
//
|
||||
// Deprecated: This field is deprecated and will be removed in the next release.
|
||||
// Starting with kernel 6.12, the kernel has deprecated kernel memory tcp accounting
|
||||
KernelMemoryTCP bool `json:",omitempty"` // KernelMemoryTCP is not supported on cgroups v2.
|
||||
CPUCfsPeriod bool `json:"CpuCfsPeriod"`
|
||||
CPUCfsQuota bool `json:"CpuCfsQuota"`
|
||||
|
||||
7
vendor/github.com/docker/docker/api/types/types_deprecated.go
generated
vendored
7
vendor/github.com/docker/docker/api/types/types_deprecated.go
generated
vendored
@@ -46,15 +46,16 @@ type NetworkSettings = container.NetworkSettings
|
||||
|
||||
// NetworkSettingsBase holds networking state for a container when inspecting it.
|
||||
//
|
||||
// Deprecated: use [container.NetworkSettingsBase].
|
||||
type NetworkSettingsBase = container.NetworkSettingsBase
|
||||
// Deprecated: [container.NetworkSettingsBase] will be removed in v29. Prefer
|
||||
// accessing the fields it contains through [container.NetworkSettings].
|
||||
type NetworkSettingsBase = container.NetworkSettingsBase //nolint:staticcheck // ignore SA1019: NetworkSettingsBase is deprecated in v28.4.
|
||||
|
||||
// DefaultNetworkSettings holds network information
|
||||
// during the 2 release deprecation period.
|
||||
// It will be removed in Docker 1.11.
|
||||
//
|
||||
// Deprecated: use [container.DefaultNetworkSettings].
|
||||
type DefaultNetworkSettings = container.DefaultNetworkSettings
|
||||
type DefaultNetworkSettings = container.DefaultNetworkSettings //nolint:staticcheck // ignore SA1019: DefaultNetworkSettings is deprecated in v28.4.
|
||||
|
||||
// SummaryNetworkSettings provides a summary of container's networks
|
||||
// in /containers/json.
|
||||
|
||||
2
vendor/github.com/docker/docker/api/types/volume/disk_usage.go
generated
vendored
2
vendor/github.com/docker/docker/api/types/volume/disk_usage.go
generated
vendored
@@ -1,6 +1,8 @@
|
||||
package volume
|
||||
|
||||
// DiskUsage contains disk usage for volumes.
|
||||
//
|
||||
// Deprecated: this type is no longer used and will be removed in the next release.
|
||||
type DiskUsage struct {
|
||||
TotalSize int64
|
||||
Reclaimable int64
|
||||
|
||||
4
vendor/github.com/docker/docker/client/client.go
generated
vendored
4
vendor/github.com/docker/docker/client/client.go
generated
vendored
@@ -463,7 +463,9 @@ func (cli *Client) dialer() func(context.Context) (net.Conn, error) {
|
||||
case "unix":
|
||||
return net.Dial(cli.proto, cli.addr)
|
||||
case "npipe":
|
||||
return sockets.DialPipe(cli.addr, 32*time.Second)
|
||||
ctx, cancel := context.WithTimeout(ctx, 32*time.Second)
|
||||
defer cancel()
|
||||
return dialPipeContext(ctx, cli.addr)
|
||||
default:
|
||||
if tlsConfig := cli.tlsConfig(); tlsConfig != nil {
|
||||
return tls.Dial(cli.proto, cli.addr, tlsConfig)
|
||||
|
||||
11
vendor/github.com/docker/docker/client/client_unix.go
generated
vendored
11
vendor/github.com/docker/docker/client/client_unix.go
generated
vendored
@@ -2,6 +2,17 @@
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
|
||||
// (EnvOverrideHost) environment variable is unset or empty.
|
||||
const DefaultDockerHost = "unix:///var/run/docker.sock"
|
||||
|
||||
// dialPipeContext connects to a Windows named pipe. It is not supported on non-Windows.
|
||||
func dialPipeContext(_ context.Context, _ string) (net.Conn, error) {
|
||||
return nil, syscall.EAFNOSUPPORT
|
||||
}
|
||||
|
||||
12
vendor/github.com/docker/docker/client/client_windows.go
generated
vendored
12
vendor/github.com/docker/docker/client/client_windows.go
generated
vendored
@@ -1,5 +1,17 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/Microsoft/go-winio"
|
||||
)
|
||||
|
||||
// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
|
||||
// (EnvOverrideHost) environment variable is unset or empty.
|
||||
const DefaultDockerHost = "npipe:////./pipe/docker_engine"
|
||||
|
||||
// dialPipeContext connects to a Windows named pipe. It is not supported on non-Windows.
|
||||
func dialPipeContext(ctx context.Context, addr string) (net.Conn, error) {
|
||||
return winio.DialPipeContext(ctx, addr)
|
||||
}
|
||||
|
||||
4
vendor/github.com/docker/docker/client/container_stats.go
generated
vendored
4
vendor/github.com/docker/docker/client/container_stats.go
generated
vendored
@@ -28,7 +28,7 @@ func (cli *Client) ContainerStats(ctx context.Context, containerID string, strea
|
||||
|
||||
return container.StatsResponseReader{
|
||||
Body: resp.Body,
|
||||
OSType: getDockerOS(resp.Header.Get("Server")),
|
||||
OSType: resp.Header.Get("Ostype"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -51,6 +51,6 @@ func (cli *Client) ContainerStatsOneShot(ctx context.Context, containerID string
|
||||
|
||||
return container.StatsResponseReader{
|
||||
Body: resp.Body,
|
||||
OSType: getDockerOS(resp.Header.Get("Server")),
|
||||
OSType: resp.Header.Get("Ostype"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
2
vendor/github.com/docker/docker/client/image_build.go
generated
vendored
2
vendor/github.com/docker/docker/client/image_build.go
generated
vendored
@@ -40,7 +40,7 @@ func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, optio
|
||||
|
||||
return build.ImageBuildResponse{
|
||||
Body: resp.Body,
|
||||
OSType: getDockerOS(resp.Header.Get("Server")),
|
||||
OSType: resp.Header.Get("Ostype"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
13
vendor/github.com/docker/docker/client/utils.go
generated
vendored
13
vendor/github.com/docker/docker/client/utils.go
generated
vendored
@@ -8,12 +8,9 @@ import (
|
||||
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/internal/lazyregexp"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
var headerRegexp = lazyregexp.New(`\ADocker/.+\s\((.+)\)\z`)
|
||||
|
||||
type emptyIDError string
|
||||
|
||||
func (e emptyIDError) InvalidParameter() {}
|
||||
@@ -31,16 +28,6 @@ func trimID(objType, id string) (string, error) {
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// getDockerOS returns the operating system based on the server header from the daemon.
|
||||
func getDockerOS(serverHeader string) string {
|
||||
var osType string
|
||||
matches := headerRegexp.FindStringSubmatch(serverHeader)
|
||||
if len(matches) > 0 {
|
||||
osType = matches[1]
|
||||
}
|
||||
return osType
|
||||
}
|
||||
|
||||
// getFiltersQuery returns a url query with "filters" query term, based on the
|
||||
// filters provided.
|
||||
func getFiltersQuery(f filters.Args) (url.Values, error) {
|
||||
|
||||
90
vendor/github.com/docker/docker/internal/lazyregexp/lazyregexp.go
generated
vendored
90
vendor/github.com/docker/docker/internal/lazyregexp/lazyregexp.go
generated
vendored
@@ -1,90 +0,0 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code below was largely copied from golang.org/x/mod@v0.22;
|
||||
// https://github.com/golang/mod/blob/v0.22.0/internal/lazyregexp/lazyre.go
|
||||
// with some additional methods added.
|
||||
|
||||
// Package lazyregexp is a thin wrapper over regexp, allowing the use of global
|
||||
// regexp variables without forcing them to be compiled at init.
|
||||
package lazyregexp
|
||||
|
||||
import (
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Regexp is a wrapper around [regexp.Regexp], where the underlying regexp will be
|
||||
// compiled the first time it is needed.
|
||||
type Regexp struct {
|
||||
str string
|
||||
once sync.Once
|
||||
rx *regexp.Regexp
|
||||
}
|
||||
|
||||
func (r *Regexp) re() *regexp.Regexp {
|
||||
r.once.Do(r.build)
|
||||
return r.rx
|
||||
}
|
||||
|
||||
func (r *Regexp) build() {
|
||||
r.rx = regexp.MustCompile(r.str)
|
||||
r.str = ""
|
||||
}
|
||||
|
||||
func (r *Regexp) FindSubmatch(s []byte) [][]byte {
|
||||
return r.re().FindSubmatch(s)
|
||||
}
|
||||
|
||||
func (r *Regexp) FindAllStringSubmatch(s string, n int) [][]string {
|
||||
return r.re().FindAllStringSubmatch(s, n)
|
||||
}
|
||||
|
||||
func (r *Regexp) FindStringSubmatch(s string) []string {
|
||||
return r.re().FindStringSubmatch(s)
|
||||
}
|
||||
|
||||
func (r *Regexp) FindStringSubmatchIndex(s string) []int {
|
||||
return r.re().FindStringSubmatchIndex(s)
|
||||
}
|
||||
|
||||
func (r *Regexp) ReplaceAllString(src, repl string) string {
|
||||
return r.re().ReplaceAllString(src, repl)
|
||||
}
|
||||
|
||||
func (r *Regexp) FindString(s string) string {
|
||||
return r.re().FindString(s)
|
||||
}
|
||||
|
||||
func (r *Regexp) FindAllString(s string, n int) []string {
|
||||
return r.re().FindAllString(s, n)
|
||||
}
|
||||
|
||||
func (r *Regexp) MatchString(s string) bool {
|
||||
return r.re().MatchString(s)
|
||||
}
|
||||
|
||||
func (r *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
|
||||
return r.re().ReplaceAllStringFunc(src, repl)
|
||||
}
|
||||
|
||||
func (r *Regexp) SubexpNames() []string {
|
||||
return r.re().SubexpNames()
|
||||
}
|
||||
|
||||
var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test")
|
||||
|
||||
// New creates a new lazy regexp, delaying the compiling work until it is first
|
||||
// needed. If the code is being run as part of tests, the regexp compiling will
|
||||
// happen immediately.
|
||||
func New(str string) *Regexp {
|
||||
lr := &Regexp{str: str}
|
||||
if inTest {
|
||||
// In tests, always compile the regexps early.
|
||||
lr.re()
|
||||
}
|
||||
return lr
|
||||
}
|
||||
46
vendor/github.com/docker/docker/internal/multierror/multierror.go
generated
vendored
46
vendor/github.com/docker/docker/internal/multierror/multierror.go
generated
vendored
@@ -1,46 +0,0 @@
|
||||
package multierror
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Join is a drop-in replacement for errors.Join with better formatting.
|
||||
func Join(errs ...error) error {
|
||||
n := 0
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
n++
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
e := &joinError{
|
||||
errs: make([]error, 0, n),
|
||||
}
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
e.errs = append(e.errs, err)
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
type joinError struct {
|
||||
errs []error
|
||||
}
|
||||
|
||||
func (e *joinError) Error() string {
|
||||
if len(e.errs) == 1 {
|
||||
return strings.TrimSpace(e.errs[0].Error())
|
||||
}
|
||||
stringErrs := make([]string, 0, len(e.errs))
|
||||
for _, subErr := range e.errs {
|
||||
stringErrs = append(stringErrs, strings.ReplaceAll(subErr.Error(), "\n", "\n\t"))
|
||||
}
|
||||
return "* " + strings.Join(stringErrs, "\n* ")
|
||||
}
|
||||
|
||||
func (e *joinError) Unwrap() []error {
|
||||
return e.errs
|
||||
}
|
||||
6
vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go
generated
vendored
6
vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go
generated
vendored
@@ -151,9 +151,9 @@ type JSONMessage struct {
|
||||
// Deprecated: this field is deprecated since docker v0.7.1 / API v1.8. Use the information in [Progress] instead. This field will be omitted in a future release.
|
||||
ProgressMessage string `json:"progress,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
From string `json:"from,omitempty"`
|
||||
Time int64 `json:"time,omitempty"`
|
||||
TimeNano int64 `json:"timeNano,omitempty"`
|
||||
From string `json:"from,omitempty"` // Deprecated: this field is no longer set in stream responses and should not be used.
|
||||
Time int64 `json:"time,omitempty"` // Deprecated: this field is no longer set in stream responses and should not be used.
|
||||
TimeNano int64 `json:"timeNano,omitempty"` // Deprecated: this field is no longer set in stream responses and should not be used.
|
||||
Error *JSONError `json:"errorDetail,omitempty"`
|
||||
|
||||
// ErrorMessage contains errors encountered during the operation.
|
||||
|
||||
17
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options/options.go
generated
vendored
17
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options/options.go
generated
vendored
@@ -46,10 +46,27 @@ type Options struct {
|
||||
WatchRoot string `mapstructure:"watch_root"` // base directory for the watch. events will be considered relative to this path
|
||||
WatchNotificationBrokers string `mapstructure:"watch_notification_brokers"`
|
||||
|
||||
NatsWatcher NatsWatcherConfig `mapstructure:"natswatcher"`
|
||||
|
||||
// InotifyWatcher specific options
|
||||
InotifyStatsFrequency time.Duration `mapstructure:"inotify_stats_frequency"`
|
||||
}
|
||||
|
||||
// NatsWatcherConfig is the configuration needed for a NATS watcher event stream.
|
||||
type NatsWatcherConfig struct {
|
||||
Endpoint string `mapstructure:"address"`
|
||||
Cluster string `mapstructure:"clusterID"`
|
||||
Stream string `mapstructure:"stream"`
|
||||
Durable string `mapstructure:"durable-name"`
|
||||
TLSInsecure bool `mapstructure:"tls-insecure"`
|
||||
TLSRootCACertificate string `mapstructure:"tls-root-ca-cert"`
|
||||
EnableTLS bool `mapstructure:"enable-tls"`
|
||||
AuthUsername string `mapstructure:"username"`
|
||||
AuthPassword string `mapstructure:"password"`
|
||||
MaxAckPending int `mapstructure:"max-ack-pending"`
|
||||
AckWait time.Duration `mapstructure:"ack-wait"`
|
||||
}
|
||||
|
||||
// New returns a new Options instance for the given configuration
|
||||
func New(m map[string]interface{}) (*Options, error) {
|
||||
// default to hybrid metadatabackend for posixfs
|
||||
|
||||
5
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/trashbin/trashbin.go
generated
vendored
5
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/trashbin/trashbin.go
generated
vendored
@@ -21,6 +21,7 @@ package trashbin
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -589,6 +590,10 @@ func (tb *Trashbin) IsEmpty(ctx context.Context, spaceID string) bool {
|
||||
}
|
||||
dirItems, err := trash.ReadDir(1)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
// empty trash
|
||||
return true
|
||||
}
|
||||
// if we cannot read the trash, we assume there are no trashed items
|
||||
tb.log.Error().Err(err).Str("spaceID", spaceID).Msg("trashbin: error reading trash directory")
|
||||
return true
|
||||
|
||||
81
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go
generated
vendored
81
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go
generated
vendored
@@ -39,6 +39,7 @@ import (
|
||||
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata/prefixes"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node"
|
||||
@@ -54,16 +55,6 @@ type ScanDebouncer struct {
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
type EventAction int
|
||||
|
||||
const (
|
||||
ActionCreate EventAction = iota
|
||||
ActionUpdate
|
||||
ActionMove
|
||||
ActionDelete
|
||||
ActionMoveFrom
|
||||
)
|
||||
|
||||
type queueItem struct {
|
||||
item scanItem
|
||||
timer *time.Timer
|
||||
@@ -190,10 +181,10 @@ func (t *Tree) workScanQueue() {
|
||||
}
|
||||
|
||||
// Scan scans the given path and updates the id chache
|
||||
func (t *Tree) Scan(path string, action EventAction, isDir bool) error {
|
||||
func (t *Tree) Scan(path string, action watcher.EventAction, isDir bool) error {
|
||||
// cases:
|
||||
switch action {
|
||||
case ActionCreate:
|
||||
case watcher.ActionCreate:
|
||||
t.log.Debug().Str("path", path).Bool("isDir", isDir).Msg("scanning path (ActionCreate)")
|
||||
if !isDir {
|
||||
// 1. New file (could be emitted as part of a new directory)
|
||||
@@ -225,7 +216,7 @@ func (t *Tree) Scan(path string, action EventAction, isDir bool) error {
|
||||
})
|
||||
}
|
||||
|
||||
case ActionUpdate:
|
||||
case watcher.ActionUpdate:
|
||||
t.log.Debug().Str("path", path).Bool("isDir", isDir).Msg("scanning path (ActionUpdate)")
|
||||
// 3. Updated file
|
||||
// -> update file unless parent directory is being rescanned
|
||||
@@ -241,7 +232,7 @@ func (t *Tree) Scan(path string, action EventAction, isDir bool) error {
|
||||
AssimilationCounter.WithLabelValues(_labelDir, _labelUpdated).Inc()
|
||||
}
|
||||
|
||||
case ActionMove:
|
||||
case watcher.ActionMove:
|
||||
t.log.Debug().Str("path", path).Bool("isDir", isDir).Msg("scanning path (ActionMove)")
|
||||
// 4. Moved file
|
||||
// -> update file
|
||||
@@ -258,7 +249,7 @@ func (t *Tree) Scan(path string, action EventAction, isDir bool) error {
|
||||
AssimilationCounter.WithLabelValues(_labelDir, _labelMoved).Inc()
|
||||
}
|
||||
|
||||
case ActionMoveFrom:
|
||||
case watcher.ActionMoveFrom:
|
||||
t.log.Debug().Str("path", path).Bool("isDir", isDir).Msg("scanning path (ActionMoveFrom)")
|
||||
// 6. file/directory moved out of the watched directory
|
||||
// -> remove from caches
|
||||
@@ -279,7 +270,7 @@ func (t *Tree) Scan(path string, action EventAction, isDir bool) error {
|
||||
|
||||
// We do not do metrics here because this has been handled in `ActionMove`
|
||||
|
||||
case ActionDelete:
|
||||
case watcher.ActionDelete:
|
||||
t.log.Debug().Str("path", path).Bool("isDir", isDir).Msg("handling deleted item")
|
||||
|
||||
// 7. Deleted file or directory
|
||||
@@ -426,6 +417,15 @@ func (t *Tree) assimilate(item scanItem) error {
|
||||
}
|
||||
}
|
||||
|
||||
fi, err := os.Lstat(item.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !fi.IsDir() && !fi.Mode().IsRegular() {
|
||||
t.log.Trace().Str("path", item.Path).Msg("skipping non-regular file")
|
||||
return nil
|
||||
}
|
||||
|
||||
if id != "" {
|
||||
// the file has an id set, we already know it from the past
|
||||
|
||||
@@ -451,20 +451,10 @@ func (t *Tree) assimilate(item scanItem) error {
|
||||
|
||||
// compare metadata mtime with actual mtime. if it matches AND the path hasn't changed (move operation)
|
||||
// we can skip the assimilation because the file was handled by us
|
||||
fi, err := os.Lstat(item.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if previousPath == item.Path && mtime.Equal(fi.ModTime()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !fi.IsDir() && !fi.Mode().IsRegular() {
|
||||
t.log.Trace().Str("path", item.Path).Msg("skipping non-regular file")
|
||||
return nil
|
||||
}
|
||||
|
||||
// was it moved or copied/restored with a clashing id?
|
||||
if ok && len(parentID) > 0 && previousPath != item.Path {
|
||||
_, err := os.Stat(previousPath)
|
||||
@@ -675,6 +665,7 @@ assimilate:
|
||||
}
|
||||
|
||||
var n *node.Node
|
||||
sizeDiff := int64(0)
|
||||
if fi.IsDir() {
|
||||
// The Space's name attribute might not match the directory name. Use the name as
|
||||
// it was set before. Also the space root doesn't have a 'type' attribute
|
||||
@@ -712,44 +703,46 @@ assimilate:
|
||||
n.SpaceRoot = &node.Node{BaseNode: node.BaseNode{SpaceID: spaceID, ID: spaceID}}
|
||||
|
||||
prevBlobSize, err := previousAttribs.Int64(prefixes.BlobsizeAttr)
|
||||
if err == nil && prevBlobSize != fi.Size() {
|
||||
// file size changed, trigger propagation of tree size changes
|
||||
err = t.Propagate(context.Background(), n, fi.Size()-prevBlobSize)
|
||||
if err != nil {
|
||||
t.log.Error().Err(err).Str("path", path).Msg("could not propagate tree size changes")
|
||||
}
|
||||
if err != nil || prevBlobSize < 0 {
|
||||
prevBlobSize = 0
|
||||
}
|
||||
if prevBlobSize != fi.Size() {
|
||||
sizeDiff = fi.Size() - prevBlobSize
|
||||
}
|
||||
}
|
||||
attributes.SetTime(prefixes.MTimeAttr, fi.ModTime())
|
||||
|
||||
n.SpaceRoot = &node.Node{BaseNode: node.BaseNode{SpaceID: spaceID, ID: spaceID}}
|
||||
|
||||
if t.options.EnableFSRevisions {
|
||||
if !fi.IsDir() && t.options.EnableFSRevisions {
|
||||
go func() {
|
||||
// Copy the previous current version to a revision
|
||||
currentNode := node.NewBaseNode(n.SpaceID, n.ID+node.CurrentIDDelimiter, t.lookup)
|
||||
currentPath := currentNode.InternalPath()
|
||||
stat, err := os.Stat(currentPath)
|
||||
if err != nil {
|
||||
t.log.Error().Err(err).Str("path", path).Str("currentPath", currentPath).Msg("could not stat current path")
|
||||
return
|
||||
}
|
||||
revisionPath := t.lookup.VersionPath(n.SpaceID, n.ID, stat.ModTime().UTC().Format(time.RFC3339Nano))
|
||||
if err == nil {
|
||||
revisionPath := t.lookup.VersionPath(n.SpaceID, n.ID, stat.ModTime().UTC().Format(time.RFC3339Nano))
|
||||
|
||||
err = os.Rename(currentPath, revisionPath)
|
||||
if err != nil {
|
||||
t.log.Error().Err(err).Str("path", path).Str("revisionPath", revisionPath).Msg("could not create revision")
|
||||
return
|
||||
err = os.Rename(currentPath, revisionPath)
|
||||
if err != nil {
|
||||
t.log.Error().Err(err).Str("path", path).Str("revisionPath", revisionPath).Msg("could not create revision")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the new version to the current version
|
||||
if err := os.MkdirAll(filepath.Dir(currentPath), 0700); err != nil {
|
||||
t.log.Error().Err(err).Str("path", path).Str("currentPath", currentPath).Msg("could not create base path for current file")
|
||||
return
|
||||
}
|
||||
|
||||
w, err := os.OpenFile(currentPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
t.log.Error().Err(err).Str("path", path).Str("currentPath", currentPath).Msg("could not open current path for writing")
|
||||
return
|
||||
}
|
||||
defer w.Close()
|
||||
r, err := os.OpenFile(n.InternalPath(), os.O_RDONLY, 0600)
|
||||
r, err := os.OpenFile(path, os.O_RDONLY, 0600)
|
||||
if err != nil {
|
||||
t.log.Error().Err(err).Str("path", path).Msg("could not open file for reading")
|
||||
return
|
||||
@@ -775,7 +768,7 @@ assimilate:
|
||||
}()
|
||||
}
|
||||
|
||||
err = t.Propagate(context.Background(), n, 0)
|
||||
err = t.Propagate(context.Background(), n, sizeDiff)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "failed to propagate")
|
||||
}
|
||||
|
||||
11
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/cephfswatcher.go
generated
vendored
11
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/cephfswatcher.go
generated
vendored
@@ -8,6 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
kafka "github.com/segmentio/kafka-go"
|
||||
@@ -97,17 +98,17 @@ func (w *CephFSWatcher) Watch(topic string) {
|
||||
go func() {
|
||||
switch {
|
||||
case mask&CEPH_MDS_NOTIFY_DELETE > 0:
|
||||
err = w.tree.Scan(path, ActionDelete, isDir)
|
||||
err = w.tree.Scan(path, watcher.ActionDelete, isDir)
|
||||
case mask&CEPH_MDS_NOTIFY_MOVED_TO > 0:
|
||||
if ev.SrcMask > 0 {
|
||||
// This is a move, clean up the old path
|
||||
err = w.tree.Scan(filepath.Join(w.tree.options.WatchRoot, ev.SrcPath), ActionMoveFrom, isDir)
|
||||
err = w.tree.Scan(filepath.Join(w.tree.options.WatchRoot, ev.SrcPath), watcher.ActionMoveFrom, isDir)
|
||||
}
|
||||
err = w.tree.Scan(path, ActionMove, isDir)
|
||||
err = w.tree.Scan(path, watcher.ActionMove, isDir)
|
||||
case mask&CEPH_MDS_NOTIFY_CREATE > 0:
|
||||
err = w.tree.Scan(path, ActionCreate, isDir)
|
||||
err = w.tree.Scan(path, watcher.ActionCreate, isDir)
|
||||
case mask&CEPH_MDS_NOTIFY_CLOSE_WRITE > 0:
|
||||
err = w.tree.Scan(path, ActionUpdate, isDir)
|
||||
err = w.tree.Scan(path, watcher.ActionUpdate, isDir)
|
||||
case mask&CEPH_MDS_NOTIFY_CLOSE > 0:
|
||||
// ignore, already handled by CLOSE_WRITE
|
||||
default:
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
@@ -88,15 +89,15 @@ start:
|
||||
go func() {
|
||||
switch ev.Event {
|
||||
case "CREATE":
|
||||
err = w.tree.Scan(ev.Path, ActionCreate, false)
|
||||
err = w.tree.Scan(ev.Path, watcher.ActionCreate, false)
|
||||
case "CLOSE":
|
||||
var bytesWritten int
|
||||
bytesWritten, err = strconv.Atoi(ev.BytesWritten)
|
||||
if err == nil && bytesWritten > 0 {
|
||||
err = w.tree.Scan(ev.Path, ActionUpdate, false)
|
||||
err = w.tree.Scan(ev.Path, watcher.ActionUpdate, false)
|
||||
}
|
||||
case "RENAME":
|
||||
err = w.tree.Scan(ev.Path, ActionMove, false)
|
||||
err = w.tree.Scan(ev.Path, watcher.ActionMove, false)
|
||||
if warmupErr := w.tree.WarmupIDCache(ev.Path, false, false); warmupErr != nil {
|
||||
w.log.Error().Err(warmupErr).Str("path", ev.Path).Msg("error warming up id cache")
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher"
|
||||
"github.com/rs/zerolog"
|
||||
kafka "github.com/segmentio/kafka-go"
|
||||
)
|
||||
@@ -77,21 +78,21 @@ func (w *GpfsWatchFolderWatcher) Watch(topic string) {
|
||||
var err error
|
||||
switch {
|
||||
case strings.Contains(lwev.Event, "IN_DELETE"):
|
||||
err = w.tree.Scan(path, ActionDelete, isDir)
|
||||
err = w.tree.Scan(path, watcher.ActionDelete, isDir)
|
||||
|
||||
case strings.Contains(lwev.Event, "IN_MOVE_FROM"):
|
||||
err = w.tree.Scan(path, ActionMoveFrom, isDir)
|
||||
err = w.tree.Scan(path, watcher.ActionMoveFrom, isDir)
|
||||
|
||||
case strings.Contains(lwev.Event, "IN_CREATE"):
|
||||
err = w.tree.Scan(path, ActionCreate, isDir)
|
||||
err = w.tree.Scan(path, watcher.ActionCreate, isDir)
|
||||
|
||||
case strings.Contains(lwev.Event, "IN_CLOSE_WRITE"):
|
||||
bytesWritten, convErr := strconv.Atoi(lwev.BytesWritten)
|
||||
if convErr == nil && bytesWritten > 0 {
|
||||
err = w.tree.Scan(path, ActionUpdate, isDir)
|
||||
err = w.tree.Scan(path, watcher.ActionUpdate, isDir)
|
||||
}
|
||||
case strings.Contains(lwev.Event, "IN_MOVED_TO"):
|
||||
err = w.tree.Scan(path, ActionMove, isDir)
|
||||
err = w.tree.Scan(path, watcher.ActionMove, isDir)
|
||||
}
|
||||
if err != nil {
|
||||
w.log.Error().Err(err).Str("path", path).Msg("error scanning path")
|
||||
|
||||
11
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/inotifywatcher.go
generated
vendored
11
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/inotifywatcher.go
generated
vendored
@@ -30,6 +30,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher"
|
||||
"github.com/pablodz/inotifywaitgo/inotifywaitgo"
|
||||
"github.com/rs/zerolog"
|
||||
slogzerolog "github.com/samber/slog-zerolog/v2"
|
||||
@@ -96,15 +97,15 @@ func (iw *InotifyWatcher) Watch(path string) {
|
||||
var err error
|
||||
switch e {
|
||||
case inotifywaitgo.DELETE:
|
||||
err = iw.tree.Scan(event.Filename, ActionDelete, event.IsDir)
|
||||
err = iw.tree.Scan(event.Filename, watcher.ActionDelete, event.IsDir)
|
||||
case inotifywaitgo.MOVED_FROM:
|
||||
err = iw.tree.Scan(event.Filename, ActionMoveFrom, event.IsDir)
|
||||
err = iw.tree.Scan(event.Filename, watcher.ActionMoveFrom, event.IsDir)
|
||||
case inotifywaitgo.MOVED_TO:
|
||||
err = iw.tree.Scan(event.Filename, ActionMove, event.IsDir)
|
||||
err = iw.tree.Scan(event.Filename, watcher.ActionMove, event.IsDir)
|
||||
case inotifywaitgo.CREATE:
|
||||
err = iw.tree.Scan(event.Filename, ActionCreate, event.IsDir)
|
||||
err = iw.tree.Scan(event.Filename, watcher.ActionCreate, event.IsDir)
|
||||
case inotifywaitgo.CLOSE_WRITE:
|
||||
err = iw.tree.Scan(event.Filename, ActionUpdate, event.IsDir)
|
||||
err = iw.tree.Scan(event.Filename, watcher.ActionUpdate, event.IsDir)
|
||||
case inotifywaitgo.CLOSE:
|
||||
// ignore, already handled by CLOSE_WRITE
|
||||
default:
|
||||
|
||||
34
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/tree.go
generated
vendored
34
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/tree.go
generated
vendored
@@ -47,6 +47,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/trashbin"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher/natswatcher"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata/prefixes"
|
||||
@@ -147,6 +148,11 @@ func New(lu node.PathLookup, bs node.Blobstore, um usermapper.Mapper, trashbin *
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "natswatcher":
|
||||
t.watcher, err = natswatcher.New(context.TODO(), t, o.NatsWatcher, o.WatchRoot, log)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
t.watcher, err = NewInotifyWatcher(t, o, log)
|
||||
if err != nil {
|
||||
@@ -499,8 +505,18 @@ func (t *Tree) ListFolder(ctx context.Context, n *node.Node) ([]*node.Node, erro
|
||||
|
||||
_, nodeID, err := t.lookup.IDsForPath(ctx, path)
|
||||
if err != nil {
|
||||
t.log.Error().Err(err).Str("path", path).Msg("failed to get ids for entry")
|
||||
continue
|
||||
// we don't know about this node yet for some reason, assimilate it on the fly
|
||||
t.log.Info().Err(err).Str("path", path).Msg("encountered unknown entity while listing the directory. Assimilate.")
|
||||
err = t.assimilate(scanItem{Path: path})
|
||||
if err != nil {
|
||||
t.log.Error().Err(err).Str("path", path).Msg("failed to assimilate node")
|
||||
continue
|
||||
}
|
||||
_, nodeID, err = t.lookup.IDsForPath(ctx, path)
|
||||
if err != nil || nodeID == "" {
|
||||
t.log.Error().Err(err).Str("path", path).Msg("still could not resolve node after assimilation")
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
child, err := node.ReadNode(ctx, t.lookup, n.SpaceID, nodeID, false, n.SpaceRoot, true)
|
||||
@@ -708,9 +724,23 @@ func (t *Tree) createDirNode(ctx context.Context, n *node.Node) (err error) {
|
||||
t.log.Error().Err(err).Str("spaceID", n.SpaceID).Str("id", n.ID).Str("path", path).Msg("could not cache id")
|
||||
}
|
||||
|
||||
// Write mtime from filesystem to metadata to preven re-assimilation
|
||||
d, err := os.Open(path)
|
||||
if err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
fi, err := d.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mtime := fi.ModTime()
|
||||
|
||||
attributes := n.NodeMetadata(ctx)
|
||||
attributes[prefixes.MTimeAttr] = []byte(mtime.UTC().Format(time.RFC3339Nano))
|
||||
attributes[prefixes.IDAttr] = []byte(n.ID)
|
||||
attributes[prefixes.TreesizeAttr] = []byte("0") // initialize as empty, TODO why bother? if it is not set we could treat it as 0?
|
||||
|
||||
if t.options.TreeTimeAccounting || t.options.TreeSizeAccounting {
|
||||
attributes[prefixes.PropagationAttr] = []byte("1") // mark the node for propagation
|
||||
}
|
||||
|
||||
11
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher/actions.go
generated
vendored
Normal file
11
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher/actions.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package watcher
|
||||
|
||||
type EventAction int
|
||||
|
||||
const (
|
||||
ActionCreate EventAction = iota
|
||||
ActionUpdate
|
||||
ActionMove
|
||||
ActionDelete
|
||||
ActionMoveFrom
|
||||
)
|
||||
236
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher/natswatcher/natswatcher.go
generated
vendored
Normal file
236
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher/natswatcher/natswatcher.go
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
package natswatcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
// natsEvent represents the event encoded in MessagePack.
|
||||
// we abbreviate the the properties to save some space
|
||||
type natsEvent struct {
|
||||
Event string `msgpack:"e"`
|
||||
Path string `msgpack:"p,omitempty"`
|
||||
ToPath string `msgpack:"t,omitempty"`
|
||||
IsDir bool `msgpack:"d,omitempty"`
|
||||
}
|
||||
|
||||
// NatsWatcher consumes filesystem-style events from NATS JetStream.
|
||||
type NatsWatcher struct {
|
||||
ctx context.Context
|
||||
tree Scannable
|
||||
log *zerolog.Logger
|
||||
watchRoot string
|
||||
config options.NatsWatcherConfig
|
||||
}
|
||||
|
||||
type Scannable interface {
|
||||
Scan(path string, action watcher.EventAction, isDir bool) error
|
||||
}
|
||||
|
||||
// NewNatsWatcher creates a new NATS watcher.
|
||||
func New(ctx context.Context, tree Scannable, cfg options.NatsWatcherConfig, watchRoot string, log *zerolog.Logger) (*NatsWatcher, error) {
|
||||
return &NatsWatcher{
|
||||
ctx: ctx,
|
||||
tree: tree,
|
||||
log: log,
|
||||
watchRoot: watchRoot,
|
||||
config: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Watch starts consuming events from a NATS JetStream subject
|
||||
func (w *NatsWatcher) Watch(path string) {
|
||||
w.log.Info().Str("stream", w.config.Stream).Msg("starting NATS watcher with auto-reconnect")
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-w.ctx.Done():
|
||||
w.log.Debug().Msg("context cancelled, stopping NATS watcher")
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
// Try to connect with exponential backoff
|
||||
nc, js, err := w.connectWithBackoff()
|
||||
if err != nil {
|
||||
w.log.Error().Err(err).Msg("failed to establish NATS connection after retries")
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := w.consume(js); err != nil {
|
||||
w.log.Error().Err(err).Msg("NATS consumer exited with error, reconnecting")
|
||||
}
|
||||
|
||||
_ = nc.Drain()
|
||||
nc.Close()
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// connectWithBackoff repeatedly attempts to connect to NATS JetStream with exponential backoff.
|
||||
func (w *NatsWatcher) connectWithBackoff() (*nats.Conn, jetstream.JetStream, error) {
|
||||
var nc *nats.Conn
|
||||
var js jetstream.JetStream
|
||||
|
||||
b := backoff.NewExponentialBackOff()
|
||||
b.InitialInterval = 1 * time.Second
|
||||
b.MaxInterval = 30 * time.Second
|
||||
b.MaxElapsedTime = 0 // never stop
|
||||
|
||||
connect := func() error {
|
||||
select {
|
||||
case <-w.ctx.Done():
|
||||
return backoff.Permanent(w.ctx.Err())
|
||||
default:
|
||||
}
|
||||
|
||||
var err error
|
||||
nc, err = w.connect()
|
||||
if err != nil {
|
||||
w.log.Warn().Err(err).Msg("failed to connect to NATS, retrying")
|
||||
return err
|
||||
}
|
||||
|
||||
js, err = jetstream.New(nc)
|
||||
if err != nil {
|
||||
nc.Close()
|
||||
w.log.Warn().Err(err).Msg("failed to create jetstream context, retrying")
|
||||
return err
|
||||
}
|
||||
|
||||
w.log.Info().Str("endpoint", w.config.Endpoint).Msg("connected to NATS JetStream")
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := backoff.Retry(connect, backoff.WithContext(b, w.ctx)); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return nc, js, nil
|
||||
}
|
||||
|
||||
// consume subscribes to JetStream and handles messages.
|
||||
func (w *NatsWatcher) consume(js jetstream.JetStream) error {
|
||||
stream, err := js.Stream(w.ctx, w.config.Stream)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get stream: %w", err)
|
||||
}
|
||||
|
||||
consumer, err := stream.CreateOrUpdateConsumer(w.ctx, jetstream.ConsumerConfig{
|
||||
Durable: w.config.Durable,
|
||||
AckPolicy: jetstream.AckExplicitPolicy,
|
||||
MaxAckPending: w.config.MaxAckPending,
|
||||
AckWait: w.config.AckWait,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create consumer: %w", err)
|
||||
}
|
||||
w.log.Info().
|
||||
Str("stream", w.config.Stream).
|
||||
Msg("started consuming from JetStream")
|
||||
|
||||
_, err = consumer.Consume(func(msg jetstream.Msg) {
|
||||
defer func() {
|
||||
if ackErr := msg.Ack(); ackErr != nil {
|
||||
w.log.Warn().Err(ackErr).Msg("failed to ack message")
|
||||
}
|
||||
}()
|
||||
|
||||
var ev natsEvent
|
||||
if err := msgpack.Unmarshal(msg.Data(), &ev); err != nil {
|
||||
w.log.Error().Err(err).Msg("failed to decode MessagePack event")
|
||||
return
|
||||
}
|
||||
|
||||
w.handleEvent(ev)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("consumer error: %w", err)
|
||||
}
|
||||
|
||||
<-w.ctx.Done()
|
||||
return w.ctx.Err()
|
||||
}
|
||||
|
||||
// connect establishes a single NATS connection with optional TLS and auth.
|
||||
func (w *NatsWatcher) connect() (*nats.Conn, error) {
|
||||
var tlsConf *tls.Config
|
||||
if w.config.EnableTLS {
|
||||
var rootCAPool *x509.CertPool
|
||||
if w.config.TLSRootCACertificate != "" {
|
||||
rootCrtFile, err := os.ReadFile(w.config.TLSRootCACertificate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read root CA: %w", err)
|
||||
}
|
||||
rootCAPool = x509.NewCertPool()
|
||||
rootCAPool.AppendCertsFromPEM(rootCrtFile)
|
||||
w.config.TLSInsecure = false
|
||||
}
|
||||
tlsConf = &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: w.config.TLSInsecure,
|
||||
RootCAs: rootCAPool,
|
||||
}
|
||||
}
|
||||
|
||||
opts := []nats.Option{nats.Name("opencloud-posixfs-natswatcher")}
|
||||
if tlsConf != nil {
|
||||
opts = append(opts, nats.Secure(tlsConf))
|
||||
}
|
||||
if w.config.AuthUsername != "" && w.config.AuthPassword != "" {
|
||||
opts = append(opts, nats.UserInfo(w.config.AuthUsername, w.config.AuthPassword))
|
||||
}
|
||||
return nats.Connect(w.config.Endpoint, opts...)
|
||||
}
|
||||
|
||||
// handleEvent applies the event to the local tree.
|
||||
func (w *NatsWatcher) handleEvent(ev natsEvent) {
|
||||
var err error
|
||||
|
||||
// Determine the relevant path
|
||||
path := filepath.Join(w.watchRoot, ev.Path)
|
||||
|
||||
switch ev.Event {
|
||||
case "CREATE":
|
||||
err = w.tree.Scan(path, watcher.ActionCreate, ev.IsDir)
|
||||
case "MOVED_TO":
|
||||
err = w.tree.Scan(path, watcher.ActionMove, ev.IsDir)
|
||||
case "MOVE_FROM":
|
||||
err = w.tree.Scan(path, watcher.ActionMoveFrom, ev.IsDir)
|
||||
case "MOVE": // support event with source and target path
|
||||
err = w.tree.Scan(path, watcher.ActionMoveFrom, ev.IsDir)
|
||||
if err == nil {
|
||||
w.log.Error().Err(err).Interface("event", ev).Msg("error processing event")
|
||||
}
|
||||
tgt := filepath.Join(w.watchRoot, ev.ToPath)
|
||||
if tgt == "" {
|
||||
w.log.Warn().Interface("event", ev).Msg("MOVE event missing target path")
|
||||
} else {
|
||||
err = w.tree.Scan(tgt, watcher.ActionMove, ev.IsDir)
|
||||
}
|
||||
case "CLOSE_WRITE":
|
||||
err = w.tree.Scan(path, watcher.ActionUpdate, ev.IsDir)
|
||||
case "DELETE":
|
||||
err = w.tree.Scan(path, watcher.ActionDelete, ev.IsDir)
|
||||
default:
|
||||
w.log.Warn().Str("event", ev.Event).Msg("unhandled event type")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
w.log.Error().Err(err).Interface("event", ev).Msg("error processing event")
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user