diff --git a/changelog/unreleased/remove-dead-runtime-code.md b/changelog/unreleased/remove-dead-runtime-code.md new file mode 100644 index 000000000..e362df8a1 --- /dev/null +++ b/changelog/unreleased/remove-dead-runtime-code.md @@ -0,0 +1,5 @@ +Enhancement: Remove dead runtime code + +When moving from the old runtime to the new one there were lots of files left behind that are essentially dead code and should be removed. The original code lives here github.com/refs/pman/ if someone finds it interesting to read. + +https://github.com/owncloud/ocis/pull/1923 diff --git a/ocis/pkg/runtime/cmd/run.go b/ocis/pkg/runtime/cmd/run.go index 0312fc6b4..1c977b0fc 100644 --- a/ocis/pkg/runtime/cmd/run.go +++ b/ocis/pkg/runtime/cmd/run.go @@ -5,10 +5,8 @@ import ( "log" "net" "net/rpc" - "os" "github.com/owncloud/ocis/ocis/pkg/runtime/config" - "github.com/owncloud/ocis/ocis/pkg/runtime/process" "github.com/spf13/cobra" ) @@ -23,11 +21,8 @@ func Run(cfg *config.Config) *cobra.Command { if err != nil { log.Fatal("dialing:", err) } - - proc := process.NewProcEntry(args[0], os.Environ(), []string{args[0]}...) var res int - - if err := client.Call("Service.Start", proc, &res); err != nil { + if err := client.Call("Service.Start", &args[0], &res); err != nil { log.Fatal(err) } diff --git a/ocis/pkg/runtime/controller/controller.go b/ocis/pkg/runtime/controller/controller.go deleted file mode 100644 index 3180e1a9b..000000000 --- a/ocis/pkg/runtime/controller/controller.go +++ /dev/null @@ -1,168 +0,0 @@ -package controller - -import ( - "fmt" - "os" - "os/exec" - "sort" - "strconv" - "strings" - "sync" - "time" - - "github.com/owncloud/ocis/ocis/pkg/runtime/config" - "github.com/owncloud/ocis/ocis/pkg/runtime/process" - "github.com/owncloud/ocis/ocis/pkg/runtime/storage" - "github.com/owncloud/ocis/ocis/pkg/runtime/watcher" - "github.com/rs/zerolog" - - "github.com/olekukonko/tablewriter" -) - -// Controller supervises processes. -type Controller struct { - m *sync.RWMutex - options Options - log zerolog.Logger - Config *config.Config - - Store storage.Storage - - // Bin is the oCIS single binary name. - Bin string - - // BinPath is the oCIS single binary path withing the host machine. - // The Controller needs to know the binary location in order to spawn new extensions. - BinPath string - - // Terminated facilitates communication from Watcher <-> Controller. Writes to this - // channel WILL always attempt to restart the crashed process. - Terminated chan process.ProcEntry -} - -var ( - once = sync.Once{} -) - -// NewController initializes a new controller. -func NewController(o ...Option) Controller { - opts := &Options{} - - for _, f := range o { - f(opts) - } - - c := Controller{ - m: &sync.RWMutex{}, - options: *opts, - log: *opts.Log, - Bin: "ocis", - Terminated: make(chan process.ProcEntry), - Store: storage.NewMapStorage(), - - Config: opts.Config, - } - - if opts.Bin != "" { - c.Bin = opts.Bin - } - - // Get binary location from $PATH lookup. If not present, it uses arg[0] as entry point. - path, err := exec.LookPath(c.Bin) - if err != nil { - c.log.Debug().Msg("oCIS binary not present in PATH, using Args[0]") - path = os.Args[0] - } - c.BinPath = path - return c -} - -// Start and watches a process. -func (c *Controller) Start(pe process.ProcEntry) error { - if pid := c.Store.Load(pe.Extension); pid != 0 { - c.log.Debug().Msg(fmt.Sprintf("extension already running: %s", pe.Extension)) - return nil - } - - w := watcher.NewWatcher() - if err := pe.Start(c.BinPath); err != nil { - return err - } - - // store the spawned child process PID. - if err := c.Store.Store(pe); err != nil { - return err - } - - w.Follow(pe, c.Terminated, c.options.Config.KeepAlive) - - once.Do(func() { - j := janitor{ - time.Second, - c.Store, - } - - go j.run() - go detach(c) - }) - return nil -} - -// Kill a managed process. -// Should a process managed by the runtime be allowed to be killed if the runtime is configured not to? -func (c *Controller) Kill(pe process.ProcEntry) error { - // load stored PID - pid := c.Store.Load(pe.Extension) - - // find process in host by PID - p, err := os.FindProcess(pid) - if err != nil { - return err - } - - if err := c.Store.Delete(pe); err != nil { - return err - } - c.log.Info().Str("package", "watcher").Msgf("terminating %v", pe.Extension) - - // terminate child process - return p.Kill() -} - -// Shutdown a running runtime. -func (c *Controller) Shutdown(ch chan struct{}) error { - entries := c.Store.LoadAll() - for cmd, pid := range entries { - c.log.Info().Str("package", "watcher").Msgf("gracefully terminating %v", cmd) - p, _ := os.FindProcess(pid) - if err := p.Kill(); err != nil { - return err - } - } - - ch <- struct{}{} - return nil -} - -// List managed processes. -func (c *Controller) List() string { - tableString := &strings.Builder{} - table := tablewriter.NewWriter(tableString) - table.SetHeader([]string{"Extension", "PID"}) - - entries := c.Store.LoadAll() - - keys := make([]string, 0, len(entries)) - for k := range entries { - keys = append(keys, k) - } - - sort.Strings(keys) - - for _, v := range keys { - table.Append([]string{v, strconv.Itoa(entries[v])}) - } - - table.Render() - return tableString.String() -} diff --git a/ocis/pkg/runtime/controller/janitor.go b/ocis/pkg/runtime/controller/janitor.go deleted file mode 100644 index 61131eab3..000000000 --- a/ocis/pkg/runtime/controller/janitor.go +++ /dev/null @@ -1,49 +0,0 @@ -package controller - -import ( - "os" - "os/signal" - "syscall" - "time" - - "github.com/owncloud/ocis/ocis/pkg/runtime/process" - "github.com/owncloud/ocis/ocis/pkg/runtime/storage" -) - -type janitor struct { - // interval at which db is cleared. - interval time.Duration - - store storage.Storage -} - -func (j *janitor) run() { - ticker := time.NewTicker(j.interval) - work := make(chan os.Signal, 1) - signal.Notify(work, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT) - - for { - select { - case <-work: - return - case <-ticker.C: - j.cleanup() - } - } -} - -// cleanup removes orphaned extension + pid that were killed via SIGKILL given the nature of is being un-catchable, -// the only way to update pman's database is by polling. -func (j *janitor) cleanup() { - for name, pid := range j.store.LoadAll() { - // On unix like systems (linux, freebsd, etc) os.FindProcess will never return an error - if p, err := os.FindProcess(pid); err == nil { - if err := p.Signal(syscall.Signal(0)); err != nil { - _ = j.store.Delete(process.ProcEntry{ - Pid: pid, - Extension: name, - }) - } - } - } -} diff --git a/ocis/pkg/runtime/controller/option.go b/ocis/pkg/runtime/controller/option.go deleted file mode 100644 index 1f8bfb81c..000000000 --- a/ocis/pkg/runtime/controller/option.go +++ /dev/null @@ -1,36 +0,0 @@ -package controller - -import ( - "github.com/owncloud/ocis/ocis/pkg/runtime/config" - "github.com/rs/zerolog" -) - -// Options are the configurable options for a Controller. -type Options struct { - Bin string - Restart bool - Config *config.Config - Log *zerolog.Logger -} - -// Option represents an option. -type Option func(o *Options) - -// NewOptions returns a new Options struct. -func NewOptions() Options { - return Options{} -} - -// WithConfig sets Controller config. -func WithConfig(cfg *config.Config) Option { - return func(o *Options) { - o.Config = cfg - } -} - -// WithLog sets Controller config. -func WithLog(l *zerolog.Logger) Option { - return func(o *Options) { - o.Log = l - } -} diff --git a/ocis/pkg/runtime/controller/util.go b/ocis/pkg/runtime/controller/util.go deleted file mode 100644 index 7e157cbfc..000000000 --- a/ocis/pkg/runtime/controller/util.go +++ /dev/null @@ -1,10 +0,0 @@ -package controller - -// detach will try to restart processes on failures. -func detach(c *Controller) { - for proc := range c.Terminated { - if err := c.Start(proc); err != nil { - c.log.Err(err) - } - } -} diff --git a/ocis/pkg/runtime/log/log.go b/ocis/pkg/runtime/log/log.go deleted file mode 100644 index 5baf45f23..000000000 --- a/ocis/pkg/runtime/log/log.go +++ /dev/null @@ -1,30 +0,0 @@ -package log - -import ( - "os" - "time" - - "github.com/rs/zerolog" -) - -var ( - // Level sets a project wide log level - Level zerolog.Level = zerolog.InfoLevel -) - -// NewLogger configures a logger. -func NewLogger(options ...Option) zerolog.Logger { - zerolog.SetGlobalLevel(Level) - - o := NewOptions() - for _, f := range options { - f(o) - } - - logger := zerolog.New(os.Stdout).With().Timestamp().Logger() - if o.Pretty { - logger = logger.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}) - } - - return logger -} diff --git a/ocis/pkg/runtime/log/options.go b/ocis/pkg/runtime/log/options.go deleted file mode 100644 index a0035c478..000000000 --- a/ocis/pkg/runtime/log/options.go +++ /dev/null @@ -1,26 +0,0 @@ -package log - -import "github.com/rs/zerolog" - -// Options are the configurable options for a Controller. -type Options struct { - Level zerolog.Level - Pretty bool -} - -// Option represents an option. -type Option func(o *Options) - -// NewOptions returns a new Options struct. -func NewOptions() *Options { - return &Options{ - Level: zerolog.DebugLevel, - } -} - -// WithPretty sets the pretty option. -func WithPretty(pretty bool) Option { - return func(o *Options) { - o.Pretty = pretty - } -} diff --git a/ocis/pkg/runtime/process/process.go b/ocis/pkg/runtime/process/process.go deleted file mode 100644 index 36766fb47..000000000 --- a/ocis/pkg/runtime/process/process.go +++ /dev/null @@ -1,60 +0,0 @@ -// +build !windows - -package process - -import ( - "os" - - sys "golang.org/x/sys/unix" -) - -// ProcEntry is an entry in the File db. -type ProcEntry struct { - Args []string - Env []string - Pid int - Extension string -} - -// NewProcEntry returns a new ProcEntry. -func NewProcEntry(extension string, env []string, args ...string) ProcEntry { - return ProcEntry{ - Extension: extension, - Args: args, - Env: env, - } -} - -// Start a process. -func (e *ProcEntry) Start(binPath string) error { - var argv = []string{binPath} - argv = append(argv, e.Args...) - - p, err := os.StartProcess(binPath, argv, &os.ProcAttr{ - Files: []*os.File{ - os.Stdin, - os.Stdout, - os.Stderr, - }, - Env: e.Env, - Sys: &sys.SysProcAttr{ - Setpgid: true, - }, - }) - if err != nil { - return err - } - e.Pid = p.Pid - - return nil -} - -// Kill the wrapped process. -func (e *ProcEntry) Kill() error { - p, err := os.FindProcess(e.Pid) - if err != nil { - return err - } - - return p.Kill() -} diff --git a/ocis/pkg/runtime/process/process_windows.go b/ocis/pkg/runtime/process/process_windows.go deleted file mode 100644 index 32b36c333..000000000 --- a/ocis/pkg/runtime/process/process_windows.go +++ /dev/null @@ -1,56 +0,0 @@ -// +build windows - -package process - -import ( - "os" -) - -// ProcEntry is an entry in the File db. -type ProcEntry struct { - Args []string - Env []string - Pid int - Extension string -} - -// NewProcEntry returns a new ProcEntry. -func NewProcEntry(extension string, env []string, args ...string) ProcEntry { - return ProcEntry{ - Extension: extension, - Args: args, - Env: env, - } -} - -// Start a process. -func (e *ProcEntry) Start(binPath string) error { - var argv = []string{binPath} - argv = append(argv, e.Args...) - - p, err := os.StartProcess(binPath, argv, &os.ProcAttr{ - Files: []*os.File{ - os.Stdin, - os.Stdout, - os.Stderr, - }, - Env: e.Env, - }) - if err != nil { - return err - } - - e.Pid = p.Pid - - return nil -} - -// Kill the wrapped process. -func (e *ProcEntry) Kill() error { - p, err := os.FindProcess(e.Pid) - if err != nil { - return err - } - - return p.Kill() -} diff --git a/ocis/pkg/runtime/storage/map.go b/ocis/pkg/runtime/storage/map.go deleted file mode 100644 index 9dfa59337..000000000 --- a/ocis/pkg/runtime/storage/map.go +++ /dev/null @@ -1,64 +0,0 @@ -package storage - -import ( - "github.com/owncloud/ocis/ocis/pkg/runtime/process" - - "sync" -) - -// Map synchronizes access to extension+pid tuples. -type Map struct { - c *sync.Map -} - -// NewMapStorage initializes a new Storage. -func NewMapStorage() Storage { - return &Map{ - c: &sync.Map{}, - } -} - -// Store a value on the underlying data structure. -func (m *Map) Store(e process.ProcEntry) error { - m.c.Store(e.Extension, e.Pid) - return nil -} - -// Delete a value on the underlying data structure. -func (m *Map) Delete(e process.ProcEntry) error { - m.c.Delete(e.Extension) - return nil -} - -// Load a single pid. -func (m *Map) Load(name string) int { - var val int - m.c.Range(func(k, v interface{}) bool { - if k.(string) == name { - val = v.(int) - return false - } - return true - }) - return val -} - -// LoadAll values from the underlying data structure. -func (m *Map) LoadAll() Entries { - e := make(map[string]int) - m.c.Range(func(k, v interface{}) bool { - ks, ok := k.(string) - if !ok { - return false - } - - vs, ok := v.(int) - if !ok { - return false - } - - e[ks] = vs - return true - }) - return e -} diff --git a/ocis/pkg/runtime/storage/map_test.go b/ocis/pkg/runtime/storage/map_test.go deleted file mode 100644 index 00941d4d0..000000000 --- a/ocis/pkg/runtime/storage/map_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package storage - -import ( - "fmt" - "math/rand" - "os" - "strconv" - "testing" - - "github.com/owncloud/ocis/ocis/pkg/runtime/process" - "github.com/stretchr/testify/assert" -) - -func TestMain(m *testing.M) { - if err := loadStore(); err != nil { - os.Exit(1) - } - os.Exit(m.Run()) -} - -var ( - store = NewMapStorage() -) - -func loadStore() error { - for i := 0; i < 20; i++ { - if err := store.Store(process.ProcEntry{ - Pid: rand.Int(), //nolint:gosec - Extension: fmt.Sprintf("extension-%s", strconv.Itoa(i)), - }); err != nil { - return err - } - } - - return nil -} - -func TestLoadAll(t *testing.T) { - all := store.LoadAll() - assert.NotNil(t, all["extension-1"]) -} - -func TestDelete(t *testing.T) { - err := store.Delete(process.ProcEntry{ - Extension: "extension-1", - }) - assert.Nil(t, err) - all := store.LoadAll() - assert.Zero(t, all["extension-1"]) -} diff --git a/ocis/pkg/runtime/storage/storage.go b/ocis/pkg/runtime/storage/storage.go deleted file mode 100644 index 833084770..000000000 --- a/ocis/pkg/runtime/storage/storage.go +++ /dev/null @@ -1,21 +0,0 @@ -package storage - -import "github.com/owncloud/ocis/ocis/pkg/runtime/process" - -// Entries is a tuple of -type Entries map[string]int - -// Storage defines a basic persistence interface layer. -type Storage interface { - // Store a representation of a process. - Store(e process.ProcEntry) error - - // Delete a representation of a process. - Delete(e process.ProcEntry) error - - // Load a single entry. - Load(name string) int - - // LoadAll retrieves a set of entries of running processes on the host machine. - LoadAll() Entries -} diff --git a/ocis/pkg/runtime/watcher/watcher.go b/ocis/pkg/runtime/watcher/watcher.go deleted file mode 100644 index cbe2d46c7..000000000 --- a/ocis/pkg/runtime/watcher/watcher.go +++ /dev/null @@ -1,55 +0,0 @@ -package watcher - -import ( - golog "log" - "os" - - "github.com/owncloud/ocis/ocis/pkg/runtime/log" - "github.com/owncloud/ocis/ocis/pkg/runtime/process" - "github.com/rs/zerolog" -) - -// Watcher watches a process and sends messages using channels. -type Watcher struct { - log zerolog.Logger -} - -// NewWatcher initializes a watcher. -func NewWatcher() Watcher { - return Watcher{ - log: log.NewLogger(log.WithPretty(true)), - } -} - -// Follow a process until it dies. If restart is enabled, a new fork of the original process will be automatically spawned. -func (w *Watcher) Follow(pe process.ProcEntry, followerChan chan process.ProcEntry, restart bool) { - state := make(chan *os.ProcessState, 1) - - w.log.Debug().Str("package", "watcher").Msgf("watching %v", pe.Extension) - go func() { - ps, err := watch(pe.Pid) - if err != nil { - golog.Fatal(err) - } - - state <- ps - }() - - go func() { - status := <-state - w.log.Info().Str("package", "watcher").Msgf("%v exited with: %v", pe.Extension, status) - if restart { - followerChan <- pe - } - }() -} - -// watch a process by its pid. This operation blocks. -func watch(pid int) (*os.ProcessState, error) { - p, err := os.FindProcess(pid) - if err != nil { - return nil, err - } - - return p.Wait() -}