bump reva and deps

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
Jörn Friedrich Dreyer
2026-01-07 17:15:23 +01:00
parent 6082e0c4df
commit 8e30e535b0
126 changed files with 8819 additions and 3109 deletions
@@ -223,6 +223,7 @@ func (h *Handler) Init(c *config.Config) {
Edition: "",
Product: "reva",
ProductVersion: "",
Channel: "",
}
}
@@ -151,6 +151,7 @@ type Status struct {
Product string `json:"product" xml:"product"`
ProductVersion string `json:"productversion" xml:"productversion"`
Hostname string `json:"hostname,omitempty" xml:"hostname,omitempty"`
Channel string `json:"channel" xml:"channel"`
}
// CapabilitiesChecksums holds available hashes
@@ -321,4 +322,5 @@ type Version struct {
Edition string `json:"edition" xml:"edition"`
Product string `json:"product" xml:"product"`
ProductVersion string `json:"productversion" xml:"productversion"`
Channel string `json:"channel" xml:"channel"`
}
+21 -1
View File
@@ -20,9 +20,11 @@ package tus
import (
"context"
"fmt"
"net/http"
"path"
"regexp"
"runtime"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/mitchellh/mapstructure"
@@ -253,6 +255,13 @@ func (l tusdLogger) Handle(_ context.Context, r slog.Record) error {
case slog.LevelError:
logev = l.log.Error()
}
// Extract caller information from slog.Record only for debug and info levels
if (r.Level == slog.LevelDebug || r.Level == slog.LevelInfo) && r.PC != 0 {
frames := runtime.CallersFrames([]uintptr{r.PC})
frame, _ := frames.Next()
// add line using zerolog's caller format
logev = logev.Str("line", fmt.Sprintf("%s:%d", frame.File, frame.Line))
}
r.Attrs(func(a slog.Attr) bool {
// Resolve the Attr's value before doing anything else.
a.Value = a.Value.Resolve()
@@ -281,7 +290,18 @@ func (l tusdLogger) Enabled(_ context.Context, _ slog.Level) bool { return true
func (l tusdLogger) WithAttrs(attr []slog.Attr) slog.Handler {
fields := make(map[string]interface{}, len(attr))
for _, a := range attr {
fields[a.Key] = a.Value.String()
switch a.Value.Kind() {
case slog.KindBool:
fields[a.Key] = a.Value.Bool()
case slog.KindInt64:
fields[a.Key] = a.Value.Int64()
case slog.KindUint64:
fields[a.Key] = a.Value.Uint64()
case slog.KindFloat64:
fields[a.Key] = a.Value.Float64()
default:
fields[a.Key] = a.Value.String()
}
}
c := l.log.With().Fields(fields).Logger()
sLog := tusdLogger{log: &c}
+15 -9
View File
@@ -44,15 +44,18 @@ var (
// Config contains the configuring for a cache
type Config struct {
Store string `mapstructure:"cache_store"`
Nodes []string `mapstructure:"cache_nodes"`
Database string `mapstructure:"cache_database"`
Table string `mapstructure:"cache_table"`
TTL time.Duration `mapstructure:"cache_ttl"`
Size int `mapstructure:"cache_size"`
DisablePersistence bool `mapstructure:"cache_disable_persistence"`
AuthUsername string `mapstructure:"cache_auth_username"`
AuthPassword string `mapstructure:"cache_auth_password"`
Store string `mapstructure:"cache_store"`
Nodes []string `mapstructure:"cache_nodes"`
Database string `mapstructure:"cache_database"`
Table string `mapstructure:"cache_table"`
TTL time.Duration `mapstructure:"cache_ttl"`
Size int `mapstructure:"cache_size"`
DisablePersistence bool `mapstructure:"cache_disable_persistence"`
AuthUsername string `mapstructure:"cache_auth_username"`
AuthPassword string `mapstructure:"cache_auth_password"`
TLSEnabled bool `mapstructure:"cache_tls_enabled"`
TLSInsecure bool `mapstructure:"cache_tls_insecure"`
TLSRootCACertificate string `mapstructure:"cache_tls_root_ca_certificate"`
}
// Cache handles key value operations on caches
@@ -243,5 +246,8 @@ func getStore(cfg Config) microstore.Store {
store.Size(cfg.Size),
store.DisablePersistence(cfg.DisablePersistence),
store.Authentication(cfg.AuthUsername, cfg.AuthPassword),
store.TLSEnabled(cfg.TLSEnabled),
store.TLSInsecure(cfg.TLSInsecure),
store.TLSRootCA(cfg.TLSRootCACertificate),
)
}
@@ -38,12 +38,16 @@ func NewStoreIDCache(c cache.Config) *StoreIDCache {
return &StoreIDCache{
cache: store.Create(
store.Store(c.Store),
store.TTL(c.TTL),
store.Size(c.Size),
microstore.Nodes(c.Nodes...),
microstore.Database(c.Database),
microstore.Table(c.Table),
store.DisablePersistence(c.DisablePersistence),
store.Authentication(c.AuthUsername, c.AuthPassword),
store.TLSEnabled(c.TLSEnabled),
store.TLSInsecure(c.TLSInsecure),
store.TLSRootCA(c.TLSRootCACertificate),
),
}
}
+4
View File
@@ -131,6 +131,7 @@ func New(m map[string]interface{}, stream events.Stream, log *zerolog.Logger) (s
}
tp, err := tree.New(lu, bs, um, trashbin, p, o, stream, store.Create(
// TODO use a NewStoreIDCache here?
store.Store(o.IDCache.Store),
store.TTL(o.IDCache.TTL),
store.Size(o.IDCache.Size),
@@ -139,6 +140,9 @@ func New(m map[string]interface{}, stream events.Stream, log *zerolog.Logger) (s
microstore.Table(o.IDCache.Table),
store.DisablePersistence(o.IDCache.DisablePersistence),
store.Authentication(o.IDCache.AuthUsername, o.IDCache.AuthPassword),
store.TLSEnabled(o.IDCache.TLSEnabled),
store.TLSInsecure(o.IDCache.TLSInsecure),
store.TLSRootCA(o.IDCache.TLSRootCACertificate),
), log)
if err != nil {
return nil, err
@@ -38,6 +38,7 @@ import (
"github.com/rs/zerolog/log"
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"
@@ -60,7 +61,7 @@ type queueItem struct {
timer *time.Timer
}
const dirtyFlag = "user.oc.dirty"
const dirtyFlag = prefixes.OcPrefix + "dirty"
type assimilationNode struct {
path string
@@ -366,6 +367,11 @@ func (t *Tree) findSpaceId(path string) (string, error) {
// find the space id, scope by the according user
spaceCandidate := path
for strings.HasPrefix(spaceCandidate, t.options.Root) {
// jail at root
if t.isRootPath(spaceCandidate) {
return "", ErrRootReached
}
spaceID, _, err := t.lookup.IDsForPath(context.Background(), spaceCandidate)
if err == nil && len(spaceID) > 0 {
if t.options.UseSpaceGroups {
@@ -412,7 +418,11 @@ func (t *Tree) assimilate(item scanItem) error {
if spaceID == "" {
// node didn't have a space ID attached. try to find it by walking up the path on disk
spaceID, err = t.findSpaceId(filepath.Dir(item.Path))
if err != nil {
switch {
// ignore if we reached the root without finding a space
case errors.Is(err, ErrRootReached):
return nil
case err != nil:
return err
}
}
@@ -741,13 +751,17 @@ assimilate:
t.log.Error().Err(err).Str("path", path).Str("currentPath", currentPath).Msg("could not open current path for writing")
return
}
defer w.Close()
defer func() {
_ = w.Close()
}()
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
}
defer r.Close()
defer func() {
_ = r.Close()
}()
_, err = io.Copy(w, r)
if err != nil {
+18 -5
View File
@@ -59,7 +59,12 @@ import (
"github.com/opencloud-eu/reva/v2/pkg/utils"
)
var tracer trace.Tracer
var (
tracer trace.Tracer
// ErrRootReached is returned when the root of the tree is reached
ErrRootReached = errors.New("root of the tree reached")
)
func init() {
tracer = otel.Tracer("github.com/cs3org/reva/pkg/storage/pkg/decomposedfs/tree")
@@ -244,7 +249,7 @@ func (t *Tree) Setup() error {
}
// GetMD returns the metadata of a node in the tree
func (t *Tree) GetMD(ctx context.Context, n *node.Node) (os.FileInfo, error) {
func (t *Tree) GetMD(_ context.Context, n *node.Node) (os.FileInfo, error) {
md, err := os.Stat(n.InternalPath())
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
@@ -295,6 +300,9 @@ func (t *Tree) TouchFile(ctx context.Context, n *node.Node, markprocessing bool,
if err != nil {
return errors.Wrap(err, "posixfs: error creating node")
}
defer func() {
_ = f.Close()
}()
attributes := n.NodeMetadata(ctx)
attributes[prefixes.IDAttr] = []byte(n.ID)
@@ -452,7 +460,9 @@ func (t *Tree) ListFolder(ctx context.Context, n *node.Node) ([]*node.Node, erro
}
return nil, errors.Wrap(err, "tree: error listing "+dir)
}
defer f.Close()
defer func() {
_ = f.Close()
}()
_, subspan = tracer.Start(ctx, "f.Readdirnames")
names, err := f.Readdirnames(0)
@@ -685,7 +695,7 @@ func (t *Tree) InitNewNode(ctx context.Context, n *node.Node, fsize uint64) (met
}
return unlock, err
}
h.Close()
_ = h.Close()
if _, err := node.CheckQuota(ctx, n.SpaceRoot, false, 0, fsize); err != nil {
return unlock, err
@@ -727,9 +737,12 @@ func (t *Tree) createDirNode(ctx context.Context, n *node.Node) (err error) {
// Write mtime from filesystem to metadata to preven re-assimilation
d, err := os.Open(path)
if err != nil {
return err
}
defer func() {
_ = d.Close()
}()
fi, err := d.Stat()
if err != nil {
return err
@@ -169,6 +169,9 @@ func NewDefault(m map[string]interface{}, bs node.Blobstore, es events.Stream, l
microstore.Table(o.IDCache.Table),
store.DisablePersistence(o.IDCache.DisablePersistence),
store.Authentication(o.IDCache.AuthUsername, o.IDCache.AuthPassword),
store.TLSEnabled(o.IDCache.TLSEnabled),
store.TLSInsecure(o.IDCache.TLSInsecure),
store.TLSRootCA(o.IDCache.TLSRootCACertificate),
), log)
aspects := aspects.Aspects{
@@ -591,6 +591,17 @@ func (n *Node) readOwner(ctx context.Context) (*userpb.UserId, error) {
return nil, err
}
// lookup Tenant in extended attributes
attr, err = n.SpaceRoot.XattrString(ctx, prefixes.SpaceTenantIDAttr)
switch {
case err == nil:
owner.TenantId = attr
case metadata.IsAttrUnset(err):
// ignore
default:
return nil, err
}
// lookup type in extended attributes
attr, err = n.SpaceRoot.XattrString(ctx, prefixes.OwnerTypeAttr)
switch {
@@ -160,6 +160,9 @@ func NewDefault(m map[string]interface{}, bs tree.Blobstore, es events.Stream, l
microstore.Table(o.IDCache.Table),
store.DisablePersistence(o.IDCache.DisablePersistence),
store.Authentication(o.IDCache.AuthUsername, o.IDCache.AuthPassword),
store.TLSEnabled(o.IDCache.TLSEnabled),
store.TLSInsecure(o.IDCache.TLSInsecure),
store.TLSRootCA(o.IDCache.TLSRootCACertificate),
), log)
permissionsSelector, err := pool.PermissionsSelector(o.PermissionsSVC, pool.WithTLSMode(o.PermTLSMode))
+39
View File
@@ -103,3 +103,42 @@ func Authentication(username, password string) store.Option {
o.Context = context.WithValue(o.Context, authenticationContextKey{}, []string{username, password})
}
}
type tlsEnabledContextKey struct{}
// TLSEnabled configures whether to use TLS or not. Only supported by the `natsjs` and `natsjskv` implementations.
func TLSEnabled(enabled bool) store.Option {
return func(o *store.Options) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, tlsEnabledContextKey{}, enabled)
}
}
type tlsInsecureContextKey struct{}
// TLSInsecure configures whether to skip TLS certificate verification. Only supported by the `natsjs` and `natsjskv` implementations.
func TLSInsecure(insecure bool) store.Option {
return func(o *store.Options) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, tlsInsecureContextKey{}, insecure)
}
}
type tlsRootCAContextKey struct{}
// TLSRootCA configures the root CA certificate to use for TLS verification. Only supported by the `natsjs` and `natsjskv` implementations.
func TLSRootCA(rootCA string) store.Option {
return func(o *store.Options) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, tlsRootCAContextKey{}, rootCA)
}
}
+43 -33
View File
@@ -20,6 +20,7 @@ package store
import (
"context"
"crypto/tls"
"strings"
"time"
@@ -64,6 +65,11 @@ func Create(opts ...microstore.Option) microstore.Store {
o(options)
}
// ensure we have a logger
if options.Logger == nil {
options.Logger = logger.DefaultLogger
}
storeType, _ := options.Context.Value(typeContextKey{}).(string)
switch storeType {
@@ -118,51 +124,55 @@ func Create(opts ...microstore.Option) microstore.Store {
}
return *ocMemStore
case TypeNatsJS:
ttl, _ := options.Context.Value(ttlContextKey{}).(time.Duration)
if mem, _ := options.Context.Value(disablePersistanceContextKey{}).(bool); mem {
opts = append(opts, natsjs.DefaultMemory())
}
// TODO nats needs a DefaultTTL option as it does not support per Write TTL ...
// FIXME nats has restrictions on the key, we cannot use slashes AFAICT
// host, port, clusterid
natsOptions := nats.GetDefaultOptions()
natsOptions.Name = "TODO" // we can pass in the service name to allow identifying the client, but that requires adding a custom context option
if auth, ok := options.Context.Value(authenticationContextKey{}).([]string); ok && len(auth) == 2 {
natsOptions.User = auth[0]
natsOptions.Password = auth[1]
}
opts, ttl, natsOptions := natsConfig(options.Logger, options.Context, opts)
return natsjs.NewStore(
append(opts,
natsjs.NatsOptions(natsOptions), // always pass in properly initialized default nats options
natsjs.DefaultTTL(ttl))...,
) // TODO test with OpenCloud nats
natsjs.DefaultTTL(ttl))..., // nats needs a DefaultTTL option as it does not support per Write TTL
)
case TypeNatsJSKV:
// NOTE: nats needs a DefaultTTL option as it does not support per Write TTL ...
ttl, _ := options.Context.Value(ttlContextKey{}).(time.Duration)
if mem, _ := options.Context.Value(disablePersistanceContextKey{}).(bool); mem {
opts = append(opts, natsjskv.DefaultMemory())
}
natsOptions := nats.GetDefaultOptions()
natsOptions.Name = "TODO" // we can pass in the service name to allow identifying the client, but that requires adding a custom context option
if auth, ok := options.Context.Value(authenticationContextKey{}).([]string); ok && len(auth) == 2 {
natsOptions.User = auth[0]
natsOptions.Password = auth[1]
}
opts, ttl, natsOptions := natsConfig(options.Logger, options.Context, opts)
return natsjskv.NewStore(
append(opts,
natsjskv.NatsOptions(natsOptions), // always pass in properly initialized default nats options
natsjskv.EncodeKeys(),
natsjskv.DefaultTTL(ttl))...,
natsjskv.EncodeKeys(), // nats has restrictions on the key, we cannot use slashes
natsjskv.DefaultTTL(ttl))..., // nats needs a DefaultTTL option as it does not support per Write TTL
)
case TypeMemory, "mem", "": // allow existing short form and use as default
return microstore.NewMemoryStore(opts...)
default:
// try to log an error
if options.Logger == nil {
options.Logger = logger.DefaultLogger
}
options.Logger.Logf(logger.ErrorLevel, "unknown store type: '%s', falling back to memory", storeType)
return microstore.NewMemoryStore(opts...)
}
}
func natsConfig(log logger.Logger, ctx context.Context, opts []microstore.Option) ([]microstore.Option, time.Duration, nats.Options) {
if mem, _ := ctx.Value(disablePersistanceContextKey{}).(bool); mem {
opts = append(opts, natsjs.DefaultMemory())
}
ttl, _ := ctx.Value(ttlContextKey{}).(time.Duration)
// preparing natsOptions before the switch to reuse the same code
natsOptions := nats.GetDefaultOptions()
natsOptions.Name = "TODO" // we can pass in the service name to allow identifying the client, but that requires adding a custom context option
if auth, ok := ctx.Value(authenticationContextKey{}).([]string); ok && len(auth) == 2 {
natsOptions.User = auth[0]
natsOptions.Password = auth[1]
}
if enableTLS, ok := ctx.Value(tlsEnabledContextKey{}).(bool); ok && enableTLS {
if rootca, ok := ctx.Value(tlsRootCAContextKey{}).(string); ok && rootca != "" {
// when root ca is configured use it. an insecure flag is ignored.
if err := nats.RootCAs(rootca)(&natsOptions); err != nil {
log.Log(logger.ErrorLevel, err)
}
} else {
// enable tls with insecure option
insecure := ctx.Value(tlsInsecureContextKey{}).(bool)
_ = nats.Secure(&tls.Config{MinVersion: tls.VersionTLS12, InsecureSkipVerify: insecure})(&natsOptions)
}
}
return opts, ttl, natsOptions
}