Add an ocm service exposing the ocm related http and grpc APIs

This commit is contained in:
André Duffeck
2023-10-13 10:04:04 +02:00
parent 3eea26390c
commit 668f917dba
32 changed files with 934 additions and 3 deletions

View File

@@ -67,7 +67,7 @@ We also suggest to use the last port in your extensions' range as a debug/metric
| 9265-9269 | FREE |
| 9270-9274 | [eventhistory]({{< ref "../eventhistory/_index.md" >}}) |
| 9275-9279 | FREE |
| 9280-9284 | FREE |
| 9280-9284 | [ocm]({{< ref "../ocm/_index.md" >}}) |
| 9285-9289 | FREE |
| 9290-9294 | FREE |
| 9295-9299 | FREE |

View File

@@ -22,6 +22,7 @@ import (
nats "github.com/owncloud/ocis/v2/services/nats/pkg/config"
notifications "github.com/owncloud/ocis/v2/services/notifications/pkg/config"
ocdav "github.com/owncloud/ocis/v2/services/ocdav/pkg/config"
ocm "github.com/owncloud/ocis/v2/services/ocm/pkg/config"
ocs "github.com/owncloud/ocis/v2/services/ocs/pkg/config"
policies "github.com/owncloud/ocis/v2/services/policies/pkg/config"
postprocessing "github.com/owncloud/ocis/v2/services/postprocessing/pkg/config"
@@ -98,6 +99,7 @@ type Config struct {
Nats *nats.Config `yaml:"nats"`
Notifications *notifications.Config `yaml:"notifications"`
OCDav *ocdav.Config `yaml:"ocdav"`
OCM *ocm.Config `yaml:"ocm"`
OCS *ocs.Config `yaml:"ocs"`
Postprocessing *postprocessing.Config `yaml:"postprocessing"`
Policies *policies.Config `yaml:"policies"`

View File

@@ -21,6 +21,7 @@ import (
nats "github.com/owncloud/ocis/v2/services/nats/pkg/config/defaults"
notifications "github.com/owncloud/ocis/v2/services/notifications/pkg/config/defaults"
ocdav "github.com/owncloud/ocis/v2/services/ocdav/pkg/config/defaults"
ocm "github.com/owncloud/ocis/v2/services/ocm/pkg/config/defaults"
ocs "github.com/owncloud/ocis/v2/services/ocs/pkg/config/defaults"
policies "github.com/owncloud/ocis/v2/services/policies/pkg/config/defaults"
postprocessing "github.com/owncloud/ocis/v2/services/postprocessing/pkg/config/defaults"
@@ -70,6 +71,7 @@ func DefaultConfig() *Config {
Nats: nats.DefaultConfig(),
Notifications: notifications.DefaultConfig(),
OCDav: ocdav.DefaultConfig(),
OCM: ocm.DefaultConfig(),
OCS: ocs.DefaultConfig(),
Postprocessing: postprocessing.DefaultConfig(),
Policies: policies.DefaultConfig(),

View File

@@ -39,6 +39,7 @@ import (
nats "github.com/owncloud/ocis/v2/services/nats/pkg/command"
notifications "github.com/owncloud/ocis/v2/services/notifications/pkg/command"
ocdav "github.com/owncloud/ocis/v2/services/ocdav/pkg/command"
ocm "github.com/owncloud/ocis/v2/services/ocm/pkg/command"
ocs "github.com/owncloud/ocis/v2/services/ocs/pkg/command"
policies "github.com/owncloud/ocis/v2/services/policies/pkg/command"
postprocessing "github.com/owncloud/ocis/v2/services/postprocessing/pkg/command"
@@ -272,6 +273,11 @@ func NewService(options ...Option) (*Service, error) {
cfg.Webfinger.Commons = cfg.Commons
return webfinger.Execute(cfg.Webfinger)
})
reg(opts.Config.OCM.Service.Name, func(ctx context.Context, cfg *ociscfg.Config) error {
cfg.OCM.Context = ctx
cfg.OCM.Commons = cfg.Commons
return ocm.Execute(cfg.OCM)
})
// populate optional services
areg := func(name string, exec func(context.Context, *ociscfg.Config) error) {

View File

@@ -43,6 +43,7 @@ type Config struct {
StorageUsersEndpoint string `yaml:"-"`
StorageSharesEndpoint string `yaml:"-"`
AppRegistryEndpoint string `yaml:"-"`
OCMEndpoint string `yaml:"-"`
StorageRegistry StorageRegistry `yaml:"storage_registry"` // TODO: should we even support switching this?

View File

@@ -63,6 +63,7 @@ func DefaultConfig() *config.Config {
StorageSharesEndpoint: "com.owncloud.api.storage-shares",
StorageUsersEndpoint: "com.owncloud.api.storage-users",
UsersEndpoint: "com.owncloud.api.users",
OCMEndpoint: "com.owncloud.api.ocm",
StorageRegistry: config.StorageRegistry{
Driver: "spaces",

View File

@@ -50,7 +50,10 @@ func GatewayConfigFromStruct(cfg *config.Config, logger log.Logger) map[string]i
// sharing is located on the sharing service
"usershareprovidersvc": cfg.SharingEndpoint,
"publicshareprovidersvc": cfg.SharingEndpoint,
"ocmshareprovidersvc": cfg.SharingEndpoint,
"ocmshareprovidersvc": cfg.OCMEndpoint,
"ocminvitemanagersvc": cfg.OCMEndpoint,
"ocmproviderauthorizersvc": cfg.OCMEndpoint,
"ocmcoresvc": cfg.OCMEndpoint,
"commit_share_to_storage_grant": cfg.CommitShareToStorageGrant,
"share_folder": cfg.ShareFolder, // ShareFolder is the location where to create shares in the recipient's storage provider.
// other
@@ -84,6 +87,7 @@ func GatewayConfigFromStruct(cfg *config.Config, logger log.Logger) map[string]i
"machine": cfg.AuthMachineEndpoint,
"publicshares": cfg.StoragePublicLinkEndpoint,
"serviceaccounts": cfg.AuthServiceEndpoint,
"ocmshares": cfg.OCMEndpoint,
},
},
},

View File

@@ -63,6 +63,7 @@ func Server(cfg *config.Config) *cli.Command {
ocdav.AllowedOrigins(cfg.HTTP.CORS.AllowedOrigins),
ocdav.FilesNamespace(cfg.FilesNamespace),
ocdav.WebdavNamespace(cfg.WebdavNamespace),
ocdav.OCMNamespace(cfg.OCMNamespace),
ocdav.AllowDepthInfinity(cfg.AllowPropfindDepthInfinity),
ocdav.SharesNamespace(cfg.SharesNamespace),
ocdav.Timeout(cfg.Timeout),

View File

@@ -23,6 +23,7 @@ type Config struct {
WebdavNamespace string `yaml:"webdav_namespace" env:"OCDAV_WEBDAV_NAMESPACE" desc:"Jail requests to /dav/webdav into this CS3 namespace. Supports template layouting with CS3 User properties."`
FilesNamespace string `yaml:"files_namespace" env:"OCDAV_FILES_NAMESPACE" desc:"Jail requests to /dav/files/{username} into this CS3 namespace. Supports template layouting with CS3 User properties."`
SharesNamespace string `yaml:"shares_namespace" env:"OCDAV_SHARES_NAMESPACE" desc:"The human readable path for the share jail. Relative to a users personal space root. Upcased intentionally."`
OCMNamespace string `yaml:"ocm_namespace" env:"OCDAV_OCM_NAMESPACE" desc:"The human readable path prefix for the ocm shares."`
// PublicURL used to redirect /s/{token} URLs to
PublicURL string `yaml:"public_url" env:"OCIS_URL;OCDAV_PUBLIC_URL" desc:"URL where oCIS is reachable for users."`

View File

@@ -81,6 +81,7 @@ func DefaultConfig() *config.Config {
WebdavNamespace: "/users/{{.Id.OpaqueId}}",
FilesNamespace: "/users/{{.Id.OpaqueId}}",
SharesNamespace: "/Shares",
OCMNamespace: "/public",
PublicURL: "https://localhost:9200",
Insecure: false,
Timeout: 84300,

37
services/ocm/Makefile Normal file
View File

@@ -0,0 +1,37 @@
SHELL := bash
NAME := ocm
include ../../.make/recursion.mk
############ tooling ############
ifneq (, $(shell command -v go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
include ../../.bingo/Variables.mk
endif
############ go tooling ############
include ../../.make/go.mk
############ release ############
include ../../.make/release.mk
############ docs generate ############
include ../../.make/docs.mk
.PHONY: docs-generate
docs-generate: config-docs-generate
############ generate ############
include ../../.make/generate.mk
.PHONY: ci-go-generate
ci-go-generate: # CI runs ci-node-generate automatically before this target
.PHONY: ci-node-generate
ci-node-generate:
############ licenses ############
.PHONY: ci-node-check-licenses
ci-node-check-licenses:
.PHONY: ci-node-save-licenses
ci-node-save-licenses:

3
services/ocm/README.md Normal file
View File

@@ -0,0 +1,3 @@
# OCM
The `ocm` service provides federated sharing functionality based on [sciencemesh](https://sciencemesh.io/) and [ocm](https://github.com/cs3org/OCM-API).

View File

@@ -0,0 +1,14 @@
package main
import (
"os"
"github.com/owncloud/ocis/v2/services/ocm/pkg/command"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config/defaults"
)
func main() {
if err := command.Execute(defaults.DefaultConfig()); err != nil {
os.Exit(1)
}
}

View File

@@ -0,0 +1,18 @@
package command
import (
"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "Check health status",
Action: func(c *cli.Context) error {
// Not implemented
return nil
},
}
}

View File

@@ -0,0 +1,34 @@
package command
import (
"os"
"github.com/owncloud/ocis/v2/ocis-pkg/clihelper"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the ocm command.
func Execute(cfg *config.Config) error {
app := clihelper.DefaultApp(&cli.App{
Name: "ocm",
Usage: "starts ocm service",
Commands: GetCommands(cfg),
})
return app.Run(os.Args)
}

View File

@@ -0,0 +1,110 @@
package command
import (
"context"
"fmt"
"os"
"path"
"github.com/cs3org/reva/v2/cmd/revad/runtime"
"github.com/gofrs/uuid"
"github.com/oklog/run"
"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
"github.com/owncloud/ocis/v2/ocis-pkg/registry"
"github.com/owncloud/ocis/v2/ocis-pkg/sync"
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
"github.com/owncloud/ocis/v2/ocis-pkg/version"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config/parser"
"github.com/owncloud/ocis/v2/services/ocm/pkg/logging"
"github.com/owncloud/ocis/v2/services/ocm/pkg/revaconfig"
"github.com/owncloud/ocis/v2/services/ocm/pkg/server/debug"
"github.com/urfave/cli/v2"
)
// Server is the entrypoint for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: fmt.Sprintf("start the %s service without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(c *cli.Context) error {
return configlog.ReturnFatal(parser.ParseConfig(cfg))
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
traceProvider, err := tracing.GetServiceTraceProvider(cfg.Tracing, cfg.Service.Name)
if err != nil {
return err
}
gr := run.Group{}
ctx, cancel := defineContext(cfg)
defer cancel()
rCfg := revaconfig.OCMConfigFromStruct(cfg, logger)
gr.Add(func() error {
pidFile := path.Join(os.TempDir(), "revad-"+cfg.Service.Name+"-"+uuid.Must(uuid.NewV4()).String()+".pid")
reg := registry.GetRegistry()
runtime.RunWithOptions(rCfg, pidFile,
runtime.WithLogger(&logger.Logger),
runtime.WithRegistry(reg),
runtime.WithTraceProvider(traceProvider),
)
return nil
}, func(err error) {
logger.Error().
Err(err).
Str("server", cfg.Service.Name).
Msg("Shutting down server")
cancel()
os.Exit(1)
})
debugServer, err := debug.Server(
debug.Logger(logger),
debug.Context(ctx),
debug.Config(cfg),
)
if err != nil {
logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(debugServer.ListenAndServe, func(_ error) {
cancel()
})
if !cfg.Supervised {
sync.Trap(&gr, cancel)
}
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, uuid.Must(uuid.NewV4()).String(), cfg.GRPC.Addr, version.GetString())
if err := registry.RegisterService(ctx, grpcSvc, logger); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc service")
}
httpSvc := registry.BuildHTTPService(cfg.HTTP.Namespace+"."+cfg.Service.Name, uuid.Must(uuid.NewV4()).String(), cfg.HTTP.Addr, version.GetString())
if err := registry.RegisterService(ctx, httpSvc, logger); err != nil {
logger.Fatal().Err(err).Msg("failed to register the http service")
}
return gr.Run()
},
}
}
// defineContext sets the context for the service. If there is a context configured it will create a new child from it,
// if not, it will create a root context that can be cancelled.
func defineContext(cfg *config.Config) (context.Context, context.CancelFunc) {
return func() (context.Context, context.CancelFunc) {
if cfg.Context == nil {
return context.WithCancel(context.Background())
}
return context.WithCancel(cfg.Context)
}()
}

View File

@@ -0,0 +1,19 @@
package command
import (
"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
"github.com/urfave/cli/v2"
)
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "print the version of this binary and the running service instances",
Category: "info",
Action: func(c *cli.Context) error {
// not implemented
return nil
},
}
}

View File

@@ -0,0 +1,131 @@
package config
import (
"context"
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
"go-micro.dev/v4/client"
)
// Config combines all available configuration parts.
type Config struct {
Commons *shared.Commons `yaml:"-"` // don't use this directly as configuration for a service
Service Service `yaml:"-"`
Tracing *Tracing `yaml:"tracing"`
Log *Log `yaml:"log"`
Debug Debug `yaml:"debug"`
HTTP HTTPConfig `yaml:"http"`
Middleware Middleware `yaml:"middleware"`
GRPC GRPCConfig `yaml:"grpc"`
GRPCClientTLS *shared.GRPCClientTLS `yaml:"grpc_client_tls"`
GrpcClient client.Client `yaml:"-"`
Reva *shared.Reva `yaml:"reva"`
OCMD OCMD `yaml:"ocmd"`
ScienceMesh ScienceMesh `yaml:"sciencemesh"`
OCMInviteManager OCMInviteManager `yaml:"ocm_invite_manager"`
OCMProviderAuthorizerDriver string `yaml:"ocm_provider_authorizer_driver" env:"SHARING_OCM_PROVIDER_AUTHORIZER_DRIVER" desc:"Driver to be used to persist ocm invites. Supported values 'json'."`
OCMProviderAuthorizerDrivers OCMProviderAuthorizerDrivers `yaml:"ocm_provider_authorizer_drivers"`
OCMShareProvider OCMShareProvider `yaml:"ocm_share_provider"`
OCMCore OCMCore `yaml:"ocm_core"`
Supervised bool `yaml:"-"`
Context context.Context `yaml:"-"`
}
// HTTPConfig defines the available http configuration.
type HTTPConfig struct {
Addr string `yaml:"addr" env:"OCM_HTTP_ADDR" desc:"The bind address of the HTTP service."`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"OCM_HTTP_PROTOCOL" desc:"The transport protocol of the HTTP service."`
Prefix string `yaml:"prefix" env:"OCM_HTTP_PREFIX" desc:"The Path prefix where the OCM can be accessed (defaults to /)."`
CORS CORS `yaml:"cors"`
}
// Middleware configures reva middlewares.
type Middleware struct {
Auth Auth `yaml:"auth"`
}
// Auth configures reva http auth middleware.
type Auth struct {
CredentialsByUserAgent map[string]string `yaml:"credentials_by_user_agent"`
}
// CORS defines the available cors configuration.
type CORS struct {
AllowedOrigins []string `yaml:"allow_origins" env:"OCIS_CORS_ALLOW_ORIGINS;OCM_CORS_ALLOW_ORIGINS" desc:"A comma-separated list of allowed CORS origins. See following chapter for more details: *Access-Control-Allow-Origin* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin"`
AllowedMethods []string `yaml:"allow_methods" env:"OCIS_CORS_ALLOW_METHODS;OCM_CORS_ALLOW_METHODS" desc:"A comma-separated list of allowed CORS methods. See following chapter for more details: *Access-Control-Request-Method* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Method"`
AllowedHeaders []string `yaml:"allow_headers" env:"OCIS_CORS_ALLOW_HEADERS;OCM_CORS_ALLOW_HEADERS" desc:"A blank or comma-separated list of allowed CORS headers. See following chapter for more details: *Access-Control-Request-Headers* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Headers."`
AllowCredentials bool `yaml:"allow_credentials" env:"OCIS_CORS_ALLOW_CREDENTIALS;OCM_CORS_ALLOW_CREDENTIALS" desc:"Allow credentials for CORS.See following chapter for more details: *Access-Control-Allow-Credentials* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials."`
}
// GRPCConfig defines the available grpc configuration.
type GRPCConfig struct {
Addr string `ocisConfig:"addr" env:"OCM_GRPC_ADDR" desc:"The bind address of the GRPC service."`
Namespace string `ocisConfig:"-" yaml:"-"`
TLS *shared.GRPCServiceTLS `yaml:"tls"`
Protocol string `yaml:"protocol" env:"OCM_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service."`
}
type ScienceMesh struct {
Prefix string `yaml:"prefix" env:"OCM_SCIENCEMESH_PREFIX" desc:"URL path prefix for the ScienceMesh service. Note that the string must not start with '/'."`
}
type OCMD struct {
Prefix string `yaml:"prefix" env:"OCM_OCMD_PREFIX" desc:"URL path prefix for the OCMD service. Note that the string must not start with '/'."`
ExposeRecipientDisplayName bool `yaml:"expose_recipient_display_name" env:"OCM_OCMD_EXPOSE_RECIPIENT_DISPLAY_NAME" desc:"Expose the display name of OCM share recipients."`
}
type OCMInviteManager struct {
Driver string `yaml:"driver" env:"SHARING_OCM_INVITE_MANAGER_DRIVER" desc:"Driver to be used to persist ocm invites. Supported values 'json'."`
Drivers OCMInviteManagerDrivers `yaml:"drivers"`
Insecure bool `yaml:"insecure" env:"SHARING_OCM_INVITE_MANAGER_INSECURE" desc:"Disable TLS certificate validation for the OCM connections. Do not set this in production environments."`
}
type OCMInviteManagerDrivers struct {
JSON OCMInviteManagerJSONDriver `yaml:"json"`
}
type OCMInviteManagerJSONDriver struct {
File string `yaml:"file" env:"SHARING_OCM_INVITE_MANAGER_JSON_FILE" desc:"Path to the JSON file where ocm invites data will be stored. If not defined, the root directory derives from $OCIS_BASE_DATA_PATH:/storage."`
}
type OCMProviderAuthorizerDrivers struct {
JSON OCMProviderAuthorizerJSONDriver `yaml:"json"`
}
type OCMProviderAuthorizerJSONDriver struct {
Providers string `yaml:"providers" env:"SHARING_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE" desc:"Path to the JSON file where ocm invites data will be stored. If not defined, the root directory derives from $OCIS_BASE_DATA_PATH:/storage."`
VerifyRequestHostname bool `yaml:"verify_request_hostname" env:"SHARING_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE"`
}
type OCMCore struct {
Driver string `yaml:"driver" env:"SHARING_OCM_CORE_DRIVER" desc:"Driver to be used for the ocm core. Supported values 'json'."`
Drivers OCMCoreDrivers `yaml:"drivers"`
}
type OCMCoreDrivers struct {
JSON OCMCoreJSONDriver `yaml:"json"`
}
type OCMCoreJSONDriver struct {
File string `yaml:"file" env:"SHARING_OCM_CORE_JSON_FILE" desc:"Path to the JSON file where ocm share data will be stored. If not defined, the root directory derives from $OCIS_BASE_DATA_PATH:/storage."`
}
type OCMShareProvider struct {
Driver string `yaml:"driver" env:"SHARING_OCM_SHARE_PROVIDER_DRIVER" desc:"Driver to be used for the ocm share provider. Supported values 'json'."`
Drivers OCMShareProviderDrivers `yaml:"drivers"`
Insecure bool `yaml:"insecure" env:"SHARING_OCM_SHARE_PROVIDER_INSECURE" desc:"Disable TLS certificate validation for the OCM connections. Do not set this in production environments."`
}
type OCMShareProviderDrivers struct {
JSON OCMShareProviderJSONDriver `yaml:"json"`
}
type OCMShareProviderJSONDriver struct {
File string `yaml:"file" env:"SHARING_OCM_SHAREPROVIDER_JSON_FILE" desc:"Path to the JSON file where ocm share data will be stored. If not defined, the root directory derives from $OCIS_BASE_DATA_PATH:/storage."`
}

View File

@@ -0,0 +1,9 @@
package config
// Debug defines the available debug configuration.
type Debug struct {
Addr string `yaml:"addr" env:"OCM_DEBUG_ADDR" desc:"Bind address of the debug server, where metrics, health, config and debug endpoints will be exposed."`
Token string `yaml:"token" env:"OCM_DEBUG_TOKEN" desc:"Token to secure the metrics endpoint."`
Pprof bool `yaml:"pprof" env:"OCM_DEBUG_PPROF" desc:"Enables pprof, which can be used for profiling."`
Zpages bool `yaml:"zpages" env:"OCM_DEBUG_ZPAGES" desc:"Enables zpages, which can be used for collecting and viewing in-memory traces."`
}

View File

@@ -0,0 +1,169 @@
package defaults
import (
"path/filepath"
"github.com/owncloud/ocis/v2/ocis-pkg/config/defaults"
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
"github.com/owncloud/ocis/v2/ocis-pkg/structs"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
)
// FullDefaultConfig returns the full default config
func FullDefaultConfig() *config.Config {
cfg := DefaultConfig()
EnsureDefaults(cfg)
Sanitize(cfg)
return cfg
}
// DefaultConfig return the default configuration
func DefaultConfig() *config.Config {
return &config.Config{
Debug: config.Debug{
Addr: "127.0.0.1:9281",
Token: "",
Pprof: false,
Zpages: false,
},
HTTP: config.HTTPConfig{
Addr: "127.0.0.1:9280",
Namespace: "com.owncloud.web",
Protocol: "tcp",
Prefix: "",
CORS: config.CORS{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{
"OPTIONS",
"HEAD",
"GET",
"PUT",
"POST",
"DELETE",
"MKCOL",
"PROPFIND",
"PROPPATCH",
"MOVE",
"COPY",
"REPORT",
"SEARCH",
},
AllowedHeaders: []string{
"Origin",
"Accept",
"Content-Type",
"Depth",
"Authorization",
"Ocs-Apirequest",
"If-None-Match",
"If-Match",
"Destination",
"Overwrite",
"X-Request-Id",
"X-Requested-With",
"Tus-Resumable",
"Tus-Checksum-Algorithm",
"Upload-Concat",
"Upload-Length",
"Upload-Metadata",
"Upload-Defer-Length",
"Upload-Expires",
"Upload-Checksum",
"Upload-Offset",
"X-HTTP-Method-Override",
"Cache-Control",
},
AllowCredentials: true,
},
},
GRPC: config.GRPCConfig{
Addr: "127.0.0.1:9282",
Namespace: "com.owncloud.api",
},
Reva: shared.DefaultRevaConfig(),
Service: config.Service{
Name: "ocm",
},
ScienceMesh: config.ScienceMesh{
Prefix: "sciencemesh",
},
OCMD: config.OCMD{
Prefix: "ocm",
},
OCMInviteManager: config.OCMInviteManager{
Driver: "json",
Drivers: config.OCMInviteManagerDrivers{
JSON: config.OCMInviteManagerJSONDriver{
File: filepath.Join(defaults.BaseDataPath(), "storage", "ocminvites.json"),
},
},
Insecure: false,
},
OCMProviderAuthorizerDriver: "json",
OCMProviderAuthorizerDrivers: config.OCMProviderAuthorizerDrivers{
JSON: config.OCMProviderAuthorizerJSONDriver{
Providers: filepath.Join(defaults.BaseDataPath(), "storage", "ocmproviders.json"),
},
},
OCMShareProvider: config.OCMShareProvider{
Driver: "json",
Drivers: config.OCMShareProviderDrivers{
JSON: config.OCMShareProviderJSONDriver{
File: filepath.Join(defaults.BaseDataPath(), "storage", "ocmshares.json"),
},
},
Insecure: false,
},
OCMCore: config.OCMCore{
Driver: "json",
Drivers: config.OCMCoreDrivers{
JSON: config.OCMCoreJSONDriver{
File: filepath.Join(defaults.BaseDataPath(), "storage", "ocmshares.json"),
},
},
},
}
}
// EnsureDefaults ensures the config contains default values
func EnsureDefaults(cfg *config.Config) {
// provide with defaults for shared logging, since we need a valid destination address for "envdecode".
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &config.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil {
cfg.Log = &config.Log{}
}
if cfg.Tracing == nil && cfg.Commons != nil && cfg.Commons.Tracing != nil {
cfg.Tracing = &config.Tracing{
Enabled: cfg.Commons.Tracing.Enabled,
Type: cfg.Commons.Tracing.Type,
Endpoint: cfg.Commons.Tracing.Endpoint,
Collector: cfg.Commons.Tracing.Collector,
}
} else if cfg.Tracing == nil {
cfg.Tracing = &config.Tracing{}
}
if cfg.Reva == nil && cfg.Commons != nil {
cfg.Reva = structs.CopyOrZeroValue(cfg.Commons.Reva)
}
if cfg.GRPCClientTLS == nil && cfg.Commons != nil {
cfg.GRPCClientTLS = structs.CopyOrZeroValue(cfg.Commons.GRPCClientTLS)
}
if cfg.GRPC.TLS == nil && cfg.Commons != nil {
cfg.GRPC.TLS = structs.CopyOrZeroValue(cfg.Commons.GRPCServiceTLS)
}
}
// Sanitize sanitizes the config
func Sanitize(cfg *config.Config) {
// nothing to sanitize here atm
}

View File

@@ -0,0 +1,9 @@
package config
// Log defines the available log configuration.
type Log struct {
Level string `mapstructure:"level" env:"OCIS_LOG_LEVEL;OCM_LOG_LEVEL" desc:"The log level. Valid values are: 'panic', 'fatal', 'error', 'warn', 'info', 'debug', 'trace'."`
Pretty bool `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;OCM_LOG_PRETTY" desc:"Activates pretty log output."`
Color bool `mapstructure:"color" env:"OCIS_LOG_COLOR;OCM_LOG_COLOR" desc:"Activates colorized log output."`
File string `mapstructure:"file" env:"OCIS_LOG_FILE;OCM_LOG_FILE" desc:"The path to the log file. Activates logging to this file if set."`
}

View File

@@ -0,0 +1,43 @@
package parser
import (
"errors"
ociscfg "github.com/owncloud/ocis/v2/ocis-pkg/config"
"github.com/owncloud/ocis/v2/ocis-pkg/structs"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config/defaults"
"github.com/owncloud/ocis/v2/ocis-pkg/config/envdecode"
)
// ParseConfig loads configuration from known paths.
func ParseConfig(cfg *config.Config) error {
_, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg)
if err != nil {
return err
}
defaults.EnsureDefaults(cfg)
// load all env variables relevant to the config in the current context.
if err := envdecode.Decode(cfg); err != nil {
// no environment variable set for this config is an expected "error"
if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) {
return err
}
}
defaults.Sanitize(cfg)
return Validate(cfg)
}
// Validate validates the config
func Validate(cfg *config.Config) error {
if cfg.GRPCClientTLS == nil && cfg.Commons != nil {
cfg.GRPCClientTLS = structs.CopyOrZeroValue(cfg.Commons.GRPCClientTLS)
}
return nil
}

View File

@@ -0,0 +1,6 @@
package config
// Service defines the available service configuration.
type Service struct {
Name string `yaml:"-"`
}

View File

@@ -0,0 +1,21 @@
package config
import "github.com/owncloud/ocis/v2/ocis-pkg/tracing"
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `yaml:"enabled" env:"OCIS_TRACING_ENABLED;OCM_TRACING_ENABLED" desc:"Activates tracing."`
Type string `yaml:"type" env:"OCIS_TRACING_TYPE;OCM_TRACING_TYPE" desc:"The type of tracing. Defaults to '', which is the same as 'jaeger'. Allowed tracing types are 'jaeger' and '' as of now."`
Endpoint string `yaml:"endpoint" env:"OCIS_TRACING_ENDPOINT;OCM_TRACING_ENDPOINT" desc:"The endpoint of the tracing agent."`
Collector string `yaml:"collector" env:"OCIS_TRACING_COLLECTOR;OCM_TRACING_COLLECTOR" desc:"The HTTP endpoint for sending spans directly to a collector, i.e. http://jaeger-collector:14268/api/traces. Only used if the tracing endpoint is unset."`
}
// Convert Tracing to the tracing package's Config struct.
func (t Tracing) Convert() tracing.Config {
return tracing.Config{
Enabled: t.Enabled,
Type: t.Type,
Endpoint: t.Endpoint,
Collector: t.Collector,
}
}

View File

@@ -0,0 +1,17 @@
package logging
import (
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
)
// LoggerFromConfig initializes a service-specific logger instance.
func Configure(name string, cfg *config.Log) log.Logger {
return log.NewLogger(
log.Name(name),
log.Level(cfg.Level),
log.Pretty(cfg.Pretty),
log.Color(cfg.Color),
log.File(cfg.File),
)
}

View File

@@ -0,0 +1,35 @@
package metrics
import "github.com/prometheus/client_golang/prometheus"
var (
// Namespace defines the namespace for the defines metrics.
Namespace = "ocis"
// Subsystem defines the subsystem for the defines metrics.
Subsystem = "ocm"
)
// Metrics defines the available metrics of this service.
type Metrics struct {
BuildInfo *prometheus.GaugeVec
}
// New initializes the available metrics.
func New() *Metrics {
m := &Metrics{
BuildInfo: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: Subsystem,
Name: "build_info",
Help: "Build information",
}, []string{"version"}),
}
_ = prometheus.Register(
m.BuildInfo,
)
// TODO: implement metrics
return m
}

