(ctx context.Context, uid, gid int)
| 81 | } |
| 82 | |
| 83 | func (s *LifecycleScript) Execute(ctx context.Context, uid, gid int) error { |
| 84 | procAttr := &syscall.ProcAttr{ |
| 85 | Env: os.Environ(), |
| 86 | Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()}, |
| 87 | Sys: &syscall.SysProcAttr{ |
| 88 | Credential: &syscall.Credential{ |
| 89 | Uid: uint32(uid), |
| 90 | Gid: uint32(gid), |
| 91 | }, |
| 92 | }, |
| 93 | } |
| 94 | |
| 95 | var eg errgroup.Group |
| 96 | for desc, command := range s.shellCommands { |
| 97 | desc := desc |
| 98 | command := command |
| 99 | eg.Go(func() error { |
| 100 | pid, err := syscall.ForkExec("/bin/sh", []string{"/bin/sh", "-c", command}, procAttr) |
| 101 | if err != nil { |
| 102 | return fmt.Errorf("lifecycle command %q failed: %v", desc, err) |
| 103 | } |
| 104 | return waitForCommand(desc, pid) |
| 105 | }) |
| 106 | } |
| 107 | |
| 108 | for desc, commandAndArgs := range s.nonShellCommands { |
| 109 | desc := desc |
| 110 | commandAndArgs := commandAndArgs |
| 111 | eg.Go(func() error { |
| 112 | path, err := exec.LookPath(commandAndArgs[0]) |
| 113 | if err != nil { |
| 114 | return err |
| 115 | } |
| 116 | pid, err := syscall.ForkExec(path, commandAndArgs, procAttr) |
| 117 | if err != nil { |
| 118 | return fmt.Errorf("failed to exec lifecycle command %q: %v", desc, err) |
| 119 | } |
| 120 | return waitForCommand(desc, pid) |
| 121 | }) |
| 122 | } |
| 123 | |
| 124 | return eg.Wait() |
| 125 | } |
| 126 | |
| 127 | func waitForCommand(desc string, pid int) error { |
| 128 | process, err := os.FindProcess(pid) |
no test coverage detected