105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
// Package hooks implements CRI-O's hook handling.
|
|
package hooks
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
|
"github.com/pkg/errors"
|
|
current "github.com/projectatomic/libpod/pkg/hooks/1.0.0"
|
|
)
|
|
|
|
// Version is the current hook configuration version.
|
|
const Version = current.Version
|
|
|
|
const (
|
|
// DefaultDir is the default directory containing system hook configuration files.
|
|
DefaultDir = "/usr/share/containers/oci/hooks.d"
|
|
|
|
// OverrideDir is the directory for hook configuration files overriding the default entries.
|
|
OverrideDir = "/etc/containers/oci/hooks.d"
|
|
)
|
|
|
|
// Manager provides an opaque interface for managing CRI-O hooks.
|
|
type Manager struct {
|
|
hooks map[string]*current.Hook
|
|
directories []string
|
|
lock sync.Mutex
|
|
}
|
|
|
|
// New creates a new hook manager. Directories are ordered by
|
|
// increasing preference (hook configurations in later directories
|
|
// override configurations with the same filename from earlier
|
|
// directories).
|
|
func New(ctx context.Context, directories []string) (manager *Manager, err error) {
|
|
manager = &Manager{
|
|
hooks: map[string]*current.Hook{},
|
|
directories: directories,
|
|
}
|
|
|
|
for _, dir := range directories {
|
|
err = ReadDir(dir, manager.hooks)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return manager, nil
|
|
}
|
|
|
|
// Hooks injects OCI runtime hooks for a given container configuration.
|
|
func (m *Manager) Hooks(config *rspec.Spec, annotations map[string]string, hasBindMounts bool) (err error) {
|
|
m.lock.Lock()
|
|
defer m.lock.Unlock()
|
|
for name, hook := range m.hooks {
|
|
match, err := hook.When.Match(config, annotations, hasBindMounts)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "matching hook %q", name)
|
|
}
|
|
if match {
|
|
if config.Hooks == nil {
|
|
config.Hooks = &rspec.Hooks{}
|
|
}
|
|
for _, stage := range hook.Stages {
|
|
switch stage {
|
|
case "prestart":
|
|
config.Hooks.Prestart = append(config.Hooks.Prestart, hook.Hook)
|
|
case "poststart":
|
|
config.Hooks.Poststart = append(config.Hooks.Poststart, hook.Hook)
|
|
case "poststop":
|
|
config.Hooks.Poststop = append(config.Hooks.Poststop, hook.Hook)
|
|
default:
|
|
return fmt.Errorf("hook %q: unknown stage %q", name, stage)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// remove remove a hook by name.
|
|
func (m *Manager) remove(hook string) (ok bool) {
|
|
m.lock.Lock()
|
|
defer m.lock.Unlock()
|
|
_, ok = m.hooks[hook]
|
|
if ok {
|
|
delete(m.hooks, hook)
|
|
}
|
|
return ok
|
|
}
|
|
|
|
// add adds a hook by path
|
|
func (m *Manager) add(path string) (err error) {
|
|
m.lock.Lock()
|
|
defer m.lock.Unlock()
|
|
hook, err := Read(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m.hooks[filepath.Base(path)] = hook
|
|
return nil
|
|
}
|