View File

@@ -0,0 +1,115 @@
package revaconfig
import (
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
)
// OCMConfigFromStruct will adapt an oCIS config struct into a reva mapstructure to start a reva service.
func OCMConfigFromStruct(cfg *config.Config, logger log.Logger) map[string]interface{} {
return map[string]interface{}{
"shared": map[string]interface{}{
"gatewaysvc": cfg.Reva.Address, // Todo or address?
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
},
"http": map[string]interface{}{
"network": cfg.HTTP.Protocol,
"address": cfg.HTTP.Addr,
"middlewares": map[string]interface{}{
"cors": map[string]interface{}{
"allowed_origins": cfg.HTTP.CORS.AllowedOrigins,
"allowed_methods": cfg.HTTP.CORS.AllowedMethods,
"allowed_headers": cfg.HTTP.CORS.AllowedHeaders,
"allow_credentials": cfg.HTTP.CORS.AllowCredentials,
// currently unused
//"options_passthrough": ,
//"debug": ,
//"max_age": ,
//"priority": ,
//"exposed_headers": ,
},
"auth": map[string]interface{}{
"credentials_by_user_agent": cfg.Middleware.Auth.CredentialsByUserAgent,
},
"prometheus": map[string]interface{}{
"namespace": "ocis",
"subsystem": "ocm",
},
"requestid": map[string]interface{}{},
},
// TODO build services dynamically
"services": map[string]interface{}{
"sciencemesh": map[string]interface{}{
"prefix": cfg.ScienceMesh.Prefix,
"smtp_credentials": map[string]string{},
"gatewaysvc": cfg.Reva.Address,
"mesh_directory_url": cfg.Commons.OcisURL,
"provider_domain": cfg.Commons.OcisURL,
},
"ocmd": map[string]interface{}{
"prefix": cfg.OCMD.Prefix,
"gatewaysvc": cfg.Reva.Address,
"expose_recipient_display_name": cfg.OCMD.ExposeRecipientDisplayName,
},
},
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,
"address": cfg.GRPC.Addr,
"tls_settings": map[string]interface{}{
"enabled": cfg.GRPC.TLS.Enabled,
"certificate": cfg.GRPC.TLS.Cert,
"key": cfg.GRPC.TLS.Key,
},
"services": map[string]interface{}{
"ocminvitemanager": map[string]interface{}{
"driver": cfg.OCMInviteManager.Driver,
"drivers": map[string]interface{}{
"json": map[string]interface{}{
"file": cfg.OCMInviteManager.Drivers.JSON.File,
},
},
"provider_domain": cfg.Commons.OcisURL,
"ocm_insecure": cfg.OCMInviteManager.Insecure,
},
"ocmproviderauthorizer": map[string]interface{}{
"driver": cfg.OCMProviderAuthorizerDriver,
"drivers": map[string]interface{}{
"json": map[string]interface{}{
"providers": cfg.OCMProviderAuthorizerDrivers.JSON.Providers,
"verify_request_hostname": cfg.OCMProviderAuthorizerDrivers.JSON.VerifyRequestHostname,
},
},
},
"ocmshareprovider": map[string]interface{}{
"driver": cfg.OCMShareProvider.Driver,
"drivers": map[string]interface{}{
"json": map[string]interface{}{
"file": cfg.OCMShareProvider.Drivers.JSON.File,
},
},
"gatewaysvc": cfg.Reva.Address,
"provider_domain": cfg.Commons.OcisURL,
"webdav_endpoint": cfg.Commons.OcisURL,
"client_insecure": cfg.OCMShareProvider.Insecure,
},
"ocmcore": map[string]interface{}{
"driver": cfg.OCMCore.Driver,
"drivers": map[string]interface{}{
"json": map[string]interface{}{
"file": cfg.OCMCore.Drivers.JSON.File,
},
},
},
"authprovider": map[string]interface{}{
"auth_manager": "ocmshares",
"auth_managers": map[string]interface{}{
"ocmshares": map[string]interface{}{
"gatewaysvc": cfg.Reva.Address,
},
},
},
},
},
}
}

