Skip to content

Commit

Permalink
sharpen userlog service
Browse files Browse the repository at this point in the history
Signed-off-by: jkoberg <jkoberg@owncloud.com>
  • Loading branch information
kobergj committed Feb 21, 2023
1 parent d7f57f3 commit 92195ae
Show file tree
Hide file tree
Showing 13 changed files with 556 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
25 changes: 21 additions & 4 deletions services/userlog/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
# 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.

## 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 [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.
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
44 changes: 36 additions & 8 deletions services/userlog/pkg/command/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,37 @@ 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{
events.UploadReady{},
events.ContainerCreated{},
events.FileTouched{},
events.FileDownloaded{},
events.FileVersionRestored{},
events.ItemMoved{},
events.ItemTrashed{},
events.ItemPurged{},
events.ItemRestored{},
}

// Server is the entrypoint for the server command.
Expand All @@ -48,7 +60,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 +71,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 +101,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
5 changes: 5 additions & 0 deletions services/userlog/pkg/config/defaults/defaultconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func DefaultConfig() *config.Config {
Store: config.Store{
Type: "inmemory",
},
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
48 changes: 30 additions & 18 deletions services/userlog/pkg/server/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package http
import (
"fmt"

stdhttp "net/http"

"github.com/go-chi/chi/v5"
chimiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
"github.com/owncloud/ocis/v2/ocis-pkg/service/http"
"github.com/owncloud/ocis/v2/ocis-pkg/version"
svc "github.com/owncloud/ocis/v2/services/userlog/pkg/service"
Expand Down Expand Up @@ -34,29 +39,36 @@ func Server(opts ...Option) (http.Service, error) {
return http.Service{}, fmt.Errorf("could not initialize http service: %w", err)
}

//middlewares := []func(stdhttp.Handler) stdhttp.Handler{
//middleware.TraceContext,
//chimiddleware.RequestID,
//middleware.Version(
//"userlog",
//version.GetString(),
//),
//middleware.Logger(
//options.Logger,
//),
//}
middlewares := []func(stdhttp.Handler) stdhttp.Handler{
middleware.TraceContext,
chimiddleware.RequestID,
middleware.Version(
"userlog",
version.GetString(),
),
middleware.Logger(
options.Logger,
),
middleware.ExtractAccountUUID(),
}

mux := chi.NewMux()
mux.Use(middlewares...)

handle, err := svc.NewUserlogService(options.Config, options.Consumer, options.Store, options.RegisteredEvents)
handle, err := svc.NewUserlogService(
svc.Logger(options.Logger),
svc.Consumer(options.Consumer),
svc.Mux(mux),
svc.Store(options.Store),
svc.Config(options.Config),
svc.HistoryClient(options.HistoryClient),
svc.GatewayClient(options.GatewayClient),
svc.RegisteredEvents(options.RegisteredEvents),
)
if err != nil {
return http.Service{}, err
}

{
//handle = svc.NewInstrument(handle, options.Metrics)
//handle = svc.NewLogging(handle, options.Logger)
//handle = svc.NewTracing(handle)
}

if err := micro.RegisterHandler(service.Server(), handle); err != nil {
return http.Service{}, err
}
Expand Down
Loading

0 comments on commit 92195ae

Please sign in to comment.