Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add app provider and app provider registry #2204

Merged
merged 13 commits into from Sep 3, 2021
6 changes: 6 additions & 0 deletions changelog/unreleased/app-provider.md
@@ -0,0 +1,6 @@
Enhancement: Add app provider and app provider registry

We added the app provider and app provider registry. Now the CS3org WOPI server can be registered and OpenInApp requests can be done.

https://github.com/owncloud/ocis/pull/2204
https://github.com/cs3org/reva/pull/1785
4 changes: 4 additions & 0 deletions deployments/examples/ocis_wopi/config/ocis/proxy-config.json
Expand Up @@ -32,6 +32,10 @@
"endpoint": "/ocs/v[12].php/cloud/(users?|groups)",
"backend": "http://localhost:9110"
},
{
"endpoint": "/app/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/ocs/",
"backend": "http://localhost:9140"
Expand Down
10 changes: 7 additions & 3 deletions deployments/examples/ocis_wopi/docker-compose.yml
Expand Up @@ -66,6 +66,13 @@ services:
WEB_UI_CONFIG: "/var/tmp/ocis/.config/web-config.json"
# proxy
PROXY_CONFIG_FILE: "/var/tmp/ocis/.config/proxy-config.json"
# app provider
APP_PROVIDER_DRIVER: wopi
APP_PROVIDER_WOPI_DRIVER_APP_NAME: Collabora
APP_PROVIDER_WOPI_DRIVER_APP_URL: https://${COLLABORA_DOMAIN:-collabora.owncloud.test}
APP_PROVIDER_WOPI_DRIVER_INSECURE: "${INSECURE:-false}"
APP_PROVIDER_WOPI_DRIVER_IOP_SECRET: ${WOPI_IOP_SECRET:-LoremIpsum123}
APP_PROVIDER_WOPI_DRIVER_WOPI_URL: https://${WOPISERVER_DOMAIN:-wopiserver.owncloud.test}
volumes:
- ./config/ocis/entrypoint-override.sh:/entrypoint-override.sh
- ./config/ocis/web-config.dist.json:/config/web-config.dist.json
Expand All @@ -90,9 +97,6 @@ services:
OCIS_LOG_LEVEL: ${OCIS_LOG_LEVEL:-error} # make oCIS less verbose
WOPISERVER_REVA_GATEWAY_ADDR: ocis:9142
OCIS_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
WOPISERVER_WOPI_SERVER_HOST: https://${WOPISERVER_DOMAIN:-wopiserver.owncloud.test}
WOPISERVER_WOPI_SERVER_IOP_SECRET: ${WOPI_IOP_SECRET:-LoremIpsum123}
WOPISERVER_WOPI_SERVER_INSECURE: "${INSECURE:-false}"
logging:
driver: "local"
restart: always
Expand Down
2 changes: 2 additions & 0 deletions docs/extensions/storage/ports.md
Expand Up @@ -34,6 +34,8 @@ For now, the storage service uses these ports to preconfigure those services:
| 9159 | storage users debug |
| 9160 | groups |
| 9161 | groups debug |
| 9164 | storage appprovider |
| 9165 | storage appprovider debug |
| 9178 | storage public link |
| 9179 | storage public link data |
| 9215 | storage meta grpc |
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Expand Up @@ -19,8 +19,8 @@ require (
github.com/asim/go-micro/v3 v3.6.0
github.com/blevesearch/bleve/v2 v2.1.0
github.com/coreos/go-oidc/v3 v3.0.0
github.com/cs3org/go-cs3apis v0.0.0-20210802070913-970eec344e59
github.com/cs3org/reva v1.12.0
github.com/cs3org/go-cs3apis v0.0.0-20210812121411-f18cf19614e8
github.com/cs3org/reva v1.12.1-0.20210901093814-b54f42d242fd
github.com/disintegration/imaging v1.6.2
github.com/glauth/glauth v1.1.3-0.20210729125545-b9aecdfcac31
github.com/go-chi/chi/v5 v5.0.3
Expand Down
136 changes: 21 additions & 115 deletions go.sum

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions ocis/pkg/command/storageappprovider.go
@@ -0,0 +1,45 @@
// +build !simple

package command

import (
"github.com/micro/cli/v2"
"github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis/pkg/register"
"github.com/owncloud/ocis/storage/pkg/command"
svcconfig "github.com/owncloud/ocis/storage/pkg/config"
"github.com/owncloud/ocis/storage/pkg/flagset"
)

// StorageAppProviderCommand is the entrypoint for the reva-app-provider command.
func StorageAppProviderCommand(cfg *config.Config) *cli.Command {
wkloucek marked this conversation as resolved.
Show resolved Hide resolved
return &cli.Command{
Name: "storage-app-provider",
Usage: "Start storage app-provider service",
Category: "Extensions",
Flags: flagset.AppProviderWithConfig(cfg.Storage),
Action: func(c *cli.Context) error {
origCmd := command.AppProvider(configureStorageAppProvider(cfg))
return handleOriginalAction(c, origCmd)
},
}
}

func configureStorageAppProvider(cfg *config.Config) *svcconfig.Config {
cfg.Storage.Log.Level = cfg.Log.Level
cfg.Storage.Log.Pretty = cfg.Log.Pretty
cfg.Storage.Log.Color = cfg.Log.Color

if cfg.Tracing.Enabled {
cfg.Storage.Tracing.Enabled = cfg.Tracing.Enabled
cfg.Storage.Tracing.Type = cfg.Tracing.Type
cfg.Storage.Tracing.Endpoint = cfg.Tracing.Endpoint
cfg.Storage.Tracing.Collector = cfg.Tracing.Collector
}

return cfg.Storage
}

func init() {
register.AddCommand(StorageAppProviderCommand)
}
1 change: 1 addition & 0 deletions ocis/pkg/runtime/service/service.go
Expand Up @@ -108,6 +108,7 @@ func NewService(options ...Option) (*Service, error) {
s.ServicesRegistry["storage-home"] = storage.NewStorageHome
s.ServicesRegistry["storage-users"] = storage.NewStorageUsers
s.ServicesRegistry["storage-public-link"] = storage.NewStoragePublicLink
s.ServicesRegistry["storage-appprovider"] = storage.NewAppProvider

// populate delayed services
s.Delayed["storage-sharing"] = storage.NewSharing
Expand Down
4 changes: 4 additions & 0 deletions proxy/pkg/proxy/proxy.go
Expand Up @@ -295,6 +295,10 @@ func defaultPolicies() []config.Policy {
Endpoint: "/ocs/v[12].php/cloud/(users?|groups)", // we have `user`, `users` and `groups` in ocis-ocs
Backend: "http://localhost:9110",
},
{
Endpoint: "/app/",
Backend: "http://localhost:9140",
},
{
Endpoint: "/ocs/",
Backend: "http://localhost:9140",
Expand Down
160 changes: 160 additions & 0 deletions storage/pkg/command/appprovider.go
@@ -0,0 +1,160 @@
package command

import (
"context"
"flag"
"os"
"path"

"github.com/cs3org/reva/cmd/revad/runtime"
"github.com/gofrs/uuid"
"github.com/micro/cli/v2"
"github.com/oklog/run"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/owncloud/ocis/storage/pkg/config"
"github.com/owncloud/ocis/storage/pkg/flagset"
"github.com/owncloud/ocis/storage/pkg/server/debug"
"github.com/owncloud/ocis/storage/pkg/tracing"
"github.com/thejerf/suture/v4"
)

// AppProvider is the entrypoint for the app provider command.
func AppProvider(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "app-provider",
Usage: "Start appprovider for providing apps",
Flags: flagset.AppProviderWithConfig(cfg),
Before: func(c *cli.Context) error {
cfg.Reva.AppProvider.Services = c.StringSlice("service")

return nil
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
tracing.Configure(cfg, logger)
gr := run.Group{}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

uuid := uuid.Must(uuid.NewV4())
pidFile := path.Join(os.TempDir(), "revad-"+c.Command.Name+"-"+uuid.String()+".pid")

rcfg := appProviderConfigFromStruct(c, cfg)

gr.Add(func() error {
runtime.RunWithOptions(rcfg, pidFile, runtime.WithLogger(&logger.Logger))
return nil
}, func(_ error) {
logger.Info().
Str("server", c.Command.Name).
Msg("Shutting down server")

cancel()
})

debugServer, err := debug.Server(
debug.Name(c.Command.Name+"-debug"),
debug.Addr(cfg.Reva.AppProvider.DebugAddr),
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.Reva.AppProvider.Supervised {
sync.Trap(&gr, cancel)
}

return gr.Run()
},
}
}

// appProviderConfigFromStruct will adapt an oCIS config struct into a reva mapstructure to start a reva service.
func appProviderConfigFromStruct(c *cli.Context, cfg *config.Config) map[string]interface{} {

rcfg := map[string]interface{}{
"core": map[string]interface{}{
"max_cpus": cfg.Reva.AppProvider.MaxCPUs,
"tracing_enabled": cfg.Tracing.Enabled,
"tracing_endpoint": cfg.Tracing.Endpoint,
"tracing_collector": cfg.Tracing.Collector,
"tracing_service_name": c.Command.Name,
},
"shared": map[string]interface{}{
"jwt_secret": cfg.Reva.JWTSecret,
},
"grpc": map[string]interface{}{
"network": cfg.Reva.AppProvider.GRPCNetwork,
"address": cfg.Reva.AppProvider.GRPCAddr,
// TODO build services dynamically
"services": map[string]interface{}{
"appprovider": map[string]interface{}{
"gatewaysvc": cfg.Reva.Gateway.Endpoint,
"app_provider_url": cfg.Reva.AppProvider.ExternalAddr,
"driver": cfg.Reva.AppProvider.Driver,
"drivers": map[string]interface{}{
"wopi": map[string]interface{}{
"app_api_key": cfg.Reva.AppProvider.WopiDriver.AppAPIKey,
"app_desktop_only": cfg.Reva.AppProvider.WopiDriver.AppDesktopOnly,
"app_icon_uri": cfg.Reva.AppProvider.WopiDriver.AppIconURI,
"app_int_url": cfg.Reva.AppProvider.WopiDriver.AppInternalURL,
"app_name": cfg.Reva.AppProvider.WopiDriver.AppName,
"app_url": cfg.Reva.AppProvider.WopiDriver.AppURL,
"insecure_connections": cfg.Reva.AppProvider.WopiDriver.Insecure,
"iop_secret": cfg.Reva.AppProvider.WopiDriver.IopSecret,
"jwt_secret": cfg.Reva.AppProvider.WopiDriver.JWTSecret,
"wopi_url": cfg.Reva.AppProvider.WopiDriver.WopiURL,
},
},
},
},
},
}
return rcfg
}

// AppProviderSutureService allows for the app-provider command to be embedded and supervised by a suture supervisor tree.
type AppProviderSutureService struct {
cfg *config.Config
}

// NewAppProvider creates a new store.AppProviderSutureService
func NewAppProvider(cfg *ociscfg.Config) suture.Service {
if cfg.Mode == 0 {
cfg.Storage.Reva.AppProvider.Supervised = true
}
return AppProviderSutureService{
cfg: cfg.Storage,
}
}

func (s AppProviderSutureService) Serve(ctx context.Context) error {
s.cfg.Reva.AppProvider.Context = ctx
f := &flag.FlagSet{}
for k := range AppProvider(s.cfg).Flags {
if err := AppProvider(s.cfg).Flags[k].Apply(f); err != nil {
return err
}
}
cliCtx := cli.NewContext(nil, f, nil)
if AppProvider(s.cfg).Before != nil {
if err := AppProvider(s.cfg).Before(cliCtx); err != nil {
return err
}
}
if err := AppProvider(s.cfg).Action(cliCtx); err != nil {
return err
}

return nil
}
6 changes: 6 additions & 0 deletions storage/pkg/command/frontend.go
Expand Up @@ -141,6 +141,12 @@ func frontendConfigFromStruct(c *cli.Context, cfg *config.Config, filesCfg map[s
},
// TODO build services dynamically
"services": map[string]interface{}{
"appprovider": map[string]interface{}{
"prefix": cfg.Reva.Frontend.AppProviderPrefix,
"transfer_shared_secret": cfg.Reva.TransferSecret,
"timeout": 86400,
"insecure": true,
},
"datagateway": map[string]interface{}{
"prefix": cfg.Reva.Frontend.DatagatewayPrefix,
"transfer_shared_secret": cfg.Reva.TransferSecret,
Expand Down
3 changes: 3 additions & 0 deletions storage/pkg/command/gateway.go
Expand Up @@ -160,6 +160,9 @@ func gatewayConfigFromStruct(c *cli.Context, cfg *config.Config, logger log.Logg
},
},
},
"appregistry": map[string]interface{}{
"driver": "static",
},
"storageregistry": map[string]interface{}{
"driver": cfg.Reva.StorageRegistry.Driver,
"drivers": map[string]interface{}{
Expand Down
1 change: 1 addition & 0 deletions storage/pkg/command/root.go
Expand Up @@ -76,6 +76,7 @@ func Execute(cfg *config.Config) error {
Gateway(cfg),
Users(cfg),
Groups(cfg),
AppProvider(cfg),
AuthBasic(cfg),
AuthBearer(cfg),
Sharing(cfg),
Expand Down
23 changes: 23 additions & 0 deletions storage/pkg/config/config.go
Expand Up @@ -39,6 +39,27 @@ type StorageRegistry struct {
JSON string
}

// AppProvider defines the available app provider configuration
type AppProvider struct {
Port
ExternalAddr string
Driver string
WopiDriver WopiDriver
}

type WopiDriver struct {
AppAPIKey string
AppDesktopOnly bool
AppIconURI string
AppInternalURL string
AppName string
AppURL string
Insecure bool
IopSecret string
JWTSecret string
WopiURL string
}

// Sharing defines the available sharing configuration.
type Sharing struct {
Port
Expand Down Expand Up @@ -109,6 +130,7 @@ type Groups struct {
type FrontendPort struct {
Port

AppProviderPrefix string
DatagatewayPrefix string
OCDavPrefix string
OCSPrefix string
Expand Down Expand Up @@ -390,6 +412,7 @@ type Reva struct {
StorageUsers StoragePort
StoragePublicLink PublicStorage
StorageMetadata StoragePort
AppProvider AppProvider
// Configs can be used to configure the reva instance.
// Services and Ports will be ignored if this is used
Configs map[string]interface{}
Expand Down