View File

@@ -0,0 +1,50 @@
package debug
import (
"context"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger log.Logger
Context context.Context
Config *config.Config
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Context provides a function to set the context option.
func Context(val context.Context) Option {
return func(o *Options) {
o.Context = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}

View File

@@ -0,0 +1,63 @@
package debug
import (
"io"
"net/http"
"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
"github.com/owncloud/ocis/v2/ocis-pkg/version"
"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
)
// Server initializes the debug service and server.
func Server(opts ...Option) (*http.Server, error) {
options := newOptions(opts...)
return debug.NewService(
debug.Logger(options.Logger),
debug.Name(options.Config.Service.Name),
debug.Version(version.GetString()),
debug.Address(options.Config.Debug.Addr),
debug.Token(options.Config.Debug.Token),
debug.Pprof(options.Config.Debug.Pprof),
debug.Zpages(options.Config.Debug.Zpages),
debug.Health(health(options.Config)),
debug.Ready(ready(options.Config)),
//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
), nil
}
// health implements the health check.
func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}
// ready implements the ready check.
func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}

View File

@@ -143,6 +143,14 @@ func DefaultPolicies() []config.Policy {
Service: "com.owncloud.web.frontend",
Unprotected: true,
},
{
Endpoint: "/sciencemesh/",
Service: "com.owncloud.web.ocm",
},
{
Endpoint: "/ocm/",
Service: "com.owncloud.web.ocm",
},
{
Endpoint: "/ocs/",
Service: "com.owncloud.web.frontend",

View File

@@ -25,6 +25,8 @@ var (
_publicPaths = [...]string{
"/dav/public-files/",
"/dav/ocm/",
"/ocm/",
"/remote.php/dav/public-files/",
"/ocs/v1.php/apps/files_sharing/api/v1/tokeninfo/unprotected",
"/ocs/v2.php/apps/files_sharing/api/v1/tokeninfo/unprotected",

View File

@@ -105,7 +105,6 @@ type UserSharingJSONCS3Driver struct {
SystemUserAPIKey string `yaml:"system_user_api_key" env:"OCIS_SYSTEM_USER_API_KEY;SHARING_USER_JSONCS3_SYSTEM_USER_API_KEY" desc:"API key for the STORAGE-SYSTEM system user."`
CacheTTL int `yaml:"cache_ttl" env:"SHARING_USER_JSONCS3_CACHE_TTL" desc:"TTL for the internal caches in seconds."`
}
type PublicSharingDrivers struct {
JSON PublicSharingJSONDriver `yaml:"json"`
JSONCS3 PublicSharingJSONCS3Driver `yaml:"jsoncs3"`