func New(proxySignals <-chan os.Signal, runner ifrit.Runner) ifrit.Runner { return ifrit.RunFunc(func(signals <-chan os.Signal, ready chan<- struct{}) error { process := ifrit.Background(runner) <-process.Ready() close(ready) go forwardSignals(proxySignals, process) go forwardSignals(signals, process) return <-process.Wait() }) }
return p, true } func (p PingChan) Run(sigChan <-chan os.Signal, ready chan<- struct{}) error { close(ready) select { case <-sigChan: return PingerExitedFromSignal case p <- Ping{}: return PingerExitedFromPing } } // NoReadyRunner exits without closing the ready chan var NoReadyRunner = ifrit.RunFunc(func(sigChan <-chan os.Signal, ready chan<- struct{}) error { return NoReadyExitedNormally }) var NoReadyExitedNormally = errors.New("no ready exited normally") // SignalRecoder records all signals received, and exits on a set of signals. type SignalRecoder struct { sync.RWMutex signals []os.Signal exitSignals map[os.Signal]struct{} } func NewSignalRecorder(exitSignals ...os.Signal) *SignalRecoder { exitSignals = append(exitSignals, os.Kill, os.Interrupt) signalSet := map[os.Signal]struct{}{}
Describe("Stop", func() { var runnerIndex int64 var startOrder chan int64 var stopOrder chan int64 makeRunner := func(waitTime time.Duration) (ifrit.Runner, chan struct{}) { quickExit := make(chan struct{}) return ifrit.RunFunc(func(signals <-chan os.Signal, ready chan<- struct{}) error { index := atomic.AddInt64(&runnerIndex, 1) startOrder <- index close(ready) select { case <-quickExit: case <-signals: } time.Sleep(waitTime) stopOrder <- index return nil }), quickExit } BeforeEach(func() { startOrder = make(chan int64, 3) stopOrder = make(chan int64, 3) r1, _ := makeRunner(0) r2, _ := makeRunner(30 * time.Millisecond) r3, _ := makeRunner(50 * time.Millisecond)
var ( lifecycle ifrit.Process fakeDeamonRunner func(signals <-chan os.Signal, ready chan<- struct{}) error ) BeforeEach(func() { builder := main.Builder{ RepoName: "ubuntu", Tag: "latest", OutputFilename: "/tmp/result/result.json", DockerDaemonTimeout: 300 * time.Millisecond, CacheDockerImage: true, } lifecycle = ifrit.Background(grouper.NewParallel(os.Interrupt, grouper.Members{ {"builder", ifrit.RunFunc(builder.Run)}, {"fake_docker_daemon", ifrit.RunFunc(fakeDeamonRunner)}, })) }) AfterEach(func() { ginkgomon.Interrupt(lifecycle) }) Context("when the daemon won't start", func() { fakeDeamonRunner = func(signals <-chan os.Signal, ready chan<- struct{}) error { close(ready) select { case signal := <-signals: return errors.New(signal.String()) case <-time.After(1 * time.Second):
func main() { var insecureDockerRegistries registries var dockerRegistryIPs ips flagSet := flag.NewFlagSet("builder", flag.ExitOnError) dockerImageURL := flagSet.String( "dockerImageURL", "", "docker image uri in docker://[registry/][scope/]repository[#tag] format", ) dockerRef := flagSet.String( "dockerRef", "", "docker image reference in standard docker string format", ) outputFilename := flagSet.String( "outputMetadataJSONFilename", "/tmp/result/result.json", "filename in which to write the app metadata", ) flagSet.Var( &insecureDockerRegistries, "insecureDockerRegistries", "insecure Docker Registry addresses (host:port)", ) dockerDaemonExecutablePath := flagSet.String( "dockerDaemonExecutablePath", "/tmp/docker_app_lifecycle/docker", "path to the 'docker' executable", ) cacheDockerImage := flagSet.Bool( "cacheDockerImage", false, "Caches Docker images to private docker registry", ) flagSet.Var( &dockerRegistryIPs, "dockerRegistryIPs", "Docker Registry IPs", ) dockerRegistryHost := flagSet.String( "dockerRegistryHost", "", "Docker Registry host", ) dockerRegistryPort := flagSet.Int( "dockerRegistryPort", 8080, "Docker Registry port", ) dockerLoginServer := flagSet.String( "dockerLoginServer", registry.IndexServerAddress(), "Docker Login server address", ) dockerUser := flagSet.String( "dockerUser", "", "User for pulling from docker registry", ) dockerPassword := flagSet.String( "dockerPassword", "", "Password for pulling from docker registry", ) dockerEmail := flagSet.String( "dockerEmail", "", "Email for pulling from docker registry", ) if err := flagSet.Parse(os.Args[1:len(os.Args)]); err != nil { println(err.Error()) os.Exit(1) } var repoName string var tag string if len(*dockerImageURL) > 0 { parts, err := url.Parse(*dockerImageURL) if err != nil { println("invalid dockerImageURL: " + *dockerImageURL) flagSet.PrintDefaults() os.Exit(1) } repoName, tag = helpers.ParseDockerURL(parts) } else if len(*dockerRef) > 0 { repoName, tag = helpers.ParseDockerRef(*dockerRef) } else { println("missing flag: dockerImageURL or dockerRef required") flagSet.PrintDefaults() os.Exit(1) } builder := Builder{ RepoName: repoName, Tag: tag, OutputFilename: *outputFilename, DockerDaemonExecutablePath: *dockerDaemonExecutablePath, InsecureDockerRegistries: insecureDockerRegistries, DockerDaemonTimeout: 10 * time.Second, CacheDockerImage: *cacheDockerImage, DockerRegistryIPs: dockerRegistryIPs, DockerRegistryHost: *dockerRegistryHost, DockerRegistryPort: *dockerRegistryPort, DockerLoginServer: *dockerLoginServer, DockerUser: *dockerUser, DockerPassword: *dockerPassword, DockerEmail: *dockerEmail, } members := grouper.Members{ {"builder", ifrit.RunFunc(builder.Run)}, } if *cacheDockerImage { if len(dockerRegistryIPs) == 0 { println("missing flag: dockerRegistryIPs required") os.Exit(1) } if len(*dockerRegistryHost) == 0 { println("missing flag: dockerRegistryHost required") os.Exit(1) } if strings.Contains(*dockerRegistryHost, ":") { println("invalid host format", *dockerRegistryHost) os.Exit(1) } if *dockerRegistryPort < 0 { println("negative port number", *dockerRegistryPort) os.Exit(1) } if *dockerRegistryPort > 65535 { println("port number too big", *dockerRegistryPort) os.Exit(1) } validateCredentials(*dockerLoginServer, *dockerUser, *dockerPassword, *dockerEmail) if _, err := os.Stat(*dockerDaemonExecutablePath); err != nil { println("docker daemon not found in", *dockerDaemonExecutablePath) os.Exit(1) } dockerDaemon := DockerDaemon{ DockerDaemonPath: *dockerDaemonExecutablePath, InsecureDockerRegistries: insecureDockerRegistries, DockerRegistryIPs: dockerRegistryIPs, DockerRegistryHost: *dockerRegistryHost, } members = append(members, grouper.Member{"docker_daemon", ifrit.RunFunc(dockerDaemon.Run)}) } group := grouper.NewParallel(os.Interrupt, members) process := ifrit.Invoke(sigmon.New(group)) fmt.Println("Staging process started ...") err := <-process.Wait() if err != nil { println("Staging process failed:", err.Error()) os.Exit(2) } fmt.Println("Staging process finished") }