github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/hooks/1.0.0/hook.go (about) 1 // Package hook is the 1.0.0 hook configuration structure. 2 package hook 3 4 import ( 5 "encoding/json" 6 "fmt" 7 "os" 8 "regexp" 9 10 rspec "github.com/opencontainers/runtime-spec/specs-go" 11 "github.com/pkg/errors" 12 ) 13 14 // Version is the hook configuration version defined in this package. 15 const Version = "1.0.0" 16 17 // Hook is the hook configuration structure. 18 type Hook struct { 19 Version string `json:"version"` 20 Hook rspec.Hook `json:"hook"` 21 When When `json:"when"` 22 Stages []string `json:"stages"` 23 } 24 25 // Read reads hook JSON bytes, verifies them, and returns the hook configuration. 26 func Read(content []byte) (hook *Hook, err error) { 27 if err = json.Unmarshal(content, &hook); err != nil { 28 return nil, err 29 } 30 return hook, nil 31 } 32 33 // Validate performs load-time hook validation. 34 func (hook *Hook) Validate(extensionStages []string) (err error) { 35 if hook == nil { 36 return errors.New("nil hook") 37 } 38 39 if hook.Version != Version { 40 return fmt.Errorf("unexpected hook version %q (expecting %v)", hook.Version, Version) 41 } 42 43 if hook.Hook.Path == "" { 44 return errors.New("missing required property: hook.path") 45 } 46 47 if _, err := os.Stat(hook.Hook.Path); err != nil { 48 return err 49 } 50 51 for key, value := range hook.When.Annotations { 52 if _, err = regexp.Compile(key); err != nil { 53 return errors.Wrapf(err, "invalid annotation key %q", key) 54 } 55 if _, err = regexp.Compile(value); err != nil { 56 return errors.Wrapf(err, "invalid annotation value %q", value) 57 } 58 } 59 60 for _, command := range hook.When.Commands { 61 if _, err = regexp.Compile(command); err != nil { 62 return errors.Wrapf(err, "invalid command %q", command) 63 } 64 } 65 66 if hook.Stages == nil { 67 return errors.New("missing required property: stages") 68 } 69 70 validStages := map[string]bool{ 71 "createContainer": true, 72 "createRuntime": true, 73 "prestart": true, 74 "poststart": true, 75 "poststop": true, 76 "startContainer": true, 77 } 78 for _, stage := range extensionStages { 79 validStages[stage] = true 80 } 81 82 for _, stage := range hook.Stages { 83 if !validStages[stage] { 84 return fmt.Errorf("unknown stage %q", stage) 85 } 86 } 87 88 return nil 89 }