diff --git a/Makefile b/Makefile index 200a5ecb9..42f4b8e86 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SCOPE_BACKEND_BUILD_UPTODATE=.scope_backend_build.uptodate SCOPE_VERSION=$(shell git rev-parse --short HEAD) GIT_REVISION=$(shell git rev-parse HEAD) WEAVENET_VERSION=2.1.3 -RUNSVINIT=vendor/runsvinit/runsvinit +RUNSVINIT=vendor/github.com/peterbourgon/runsvinit/runsvinit CODECGEN_DIR=vendor/github.com/ugorji/go/codec/codecgen CODECGEN_EXE=$(CODECGEN_DIR)/bin/codecgen_$(shell go env GOHOSTOS)_$(shell go env GOHOSTARCH) CODECGEN_UID=0 @@ -74,7 +74,7 @@ $(CLOUD_AGENT_EXPORT): docker/Dockerfile.cloud-agent docker/$(SCOPE_EXE) docker/ $(SCOPE_EXPORT): docker/Dockerfile.scope $(CLOUD_AGENT_EXPORT) docker/$(RUNSVINIT) docker/demo.json docker/run-app docker/run-probe docker/entrypoint.sh -$(RUNSVINIT): vendor/runsvinit/*.go +$(RUNSVINIT): vendor/github.com/peterbourgon/runsvinit/*.go $(SCOPE_EXE): $(shell find ./ -path ./vendor -prune -o -type f -name '*.go') prog/staticui/staticui.go prog/externalui/externalui.go $(CODECGEN_TARGETS) diff --git a/go.mod b/go.mod index c40853b0b..3d8e24f85 100644 --- a/go.mod +++ b/go.mod @@ -121,6 +121,7 @@ require ( github.com/performancecopilot/speed v3.0.1-0.20180614024626-d49dd9b77adc+incompatible // indirect github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c // indirect github.com/peterbourgon/diskv v2.0.2-0.20171120014656-2973218375c3+incompatible // indirect + github.com/peterbourgon/runsvinit v2.0.0+incompatible github.com/philhofer/fwd v0.0.0-20160129035939-98c11a7a6ec8 // indirect github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v0.9.2 diff --git a/go.sum b/go.sum index 72328948f..3ea077cda 100644 --- a/go.sum +++ b/go.sum @@ -239,6 +239,8 @@ github.com/performancecopilot/speed v3.0.1-0.20180614024626-d49dd9b77adc+incompa github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod h1:HUpKUBZnpzkdx0kD/+Yfuft+uD3zHGtXF/XJB14TUr4= github.com/peterbourgon/diskv v2.0.2-0.20171120014656-2973218375c3+incompatible h1:vC4yEuGvpjMoHhoIU9DYQJBvtQ5e0efvMVxpEYCWHzw= github.com/peterbourgon/diskv v2.0.2-0.20171120014656-2973218375c3+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/peterbourgon/runsvinit v2.0.0+incompatible h1:j6URJ2gUTfZbMBM1AnkJ7M82lQxawZm4LonASHXSu94= +github.com/peterbourgon/runsvinit v2.0.0+incompatible/go.mod h1:cvlRM1j2aaGjcgVMMBX+uKbUFZkRL/2pA/RGE6Piv/M= github.com/philhofer/fwd v0.0.0-20160129035939-98c11a7a6ec8 h1:jkUFVqrKRttbdDqkTrvOmHxfqIsJK0Oe2WGi1ACAE+M= github.com/philhofer/fwd v0.0.0-20160129035939-98c11a7a6ec8/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/prog/tools.go b/prog/tools.go new file mode 100644 index 000000000..6aefa1c1b --- /dev/null +++ b/prog/tools.go @@ -0,0 +1,9 @@ +// Ensure go mod fetches files needed to build the Docker container; +// the build constraint ensures this file is ignored +// +build tools + +package report + +import ( + _ "github.com/peterbourgon/runsvinit" +) diff --git a/vendor/github.com/peterbourgon/runsvinit/.gitignore b/vendor/github.com/peterbourgon/runsvinit/.gitignore new file mode 100644 index 000000000..552a1b1c4 --- /dev/null +++ b/vendor/github.com/peterbourgon/runsvinit/.gitignore @@ -0,0 +1,28 @@ +runsvinit +runsvinit-*-* +examples/runsvinit-linux-amd64* + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/peterbourgon/runsvinit/LICENSE b/vendor/github.com/peterbourgon/runsvinit/LICENSE new file mode 100644 index 000000000..9d83342ac --- /dev/null +++ b/vendor/github.com/peterbourgon/runsvinit/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Peter Bourgon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/github.com/peterbourgon/runsvinit/README.md b/vendor/github.com/peterbourgon/runsvinit/README.md new file mode 100644 index 000000000..7663aeb4d --- /dev/null +++ b/vendor/github.com/peterbourgon/runsvinit/README.md @@ -0,0 +1,43 @@ +# runsvinit + +If you have a Docker container that's a collection of runit-supervised daemons, +this process is suitable for use as the ENTRYPOINT. +See [the example](https://github.com/peterbourgon/runsvinit/tree/master/example). + +**Why not just exec runsvdir?** + +`docker stop` issues SIGTERM (or, in a future version of Docker, perhaps another custom signal) +but if runsvdir receives a signal, +it doesn't wait for its supervised processes to exit before returning. +If you don't care about graceful shutdown of your daemons, no problem, you don't need this tool. + +**Why not wrap runsvdir in a simple shell script?** + +This works great: + +```sh +#!/bin/sh + +sv_stop() { + for s in $(ls -d /etc/service/*) + do + /sbin/sv stop $s + done +} + +trap "sv_stop; exit" SIGTERM +/sbin/runsvdir /etc/service & +wait +``` + +...except it doesn't [reap orphaned child processes](https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/) +and is therefore unsuitable for being PID 1. + +**Why not use my_init from [phusion/baseimage-docker](https://github.com/phusion/baseimage-docker)?** + +That works great — if you're willing to add python3 to your Docker images :) + +**So this is just a stripped-down my_init in Go?** + +Basically, yes. + diff --git a/vendor/github.com/peterbourgon/runsvinit/main.go b/vendor/github.com/peterbourgon/runsvinit/main.go new file mode 100644 index 000000000..93b8af128 --- /dev/null +++ b/vendor/github.com/peterbourgon/runsvinit/main.go @@ -0,0 +1,136 @@ +package main + +import ( + "log" + "os" + "os/exec" + "os/signal" + "path/filepath" + "strings" + "syscall" +) + +const etcService = "/etc/service" + +func main() { + log.SetFlags(0) + + runsvdir, err := exec.LookPath("runsvdir") + if err != nil { + log.Fatal(err) + } + + sv, err := exec.LookPath("sv") + if err != nil { + log.Fatal(err) + } + + if fi, err := os.Stat(etcService); err != nil { + log.Fatal(err) + } else if !fi.IsDir() { + log.Fatalf("%s is not a directory", etcService) + } + + if pid := os.Getpid(); pid != 1 { + log.Printf("warning: I'm not PID 1, I'm PID %d", pid) + } + + go reapAll() + + supervisor := cmd(runsvdir, etcService) + if err := supervisor.Start(); err != nil { + log.Fatal(err) + } + + log.Printf("%s started", runsvdir) + + go shutdown(sv, supervisor.Process) + + if err := supervisor.Wait(); err != nil { + log.Printf("%s exited with error: %v", runsvdir, err) + } else { + log.Printf("%s exited cleanly", runsvdir) + } +} + +func reapAll() { + c := make(chan os.Signal) + signal.Notify(c, syscall.SIGCHLD) + for range c { + go reapOne() + } +} + +// From https://github.com/ramr/go-reaper/blob/master/reaper.go +func reapOne() { + var ( + ws syscall.WaitStatus + pid int + err error + ) + for { + pid, err = syscall.Wait4(-1, &ws, 0, nil) + if err != syscall.EINTR { + break + } + } + if err == syscall.ECHILD { + return + } + log.Printf("reaped child process %d (%+v)", pid, ws) +} + +type signaler interface { + Signal(os.Signal) error +} + +func shutdown(sv string, s signaler) { + c := make(chan os.Signal) + signal.Notify(c, syscall.SIGTERM, syscall.SIGINT) + sig := <-c + log.Printf("received %s", sig) + + matches, err := filepath.Glob(filepath.Join(etcService, "*")) + if err != nil { + log.Printf("when shutting down services: %v", err) + return + } + + var stopped []string + for _, match := range matches { + fi, err := os.Stat(match) + if err != nil { + log.Printf("%s: %v", match, err) + continue + } + if !fi.IsDir() { + log.Printf("%s: not a directory", match) + continue + } + service := filepath.Base(match) + stop := cmd(sv, "stop", service) + if err := stop.Run(); err != nil { + log.Printf("%s: %v", strings.Join(stop.Args, " "), err) + continue + } + stopped = append(stopped, service) + } + + log.Printf("stopped %d: %s", len(stopped), strings.Join(stopped, ", ")) + log.Printf("stopping supervisor with signal %s...", sig) + if err := s.Signal(sig); err != nil { + log.Print(err) + } + log.Printf("shutdown handler exiting") +} + +func cmd(path string, args ...string) *exec.Cmd { + return &exec.Cmd{ + Path: path, + Args: append([]string{path}, args...), + Env: os.Environ(), + Stdin: os.Stdin, + Stdout: os.Stdout, + Stderr: os.Stderr, + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index b399b9a6a..677390c41 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -227,6 +227,8 @@ github.com/paypal/ionet github.com/pborman/uuid # github.com/peterbourgon/diskv v2.0.2-0.20171120014656-2973218375c3+incompatible github.com/peterbourgon/diskv +# github.com/peterbourgon/runsvinit v2.0.0+incompatible +github.com/peterbourgon/runsvinit # github.com/philhofer/fwd v0.0.0-20160129035939-98c11a7a6ec8 github.com/philhofer/fwd # github.com/pkg/errors v0.8.1