Skip to content

Commit

Permalink
sharpen userlog service
Browse files Browse the repository at this point in the history
Signed-off-by: jkoberg <[email protected]>
  • Loading branch information
kobergj committed Feb 23, 2023
1 parent d7f57f3 commit 8bf47c6
Show file tree
Hide file tree
Showing 17 changed files with 1,020 additions and 90 deletions.
1 change: 1 addition & 0 deletions .drone.star
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ config = {
"services/storage-users",
"services/store",
"services/thumbnails",
"services/userlog",
"services/users",
"services/web",
"services/webdav",
Expand Down
9 changes: 5 additions & 4 deletions services/proxy/pkg/config/defaults/defaultconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ func DefaultPolicies() []config.Policy {
Endpoint: "/archiver",
Service: "com.owncloud.web.frontend",
},
{
// reroute oc10 notifications endpoint to userlog service
Endpoint: "/ocs/v2.php/apps/notifications/api/v1/notifications",
Service: "com.owncloud.userlog.userlog",
},
{
Type: config.RegexRoute,
Endpoint: "/ocs/v[12].php/cloud/user/signing-key", // only `user/signing-key` is left in ocis-ocs
Expand Down Expand Up @@ -202,10 +207,6 @@ func DefaultPolicies() []config.Policy {
Endpoint: "/api/v0/settings",
Service: "com.owncloud.web.settings",
},
{
Endpoint: "/api/v0/activities",
Service: "com.owncloud.userlog.userlog",
},
},
},
}
Expand Down
3 changes: 2 additions & 1 deletion services/userlog/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ docs-generate: config-docs-generate
include ../../.make/generate.mk

.PHONY: ci-go-generate
ci-go-generate: # CI runs ci-node-generate automatically before this target
ci-go-generate: $(MOCKERY) # CI runs ci-node-generate automatically before this target
$(MOCKERY) --dir ../../protogen/gen/ocis/services/eventhistory/v0 --case underscore --name EventHistoryService

.PHONY: ci-node-generate
ci-node-generate:
Expand Down
26 changes: 22 additions & 4 deletions services/userlog/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
# Userlog service
# Userlog Service

The `userlog` service provides a way to configure which events a user wants to be informed about and an API to retrieve them.
The `userlog` service is a mediator between the `eventhistory` service and clients who want to be informed about user related events. It provides an API to retrieve those.

## Store

