Merge pull request #194 from thockin/fix-pid1

Handle running as PID 1
This commit is contained in:
Kubernetes Prow Robot 2019-10-28 15:52:43 -07:00 committed by GitHub
commit 012d0bfbf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 4 deletions

View File

@ -14,10 +14,6 @@
FROM {ARG_FROM} FROM {ARG_FROM}
MAINTAINER Tim Hockin <thockin@google.com>
ADD bin/{ARG_OS}_{ARG_ARCH}/{ARG_BIN} /{ARG_BIN}
RUN apt-get update \ RUN apt-get update \
&& apt-get -y install \ && apt-get -y install \
ca-certificates \ ca-certificates \
@ -28,6 +24,8 @@ RUN apt-get update \
RUN echo "git-sync:x:65533:65533::/tmp:/sbin/nologin" >> /etc/passwd RUN echo "git-sync:x:65533:65533::/tmp:/sbin/nologin" >> /etc/passwd
ADD bin/{ARG_OS}_{ARG_ARCH}/{ARG_BIN} /{ARG_BIN}
WORKDIR /tmp WORKDIR /tmp
USER git-sync:nogroup USER git-sync:nogroup
ENTRYPOINT ["/{ARG_BIN}"] ENTRYPOINT ["/{ARG_BIN}"]

View File

@ -40,6 +40,7 @@ import (
"github.com/go-logr/glogr" "github.com/go-logr/glogr"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"k8s.io/git-sync/pkg/pid1"
"k8s.io/git-sync/pkg/version" "k8s.io/git-sync/pkg/version"
) )
@ -187,6 +188,20 @@ func envDuration(key string, def time.Duration) time.Duration {
} }
func main() { func main() {
// In case we come up as pid 1, act as init.
if os.Getpid() == 1 {
fmt.Fprintf(os.Stderr, "INFO: detected pid 1, running init handler\n")
err := pid1.ReRun()
if err == nil {
os.Exit(0)
}
if exerr, ok := err.(*exec.ExitError); ok {
os.Exit(exerr.ExitCode())
}
fmt.Fprintf(os.Stderr, "ERROR: unhandled pid1 error: %v\n", err)
os.Exit(127)
}
setFlagDefaults() setFlagDefaults()
flag.Parse() flag.Parse()
@ -201,15 +216,18 @@ func main() {
flag.Usage() flag.Usage()
os.Exit(1) os.Exit(1)
} }
if *flDest == "" { if *flDest == "" {
parts := strings.Split(strings.Trim(*flRepo, "/"), "/") parts := strings.Split(strings.Trim(*flRepo, "/"), "/")
*flDest = parts[len(parts)-1] *flDest = parts[len(parts)-1]
} }
if strings.Contains(*flDest, "/") { if strings.Contains(*flDest, "/") {
fmt.Fprintf(os.Stderr, "ERROR: --dest must be a bare name\n") fmt.Fprintf(os.Stderr, "ERROR: --dest must be a bare name\n")
flag.Usage() flag.Usage()
os.Exit(1) os.Exit(1)
} }
if _, err := exec.LookPath(*flGitCmd); err != nil { if _, err := exec.LookPath(*flGitCmd); err != nil {
fmt.Fprintf(os.Stderr, "ERROR: git executable %q not found: %v\n", *flGitCmd, err) fmt.Fprintf(os.Stderr, "ERROR: git executable %q not found: %v\n", *flGitCmd, err)
os.Exit(1) os.Exit(1)

62
pkg/pid1/pid1.go Normal file
View File

@ -0,0 +1,62 @@
package pid1
import (
"fmt"
"os"
"os/exec"
"os/signal"
"syscall"
)
// ReRun converts the current process into a bare-bones init, runs the current
// commandline as a child process, and waits for it to complete. The new child
// process shares stdin/stdout/stderr with the parent. When the child exits,
// this will return the same value as exec.Command.Run(). If there is an error
// in reaping children that this can not handle, it will panic.
func ReRun() error {
bin, err := os.Readlink("/proc/self/exe")
if err != nil {
return err
}
cmd := exec.Command(bin, os.Args[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
return err
}
go runInit(cmd.Process.Pid)
return cmd.Wait()
}
// runInit runs a bare-bones init process. This will never return. In case of
// truly unknown errors it will panic.
func runInit(pid int) {
sigs := make(chan os.Signal, 8)
signal.Notify(sigs)
for sig := range sigs {
if sig == syscall.SIGCHLD {
sigchld()
} else {
// Pass it on to the real process.
syscall.Kill(pid, sig.(syscall.Signal))
}
}
}
// sigchld handles a SIGCHLD.
func sigchld() {
// Loop to handle multiple child processes.
for {
var status syscall.WaitStatus
pid, err := syscall.Wait4(-1, &status, syscall.WNOHANG, nil)
if err != nil {
panic(fmt.Sprintf("failed to wait4(): %v\n", err))
}
if pid <= 0 {
// No more children to reap.
break
}
// Must have found one, see if there are more.
}
}