From e73d5493db7d73bb5862c34fc89691964bcaadf2 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Tue, 18 Apr 2023 11:04:59 +0200 Subject: [PATCH] add optional services and fix config slice parser --- changelog/unreleased/runtime.md | 5 ++++ ocis-pkg/config/config.go | 9 +++--- ocis-pkg/config/envdecode/envdecode.go | 2 +- ocis-pkg/config/envdecode/envdecode_test.go | 20 ++++++------- ocis/pkg/runtime/service/service.go | 32 +++++++++++++++------ 5 files changed, 45 insertions(+), 23 deletions(-) create mode 100644 changelog/unreleased/runtime.md diff --git a/changelog/unreleased/runtime.md b/changelog/unreleased/runtime.md new file mode 100644 index 000000000..aa0965953 --- /dev/null +++ b/changelog/unreleased/runtime.md @@ -0,0 +1,5 @@ +Enhancement: Add optional services to the runtime + +Make it possible to start optional services in the ocis runtime. Instead of using `OCIS_RUN_SERVICES` to define all services we can now use `OCIS_ADD_RUN_SERVICES` to add a comma separated list of additional services which are not started in the single process by default. + +https://github.com/owncloud/ocis/pull/6071 diff --git a/ocis-pkg/config/config.go b/ocis-pkg/config/config.go index 626b4b692..8fb9c7a5d 100644 --- a/ocis-pkg/config/config.go +++ b/ocis-pkg/config/config.go @@ -44,10 +44,11 @@ type Mode int // Runtime configures the oCIS runtime when running in supervised mode. type Runtime struct { - Port string `yaml:"port" env:"OCIS_RUNTIME_PORT"` - Host string `yaml:"host" env:"OCIS_RUNTIME_HOST"` - Services string `yaml:"services" env:"OCIS_RUN_EXTENSIONS;OCIS_RUN_SERVICES" desc:"A comma-separated list of service names. Will start only the listed services."` - Disabled string `yaml:"disabled_services" env:"OCIS_EXCLUDE_RUN_SERVICES" desc:"A comma-separated list of service names. Will start all services except of the ones listed. Has no effect when OCIS_RUN_SERVICES is set."` + Port string `yaml:"port" env:"OCIS_RUNTIME_PORT"` + Host string `yaml:"host" env:"OCIS_RUNTIME_HOST"` + Services []string `yaml:"services" env:"OCIS_RUN_EXTENSIONS;OCIS_RUN_SERVICES" desc:"A comma-separated list of service names. Will start only the listed services."` + Disabled []string `yaml:"disabled_services" env:"OCIS_EXCLUDE_RUN_SERVICES" desc:"A comma-separated list of service names. Will start all services except of the ones listed. Has no effect when OCIS_RUN_SERVICES is set."` + Additional []string `yaml:"add_services" env:"OCIS_ADD_RUN_SERVICES" desc:"A comma-separated list of service names. Will add the listed services to the default configuration. Has no effect when OCIS_RUN_SERVICES is set."` } // Config combines all available configuration parts. diff --git a/ocis-pkg/config/envdecode/envdecode.go b/ocis-pkg/config/envdecode/envdecode.go index 8a26b84df..60d030dd2 100644 --- a/ocis-pkg/config/envdecode/envdecode.go +++ b/ocis-pkg/config/envdecode/envdecode.go @@ -214,7 +214,7 @@ func decode(target interface{}, strict bool) (int, error) { } func decodeSlice(f *reflect.Value, env string) error { - parts := strings.Split(env, ";") + parts := strings.Split(env, ",") values := parts[:0] for _, x := range parts { diff --git a/ocis-pkg/config/envdecode/envdecode_test.go b/ocis-pkg/config/envdecode/envdecode_test.go index cb3274c1c..61893f34d 100644 --- a/ocis-pkg/config/envdecode/envdecode_test.go +++ b/ocis-pkg/config/envdecode/envdecode_test.go @@ -58,7 +58,7 @@ type testConfig struct { UnmarshalerNumber unmarshalerNumber `env:"TEST_UNMARSHALER_NUMBER"` DefaultInt int `env:"TEST_UNSET,asdf=asdf,default=1234"` - DefaultSliceInt []int `env:"TEST_UNSET,asdf=asdf,default=1;2;3"` + DefaultSliceInt []int `env:"TEST_UNSET,asdf=asdf,default=1"` DefaultDuration time.Duration `env:"TEST_UNSET,asdf=asdf,default=24h"` DefaultURL *url.URL `env:"TEST_UNSET,default=http://example.com"` } @@ -137,12 +137,12 @@ func TestDecode(t *testing.T) { os.Setenv("TEST_DURATION", "10m") os.Setenv("TEST_URL", "https://example.com") os.Setenv("TEST_INVALID_INT64", "asdf") - os.Setenv("TEST_STRING_SLICE", "foo;bar") - os.Setenv("TEST_INT64_SLICE", int64AsString+";"+int64AsString) - os.Setenv("TEST_UINT16_SLICE", "60000;50000") - os.Setenv("TEST_FLOAT64_SLICE", piAsString+";"+piAsString) - os.Setenv("TEST_BOOL_SLICE", "true; false; true") - os.Setenv("TEST_DURATION_SLICE", "10m; 20m") + os.Setenv("TEST_STRING_SLICE", "foo,bar") + os.Setenv("TEST_INT64_SLICE", int64AsString+","+int64AsString) + os.Setenv("TEST_UINT16_SLICE", "60000,50000") + os.Setenv("TEST_FLOAT64_SLICE", piAsString+","+piAsString) + os.Setenv("TEST_BOOL_SLICE", "true, false, true") + os.Setenv("TEST_DURATION_SLICE", "10m, 20m") os.Setenv("TEST_URL_SLICE", "https://example.com") os.Setenv("TEST_DECODER_STRUCT", "{\"string\":\"foo\"}") os.Setenv("TEST_DECODER_STRUCT_PTR", "{\"string\":\"foo\"}") @@ -274,7 +274,7 @@ func TestDecode(t *testing.T) { t.Fatalf("Expected 1234, got %d", tc.DefaultInt) } - expectedDefaultSlice := []int{1, 2, 3} + expectedDefaultSlice := []int{1} if !reflect.DeepEqual(tc.DefaultSliceInt, expectedDefaultSlice) { t.Fatalf("Expected %d, got %d", expectedDefaultSlice, tc.DefaultSliceInt) } @@ -603,13 +603,13 @@ func TestExport(t *testing.T) { os.Setenv("TEST_BOOL", "true") os.Setenv("TEST_DURATION", "10m") os.Setenv("TEST_URL", "https://example.com") - os.Setenv("TEST_STRING_SLICE", "foo;bar") + os.Setenv("TEST_STRING_SLICE", "foo,bar") os.Setenv("TEST_NESTED_STRING", "nest_foo") os.Setenv("TEST_NESTED_STRING_POINTER", "nest_foo_ptr") os.Setenv("TEST_NESTED_TWICE_STRING", "nest_twice_foo") os.Setenv("TEST_REQUIRED_INT", "101") os.Setenv("TEST_DEFAULT_INT_SET", "102") - os.Setenv("TEST_DEFAULT_INT_SLICE", "1;2;3") + os.Setenv("TEST_DEFAULT_INT_SLICE", "1,2,3") var tc testConfigExport tc.NestedPtr = &nestedConfigExportPointer{} diff --git a/ocis/pkg/runtime/service/service.go b/ocis/pkg/runtime/service/service.go index 06cc367ed..eec8b87e9 100644 --- a/ocis/pkg/runtime/service/service.go +++ b/ocis/pkg/runtime/service/service.go @@ -18,8 +18,10 @@ import ( ociscfg "github.com/owncloud/ocis/v2/ocis-pkg/config" "github.com/owncloud/ocis/v2/ocis-pkg/log" "github.com/owncloud/ocis/v2/ocis-pkg/shared" + antivirus "github.com/owncloud/ocis/v2/services/antivirus/pkg/command" appProvider "github.com/owncloud/ocis/v2/services/app-provider/pkg/command" appRegistry "github.com/owncloud/ocis/v2/services/app-registry/pkg/command" + audit "github.com/owncloud/ocis/v2/services/audit/pkg/command" authbasic "github.com/owncloud/ocis/v2/services/auth-basic/pkg/command" authmachine "github.com/owncloud/ocis/v2/services/auth-machine/pkg/command" eventhistory "github.com/owncloud/ocis/v2/services/eventhistory/pkg/command" @@ -34,6 +36,7 @@ import ( notifications "github.com/owncloud/ocis/v2/services/notifications/pkg/command" ocdav "github.com/owncloud/ocis/v2/services/ocdav/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" proxy "github.com/owncloud/ocis/v2/services/proxy/pkg/command" search "github.com/owncloud/ocis/v2/services/search/pkg/command" @@ -65,6 +68,7 @@ type Service struct { Supervisor *suture.Supervisor ServicesRegistry serviceFuncMap Delayed serviceFuncMap + Additional serviceFuncMap Log log.Logger serviceToken map[string][]suture.ServiceToken @@ -96,6 +100,7 @@ func NewService(options ...Option) (*Service, error) { s := &Service{ ServicesRegistry: make(serviceFuncMap), Delayed: make(serviceFuncMap), + Additional: make(serviceFuncMap), Log: l, serviceToken: make(map[string][]suture.ServiceToken), @@ -134,6 +139,11 @@ func NewService(options ...Option) (*Service, error) { s.ServicesRegistry[opts.Config.EventHistory.Service.Name] = eventhistory.NewSutureService s.ServicesRegistry[opts.Config.Userlog.Service.Name] = userlog.NewSutureService + // populate optional services + s.Additional[opts.Config.Antivirus.Service.Name] = antivirus.NewSutureService + s.Additional[opts.Config.Audit.Service.Name] = audit.NewSutureService + s.Additional[opts.Config.Policies.Service.Name] = policies.NewSutureService + // populate delayed services s.Delayed[opts.Config.Sharing.Service.Name] = sharing.NewSutureService s.Delayed[opts.Config.Proxy.Service.Name] = proxy.NewSutureService @@ -212,6 +222,9 @@ func Start(o ...Option) error { // schedule services that we are sure don't have interdependencies. scheduleServiceTokens(s, s.ServicesRegistry) + // schedule services that are optional + scheduleServiceTokens(s, s.Additional) + // there are reasons not to do this, but we have race conditions ourselves. Until we resolve them, mind the following disclaimer: // Calling ServeBackground will CORRECTLY start the supervisor running in a new goroutine. It is risky to directly run // go supervisor.Serve() @@ -245,9 +258,8 @@ func scheduleServiceTokens(s *Service, funcSet serviceFuncMap) { // the runtime. func (s *Service) generateRunSet(cfg *ociscfg.Config) { runset = make(map[string]struct{}) - if cfg.Runtime.Services != "" { - e := strings.Split(strings.ReplaceAll(cfg.Runtime.Services, " ", ""), ",") - for _, name := range e { + if cfg.Runtime.Services != nil { + for _, name := range cfg.Runtime.Services { runset[name] = struct{}{} } return @@ -261,12 +273,16 @@ func (s *Service) generateRunSet(cfg *ociscfg.Config) { runset[name] = struct{}{} } - if cfg.Runtime.Disabled != "" { - e := strings.Split(strings.ReplaceAll(cfg.Runtime.Disabled, " ", ""), ",") - for _, name := range e { - delete(runset, name) - } + // add additional services if explicitly added by config + for _, name := range cfg.Runtime.Additional { + runset[name] = struct{}{} } + + // remove services if explicitly excluded by config + for _, name := range cfg.Runtime.Disabled { + delete(runset, name) + } + } // List running processes for the Service Controller.