mirror of
				https://github.com/containers/podman.git
				synced 2025-11-04 17:07:20 +08:00 
			
		
		
		
	Add support for the missing hook types [1]:
- createContainer
- createRuntime
- startContainer
Otherwise, Podman won't inject them into the runtime config (and pass it
on to runc/crun) but error out.
[1] 44341cdd36/runtime.md (lifecycle)
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
		
	
		
			
				
	
	
		
			147 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Package hooks implements hook configuration and handling for CRI-O and libpod.
 | 
						|
package hooks
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
 | 
						|
	current "github.com/containers/podman/v2/pkg/hooks/1.0.0"
 | 
						|
	rspec "github.com/opencontainers/runtime-spec/specs-go"
 | 
						|
	"github.com/pkg/errors"
 | 
						|
	"github.com/sirupsen/logrus"
 | 
						|
)
 | 
						|
 | 
						|
// 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
 | 
						|
	extensionStages []string
 | 
						|
	lock            sync.Mutex
 | 
						|
}
 | 
						|
 | 
						|
type namedHook struct {
 | 
						|
	name string
 | 
						|
	hook *current.Hook
 | 
						|
}
 | 
						|
 | 
						|
// 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).
 | 
						|
//
 | 
						|
// extensionStages allows callers to add additional stages beyond
 | 
						|
// those specified in the OCI Runtime Specification and to control
 | 
						|
// OCI-defined stages instead of delagating to the OCI runtime.  See
 | 
						|
// Hooks() for more information.
 | 
						|
func New(ctx context.Context, directories []string, extensionStages []string) (manager *Manager, err error) {
 | 
						|
	manager = &Manager{
 | 
						|
		hooks:           map[string]*current.Hook{},
 | 
						|
		directories:     directories,
 | 
						|
		extensionStages: extensionStages,
 | 
						|
	}
 | 
						|
 | 
						|
	for _, dir := range directories {
 | 
						|
		err = ReadDir(dir, manager.extensionStages, manager.hooks)
 | 
						|
		if err != nil && !os.IsNotExist(err) {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return manager, nil
 | 
						|
}
 | 
						|
 | 
						|
// filenames returns sorted hook entries.
 | 
						|
func (m *Manager) namedHooks() (hooks []*namedHook) {
 | 
						|
	m.lock.Lock()
 | 
						|
	defer m.lock.Unlock()
 | 
						|
 | 
						|
	hooks = make([]*namedHook, len(m.hooks))
 | 
						|
	i := 0
 | 
						|
	for name, hook := range m.hooks {
 | 
						|
		hooks[i] = &namedHook{
 | 
						|
			name: name,
 | 
						|
			hook: hook,
 | 
						|
		}
 | 
						|
		i++
 | 
						|
	}
 | 
						|
 | 
						|
	return hooks
 | 
						|
}
 | 
						|
 | 
						|
// Hooks injects OCI runtime hooks for a given container configuration.
 | 
						|
//
 | 
						|
// If extensionStages was set when initializing the Manager,
 | 
						|
// matching hooks requesting those stages will be returned in
 | 
						|
// extensionStageHooks.  This takes precedence over their inclusion in
 | 
						|
// the OCI configuration.  For example:
 | 
						|
//
 | 
						|
//   manager, err := New(ctx, []string{DefaultDir}, []string{"poststop"})
 | 
						|
//   extensionStageHooks, err := manager.Hooks(config, annotations, hasBindMounts)
 | 
						|
//
 | 
						|
// will have any matching post-stop hooks in extensionStageHooks and
 | 
						|
// will not insert them into config.Hooks.Poststop.
 | 
						|
func (m *Manager) Hooks(config *rspec.Spec, annotations map[string]string, hasBindMounts bool) (extensionStageHooks map[string][]rspec.Hook, err error) {
 | 
						|
	hooks := m.namedHooks()
 | 
						|
	sort.Slice(hooks, func(i, j int) bool { return strings.ToLower(hooks[i].name) < strings.ToLower(hooks[j].name) })
 | 
						|
	localStages := map[string]bool{} // stages destined for extensionStageHooks
 | 
						|
	for _, stage := range m.extensionStages {
 | 
						|
		localStages[stage] = true
 | 
						|
	}
 | 
						|
	for _, namedHook := range hooks {
 | 
						|
		match, err := namedHook.hook.When.Match(config, annotations, hasBindMounts)
 | 
						|
		if err != nil {
 | 
						|
			return extensionStageHooks, errors.Wrapf(err, "matching hook %q", namedHook.name)
 | 
						|
		}
 | 
						|
		if match {
 | 
						|
			logrus.Debugf("hook %s matched; adding to stages %v", namedHook.name, namedHook.hook.Stages)
 | 
						|
			if config.Hooks == nil {
 | 
						|
				config.Hooks = &rspec.Hooks{}
 | 
						|
			}
 | 
						|
			for _, stage := range namedHook.hook.Stages {
 | 
						|
				if _, ok := localStages[stage]; ok {
 | 
						|
					if extensionStageHooks == nil {
 | 
						|
						extensionStageHooks = map[string][]rspec.Hook{}
 | 
						|
					}
 | 
						|
					extensionStageHooks[stage] = append(extensionStageHooks[stage], namedHook.hook.Hook)
 | 
						|
				} else {
 | 
						|
					switch stage {
 | 
						|
					case "createContainer":
 | 
						|
						config.Hooks.CreateContainer = append(config.Hooks.CreateContainer, namedHook.hook.Hook)
 | 
						|
					case "createRuntime":
 | 
						|
						config.Hooks.CreateRuntime = append(config.Hooks.CreateRuntime, namedHook.hook.Hook)
 | 
						|
					case "prestart":
 | 
						|
						config.Hooks.Prestart = append(config.Hooks.Prestart, namedHook.hook.Hook)
 | 
						|
					case "poststart":
 | 
						|
						config.Hooks.Poststart = append(config.Hooks.Poststart, namedHook.hook.Hook)
 | 
						|
					case "poststop":
 | 
						|
						config.Hooks.Poststop = append(config.Hooks.Poststop, namedHook.hook.Hook)
 | 
						|
					case "startContainer":
 | 
						|
						config.Hooks.StartContainer = append(config.Hooks.StartContainer, namedHook.hook.Hook)
 | 
						|
					default:
 | 
						|
						return extensionStageHooks, fmt.Errorf("hook %q: unknown stage %q", namedHook.name, stage)
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			logrus.Debugf("hook %s did not match", namedHook.name)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return extensionStageHooks, nil
 | 
						|
}
 |