The `userlog` service persists information via the configured store in `USERLOG_STORE_TYPE`. Possible stores are:
- `mem`: Basic in-memory store and the default.
- `ocmem`: Advanced in-memory store allowing max size.
- `redis`: Stores data in a configured redis cluster.
- `etcd`: Stores data in a configured etcd cluster.
- `nats-js`: Stores data using key-value-store feature of [nats jetstream](https://docs.nats.io/nats-concepts/jetstream/key-value-store)
- `noop`: Stores nothing. Useful for testing. Not recommended in productive enviroments.

1. Note that in-memory stores are by nature not reboot persistent.
2. Though usually not necessary, a database name and a database table can be configured for event stores if the event store supports this. Generally not applicapable for stores of type `in-memory`. These settings are blank by default which means that the standard settings of the configured store applies.
3. The userlog service can be scaled if not using `in-memory` stores and the stores are configured identically over all instances.

## Configuring

The `userlog` service has hardcoded configuration for now.
For the time being, the configuration which user related events are of interest is hardcoded and cannot be changed.

## Retrieving

The `userlog` service provides an API to retrieve configured events.
The `userlog` service provides an API to retrieve configured events. For now, this API is mostly following the [oc10 notification GET API](https://doc.owncloud.com/server/next/developer_manual/core/apis/ocs-notification-endpoint-v1.html#get-user-notifications).

## Deleting

To delete events for an user use a `DELETE` request to `ocs/v2.php/apps/notifications/api/v1/notifications` containing the ids to delete.
63 changes: 63 additions & 0 deletions services/userlog/mocks/event_history_service.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion services/userlog/pkg/command/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type SutureService struct {

// NewSutureService creates a new userlog.SutureService
func NewSutureService(cfg *ociscfg.Config) suture.Service {
cfg.Notifications.Commons = cfg.Commons
cfg.Userlog.Commons = cfg.Commons
return SutureService{
cfg: cfg.Userlog,
}
Expand Down
65 changes: 57 additions & 8 deletions services/userlog/pkg/command/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,58 @@ package command
import (
"context"
"fmt"
"strings"

"github.com/cs3org/reva/v2/pkg/events"
"github.com/cs3org/reva/v2/pkg/events/stream"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/oklog/run"
"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
"github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
ogrpc "github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
"github.com/owncloud/ocis/v2/ocis-pkg/store"
"github.com/owncloud/ocis/v2/ocis-pkg/version"
ehsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/eventhistory/v0"
"github.com/owncloud/ocis/v2/services/userlog/pkg/config"
"github.com/owncloud/ocis/v2/services/userlog/pkg/config/parser"
"github.com/owncloud/ocis/v2/services/userlog/pkg/logging"
"github.com/owncloud/ocis/v2/services/userlog/pkg/metrics"
"github.com/owncloud/ocis/v2/services/userlog/pkg/server/http"
"github.com/urfave/cli/v2"
"go-micro.dev/v4/store"
)

// all events we care about
var _registeredEvents = []events.Unmarshaller{
// file related
events.UploadReady{},
events.ContainerCreated{},
events.FileTouched{},
events.FileDownloaded{},
events.FileVersionRestored{},
events.ItemMoved{},
events.ItemTrashed{},
events.ItemPurged{},
events.ItemRestored{},

// space related
events.SpaceCreated{},
events.SpaceRenamed{},
events.SpaceEnabled{},
events.SpaceDisabled{},
events.SpaceDeleted{},
events.SpaceShared{},
events.SpaceUnshared{},
events.SpaceUpdated{},
events.SpaceMembershipExpired{},

// share related
events.ShareCreated{},
// events.ShareRemoved{}, // TODO: ShareRemoved doesn't hold sharee information
events.ShareUpdated{},
events.ShareExpired{},
events.LinkCreated{},
// events.LinkRemoved{}, // TODO: LinkRemoved doesn't hold sharee information
events.LinkUpdated{},
}

// Server is the entrypoint for the server command.
Expand All @@ -48,7 +81,9 @@ func Server(cfg *config.Config) *cli.Command {
}
return context.WithCancel(cfg.Context)
}()

mtrcs := metrics.New()
mtrcs.BuildInfo.WithLabelValues(version.GetString()).Set(1)

defer cancel()

Expand All @@ -57,15 +92,27 @@ func Server(cfg *config.Config) *cli.Command {
return err
}

var st store.Store
switch cfg.Store.Type {
case "inmemory":
st = store.NewMemoryStore()
default:
return fmt.Errorf("unknown store '%s' configured", cfg.Store.Type)
st := store.Create(
store.Type(cfg.Store.Type),
store.Addresses(strings.Split(cfg.Store.Addresses, ",")...),
store.Database(cfg.Store.Database),
store.Table(cfg.Store.Table),
)

tm, err := pool.StringToTLSMode(cfg.GRPCClientTLS.Mode)
if err != nil {
return err
}
gwclient, err := pool.GetGatewayServiceClient(
cfg.RevaGateway,
pool.WithTLSCACert(cfg.GRPCClientTLS.CACert),
pool.WithTLSMode(tm),
)
if err != nil {
return fmt.Errorf("could not get reva client: %s", err)
}

mtrcs.BuildInfo.WithLabelValues(version.GetString()).Set(1)
hClient := ehsvc.NewEventHistoryService("com.owncloud.api.eventhistory", grpc.DefaultClient())

{
server, err := http.Server(
Expand All @@ -75,6 +122,8 @@ func Server(cfg *config.Config) *cli.Command {
http.Metrics(mtrcs),
http.Store(st),
http.Consumer(consumer),
http.Gateway(gwclient),
http.History(hClient),
http.RegisteredEvents(_registeredEvents),
)

Expand Down
14 changes: 9 additions & 5 deletions services/userlog/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package config

import (
"context"
"time"

"github.com/owncloud/ocis/v2/ocis-pkg/shared"
)
Expand All @@ -19,16 +18,21 @@ type Config struct {
HTTP HTTP `yaml:"http"`
GRPCClientTLS *shared.GRPCClientTLS `yaml:"grpc_client_tls"`

Events Events `yaml:"events"`
Store Store `yaml:"store"`
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;USERLOG_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary to access resources from other services."`
RevaGateway string `yaml:"reva_gateway" env:"REVA_GATEWAY" desc:"CS3 gateway used to look up user metadata"`
Events Events `yaml:"events"`
Store Store `yaml:"store"`

Context context.Context `yaml:"-"`
}

// Store configures the store to use
type Store struct {
Type string `yaml:"type" env:"USERLOG_STORE_TYPE" desc:"The type of the store. Supported is inmemory"`
RecordExpiry time.Duration `yaml:"record_expiry" env:"USERLOG_RECORD_EXPIRY" desc:"time to life for events in the store"`
Type string `yaml:"type" env:"USERLOG_STORE_TYPE" desc:"The type of the userlog store. Supported values are: 'mem', 'ocmem', 'etcd', 'redis', 'nats-js', 'noop'. See the text description for details."`
Addresses string `yaml:"addresses" env:"USERLOG_STORE_ADDRESSES" desc:"A comma separated list of addresses to access the configured store. This has no effect when 'in-memory' stores are configured. Note that the behaviour how addresses are used is dependent on the library of the configured store."`
Database string `yaml:"database" env:"USERLOG_STORE_DATABASE" desc:"(optional) The database name the configured store should use. This has no effect when 'in-memory' stores are configured."`
Table string `yaml:"table" env:"USERLOG_STORE_TABLE" desc:"(optional) The database table the store should use. This has no effect when 'in-memory' stores are configured."`
Size int `yaml:"size" env:"USERLOG_STORE_SIZE" desc:"The maximum quantity of items in the store. Only applies when store type 'ocmem' is configured. Defaults to 512."`
}

// Events combines the configuration options for the event bus.
Expand Down
7 changes: 6 additions & 1 deletion services/userlog/pkg/config/defaults/defaultconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ func DefaultConfig() *config.Config {
EnableTLS: false,
},
Store: config.Store{
Type: "inmemory",
Type: "mem",
},
RevaGateway: shared.DefaultRevaConfig().Address,
HTTP: config.HTTP{
Addr: "127.0.0.1:0",
Root: "/",
Expand Down Expand Up @@ -57,6 +58,10 @@ func EnsureDefaults(cfg *config.Config) {
cfg.Log = &config.Log{}
}

if cfg.MachineAuthAPIKey == "" && cfg.Commons != nil && cfg.Commons.MachineAuthAPIKey != "" {
cfg.MachineAuthAPIKey = cfg.Commons.MachineAuthAPIKey
}

if cfg.GRPCClientTLS == nil {
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
if cfg.Commons != nil && cfg.Commons.GRPCClientTLS != nil {
Expand Down
5 changes: 5 additions & 0 deletions services/userlog/pkg/config/parser/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"

ociscfg "github.com/owncloud/ocis/v2/ocis-pkg/config"
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
"github.com/owncloud/ocis/v2/services/userlog/pkg/config"
"github.com/owncloud/ocis/v2/services/userlog/pkg/config/defaults"

Expand Down Expand Up @@ -34,5 +35,9 @@ func ParseConfig(cfg *config.Config) error {

// Validate validates the config
func Validate(cfg *config.Config) error {
if cfg.MachineAuthAPIKey == "" {
return shared.MissingMachineAuthApiKeyError(cfg.Service.Name)
}

return nil
}
18 changes: 18 additions & 0 deletions services/userlog/pkg/server/http/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package http
import (
"context"

gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
"github.com/cs3org/reva/v2/pkg/events"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
ehsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/eventhistory/v0"
"github.com/owncloud/ocis/v2/services/userlog/pkg/config"
"github.com/owncloud/ocis/v2/services/userlog/pkg/metrics"
"github.com/urfave/cli/v2"
Expand All @@ -24,6 +26,8 @@ type Options struct {
Namespace string
Store store.Store
Consumer events.Consumer
GatewayClient gateway.GatewayAPIClient
HistoryClient ehsvc.EventHistoryService
RegisteredEvents []events.Unmarshaller
}

Expand Down Expand Up @@ -94,6 +98,20 @@ func Consumer(consumer events.Consumer) Option {
}
}

// Gateway provides a function to configure the gateway client
func Gateway(gw gateway.GatewayAPIClient) Option {
return func(o *Options) {
o.GatewayClient = gw
}
}

// History provides a function to configure the event history client
func History(h ehsvc.EventHistoryService) Option {
return func(o *Options) {
o.HistoryClient = h
}
}

// RegisteredEvents provides a function to register events
func RegisteredEvents(evs []events.Unmarshaller) Option {
return func(o *Options) {
Expand Down
Loading

0 comments on commit 8bf47c6

Please sign in to comment.