From 57e23d3c3cecbea762158dc9465df399b1684a4b Mon Sep 17 00:00:00 2001 From: Matthew Sykes Date: Mon, 26 Mar 2018 14:40:40 -0400 Subject: [PATCH] [FAB-9167] builds check for stale deps Change-Id: I4cab5a8843612e831ee0f9f89dbd1a4129979a35 Signed-off-by: Matthew Sykes --- Gopkg.lock | 8 +- Gopkg.toml | 23 +- Makefile | 13 +- gotools/Makefile | 9 + images/buildenv/Dockerfile.in | 2 +- scripts/check_deps.sh | 8 + vendor/github.com/tedsuo/ifrit/LICENSE | 21 -- vendor/github.com/tedsuo/ifrit/doc.go | 25 -- .../tedsuo/ifrit/fake_runner/doc.go | 2 - .../tedsuo/ifrit/fake_runner/fake_runner.go | 56 ----- .../tedsuo/ifrit/fake_runner/test_runner.go | 50 ---- .../tedsuo/ifrit/ginkgomon/ginkgomon.go | 161 ------------- .../tedsuo/ifrit/ginkgomon/helpers.go | 36 --- .../github.com/tedsuo/ifrit/grouper/client.go | 153 ------------- vendor/github.com/tedsuo/ifrit/grouper/doc.go | 31 --- .../tedsuo/ifrit/grouper/dynamic_group.go | 214 ------------------ .../tedsuo/ifrit/grouper/entrance_events.go | 74 ------ .../tedsuo/ifrit/grouper/exit_events.go | 97 -------- .../tedsuo/ifrit/grouper/members.go | 71 ------ .../tedsuo/ifrit/grouper/ordered.go | 189 ---------------- .../tedsuo/ifrit/grouper/parallel.go | 195 ---------------- .../tedsuo/ifrit/grouper/sliding_buffer.go | 35 --- .../tedsuo/ifrit/grpc_server/server.go | 120 ---------- .../tedsuo/ifrit/http_server/http_server.go | 176 -------------- .../unix_transport/unix_transport.go | 105 --------- vendor/github.com/tedsuo/ifrit/process.go | 97 -------- vendor/github.com/tedsuo/ifrit/proxy/proxy.go | 30 --- .../tedsuo/ifrit/restart/restart.go | 63 ------ .../tedsuo/ifrit/restart/strategies.go | 22 -- vendor/github.com/tedsuo/ifrit/runner.go | 37 --- .../github.com/tedsuo/ifrit/sigmon/sigmon.go | 48 ---- .../tedsuo/ifrit/test_helpers/test_helpers.go | 85 ------- 32 files changed, 43 insertions(+), 2213 deletions(-) create mode 100755 scripts/check_deps.sh delete mode 100644 vendor/github.com/tedsuo/ifrit/LICENSE delete mode 100644 vendor/github.com/tedsuo/ifrit/doc.go delete mode 100644 vendor/github.com/tedsuo/ifrit/fake_runner/doc.go delete mode 100644 vendor/github.com/tedsuo/ifrit/fake_runner/fake_runner.go delete mode 100644 vendor/github.com/tedsuo/ifrit/fake_runner/test_runner.go delete mode 100644 vendor/github.com/tedsuo/ifrit/ginkgomon/ginkgomon.go delete mode 100644 vendor/github.com/tedsuo/ifrit/ginkgomon/helpers.go delete mode 100644 vendor/github.com/tedsuo/ifrit/grouper/client.go delete mode 100644 vendor/github.com/tedsuo/ifrit/grouper/doc.go delete mode 100644 vendor/github.com/tedsuo/ifrit/grouper/dynamic_group.go delete mode 100644 vendor/github.com/tedsuo/ifrit/grouper/entrance_events.go delete mode 100644 vendor/github.com/tedsuo/ifrit/grouper/exit_events.go delete mode 100644 vendor/github.com/tedsuo/ifrit/grouper/members.go delete mode 100644 vendor/github.com/tedsuo/ifrit/grouper/ordered.go delete mode 100644 vendor/github.com/tedsuo/ifrit/grouper/parallel.go delete mode 100644 vendor/github.com/tedsuo/ifrit/grouper/sliding_buffer.go delete mode 100644 vendor/github.com/tedsuo/ifrit/grpc_server/server.go delete mode 100644 vendor/github.com/tedsuo/ifrit/http_server/http_server.go delete mode 100644 vendor/github.com/tedsuo/ifrit/http_server/unix_transport/unix_transport.go delete mode 100644 vendor/github.com/tedsuo/ifrit/process.go delete mode 100644 vendor/github.com/tedsuo/ifrit/proxy/proxy.go delete mode 100644 vendor/github.com/tedsuo/ifrit/restart/restart.go delete mode 100644 vendor/github.com/tedsuo/ifrit/restart/strategies.go delete mode 100644 vendor/github.com/tedsuo/ifrit/runner.go delete mode 100644 vendor/github.com/tedsuo/ifrit/sigmon/sigmon.go delete mode 100644 vendor/github.com/tedsuo/ifrit/test_helpers/test_helpers.go diff --git a/Gopkg.lock b/Gopkg.lock index 7ecb8db9918..6fdce621941 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -396,12 +396,6 @@ ] revision = "169b1b37be738edb2813dab48c97a549bcf99bb5" -[[projects]] - branch = "master" - name = "github.com/tedsuo/ifrit" - packages = ["."] - revision = "d787ed1df88a79d9e9b1072738a40500b8ec22ee" - [[projects]] name = "github.com/uber-go/tally" packages = [ @@ -536,6 +530,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "d95a27d006fa56b1278f5c40b0b59fd19e1fa28a62707673894caee629bad4cb" + inputs-digest = "b0b0b643aaf74f16a90bdcb1c098b91de2efac530ce821431adff4710db5da2c" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 4297b667d5d..763fd2c2cf2 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -1,8 +1,19 @@ +# Copyright IBM Corp All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 + required = [ - "github.com/onsi/ginkgo", - "github.com/onsi/gomega", - "github.com/tedsuo/ifrit", - "github.com/golang/protobuf/protoc-gen-go" + "github.com/onsi/ginkgo", + "github.com/onsi/gomega", + "github.com/golang/protobuf/protoc-gen-go" +] + +# Need to ignore directories that are not ignored by default +ignored = [ + "github.com/hyperledger/fabric/build", + "github.com/hyperledger/fabric/build/*", + "github.com/hyperledger/fabric/gotools", + "github.com/hyperledger/fabric/gotools/*", ] [[constraint]] @@ -137,7 +148,3 @@ required = [ [[prune.project]] name = "github.com/onsi/gomega" unused-packages = false - - [[prune.project]] - name = "github.com/tedsuo/ifrit" - unused-packages = false \ No newline at end of file diff --git a/Makefile b/Makefile index 6582282eea6..60d275b0e76 100755 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ # - behave-deps - ensures pre-requisites are available for running behave manually # - gotools - installs go tools like golint # - linter - runs all code checks +# - check-deps - check for vendored dependencies that are no longer used # - license - checks go source files for Apache license header # - native - ensures all native binaries are available # - docker[-clean] - ensures all docker images are available[/cleaned] @@ -116,11 +117,11 @@ include docker-env.mk all: native docker checks -checks: license spelling linter unit-test +checks: basic-checks unit-test basic-checks: license spelling linter -desk-check: license spelling linter verify +desk-check: checks verify # Pull thirdparty docker images based on the latest baseimage release version .PHONY: docker-thirdparty @@ -197,7 +198,7 @@ profile: unit-test-clean peer-docker testenv # Generates a string to the terminal suitable for manual augmentation / re-issue, useful for running tests by hand test-cmd: - @echo "go test -tags \"$(GO_TAGS)\" + @echo "go test -tags \"$(GO_TAGS)\"" docker: docker-thirdparty $(patsubst %,build/image/%/$(DUMMY), $(IMAGES)) @@ -211,10 +212,14 @@ behave: behave-deps behave-peer-chaincode: build/bin/peer peer-docker orderer-docker @cd peer/chaincode && behave -linter: buildenv +linter: check-deps buildenv @echo "LINT: Running code checks.." @$(DRUN) $(DOCKER_NS)/fabric-buildenv:$(DOCKER_TAG) ./scripts/golinter.sh +check-deps: buildenv + @echo "DEP: Checking for dependency issues.." + @$(DRUN) $(DOCKER_NS)/fabric-buildenv:$(DOCKER_TAG) ./scripts/check_deps.sh + %/chaintool: Makefile @echo "Installing chaintool" @mkdir -p $(@D) diff --git a/gotools/Makefile b/gotools/Makefile index 0cf3a786052..3f2759cf2a2 100644 --- a/gotools/Makefile +++ b/gotools/Makefile @@ -48,6 +48,15 @@ gotool.ginkgo: @cp -R $(GOPATH)/src/github.com/hyperledger/fabric/vendor/github.com/onsi/ginkgo/* $(TMP_GOPATH)/src/github.com/onsi/ginkgo @GOPATH=$(abspath $(TMP_GOPATH)) go install github.com/onsi/ginkgo/ginkgo +# Lock to a versioned dep +gotool.dep: DEP_VERSION ?= "0.4.1" +gotool.dep: + @echo "Getting dep $(DEP_VERSION)" + @GOPATH=$(abspath $(TMP_GOPATH)) go get -d github.com/golang/dep + @cd $(abspath $(TMP_GOPATH)) git checkout $(DEP_VERSION) + @echo "Building github.com/golang/dep -> dep" + @GOPATH=$(abspath $(TMP_GOPATH)) go install -ldflags="-X main.version=$(DEP_VERSION) -X main.buildDate=$$(date '+%Y-%m-%d')" github.com/golang/dep/cmd/dep + # Default rule for gotools uses the name->path map for a generic 'go get' style build gotool.%: $(eval TOOL = ${subst gotool.,,${@}}) diff --git a/images/buildenv/Dockerfile.in b/images/buildenv/Dockerfile.in index cbbf07d1afe..fa1b5375e9a 100644 --- a/images/buildenv/Dockerfile.in +++ b/images/buildenv/Dockerfile.in @@ -1,7 +1,7 @@ # Copyright Greg Haskins All Rights Reserved # # SPDX-License-Identifier: Apache-2.0 -# + FROM _BASE_NS_/fabric-baseimage:_BASE_TAG_ COPY payload/protoc-gen-go /usr/local/bin/ ADD payload/gotools.tar.bz2 /usr/local/bin/ diff --git a/scripts/check_deps.sh b/scripts/check_deps.sh new file mode 100755 index 00000000000..2041aae6953 --- /dev/null +++ b/scripts/check_deps.sh @@ -0,0 +1,8 @@ +#!/bin/bash -e + +# Copyright IBM Corp All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +dep version +dep ensure --no-vendor --dry-run diff --git a/vendor/github.com/tedsuo/ifrit/LICENSE b/vendor/github.com/tedsuo/ifrit/LICENSE deleted file mode 100644 index 2c94255349b..00000000000 --- a/vendor/github.com/tedsuo/ifrit/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Theodore Young - -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/tedsuo/ifrit/doc.go b/vendor/github.com/tedsuo/ifrit/doc.go deleted file mode 100644 index bff8991cbf1..00000000000 --- a/vendor/github.com/tedsuo/ifrit/doc.go +++ /dev/null @@ -1,25 +0,0 @@ -/* -A process model for go. - -Ifrit is a small set of interfaces for composing single-purpose units of work -into larger programs. Users divide their program into single purpose units of -work, each of which implements the `Runner` interface Each `Runner` can be -invoked to create a `Process` which can be monitored and signaled to stop. - -The name Ifrit comes from a type of daemon in arabic folklore. It's a play on -the unix term 'daemon' to indicate a process that is managed by the init system. - -Ifrit ships with a standard library which contains packages for common -processes - http servers, integration test helpers - alongside packages which -model process supervision and orchestration. These packages can be combined to -form complex servers which start and shutdown cleanly. - -The advantage of small, single-responsibility processes is that they are simple, -and thus can be made reliable. Ifrit's interfaces are designed to be free -of race conditions and edge cases, allowing larger orcestrated process to also -be made reliable. The overall effect is less code and more reliability as your -system grows with grace. -*/ -package ifrit - - diff --git a/vendor/github.com/tedsuo/ifrit/fake_runner/doc.go b/vendor/github.com/tedsuo/ifrit/fake_runner/doc.go deleted file mode 100644 index ccf1ba0076d..00000000000 --- a/vendor/github.com/tedsuo/ifrit/fake_runner/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// fake_runner contains test fixtures. -package fake_runner diff --git a/vendor/github.com/tedsuo/ifrit/fake_runner/fake_runner.go b/vendor/github.com/tedsuo/ifrit/fake_runner/fake_runner.go deleted file mode 100644 index a98a896ebd0..00000000000 --- a/vendor/github.com/tedsuo/ifrit/fake_runner/fake_runner.go +++ /dev/null @@ -1,56 +0,0 @@ -// This file was generated by counterfeiter -package fake_runner - -import ( - "os" - "sync" - - "github.com/tedsuo/ifrit" -) - -type FakeRunner struct { - RunStub func(signals <-chan os.Signal, ready chan<- struct{}) error - runMutex sync.RWMutex - runArgsForCall []struct { - signals <-chan os.Signal - ready chan<- struct{} - } - runReturns struct { - result1 error - } -} - -func (fake *FakeRunner) Run(signals <-chan os.Signal, ready chan<- struct{}) error { - fake.runMutex.Lock() - fake.runArgsForCall = append(fake.runArgsForCall, struct { - signals <-chan os.Signal - ready chan<- struct{} - }{signals, ready}) - fake.runMutex.Unlock() - if fake.RunStub != nil { - return fake.RunStub(signals, ready) - } else { - return fake.runReturns.result1 - } -} - -func (fake *FakeRunner) RunCallCount() int { - fake.runMutex.RLock() - defer fake.runMutex.RUnlock() - return len(fake.runArgsForCall) -} - -func (fake *FakeRunner) RunArgsForCall(i int) (<-chan os.Signal, chan<- struct{}) { - fake.runMutex.RLock() - defer fake.runMutex.RUnlock() - return fake.runArgsForCall[i].signals, fake.runArgsForCall[i].ready -} - -func (fake *FakeRunner) RunReturns(result1 error) { - fake.RunStub = nil - fake.runReturns = struct { - result1 error - }{result1} -} - -var _ ifrit.Runner = new(FakeRunner) diff --git a/vendor/github.com/tedsuo/ifrit/fake_runner/test_runner.go b/vendor/github.com/tedsuo/ifrit/fake_runner/test_runner.go deleted file mode 100644 index 74d1a280ae5..00000000000 --- a/vendor/github.com/tedsuo/ifrit/fake_runner/test_runner.go +++ /dev/null @@ -1,50 +0,0 @@ -package fake_runner - -import ( - "os" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -type TestRunner struct { - *FakeRunner - exitChan chan error -} - -func NewTestRunner() *TestRunner { - exitChan := make(chan error) - runner := &FakeRunner{ - RunStub: func(signals <-chan os.Signal, ready chan<- struct{}) error { - return <-exitChan - }, - } - - return &TestRunner{runner, exitChan} -} - -func (r *TestRunner) WaitForCall() <-chan os.Signal { - Eventually(r.RunCallCount).Should(Equal(1)) - signal, _ := r.RunArgsForCall(0) - return signal -} - -func (r *TestRunner) TriggerReady() { - Eventually(r.RunCallCount).Should(Equal(1)) - _, ready := r.RunArgsForCall(0) - close(ready) -} - -func (r *TestRunner) TriggerExit(err error) { - defer GinkgoRecover() - - r.exitChan <- err -} - -func (r *TestRunner) EnsureExit() { - select { - case r.exitChan <- nil: - default: - - } -} diff --git a/vendor/github.com/tedsuo/ifrit/ginkgomon/ginkgomon.go b/vendor/github.com/tedsuo/ifrit/ginkgomon/ginkgomon.go deleted file mode 100644 index 0d0c022a64a..00000000000 --- a/vendor/github.com/tedsuo/ifrit/ginkgomon/ginkgomon.go +++ /dev/null @@ -1,161 +0,0 @@ -/* -Ginkgomon provides ginkgo test helpers. -*/ -package ginkgomon - -import ( - "fmt" - "io" - "os" - "os/exec" - "time" - - "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/onsi/gomega/gbytes" - "github.com/onsi/gomega/gexec" -) - -// Config defines a ginkgomon Runner. -type Config struct { - Command *exec.Cmd // process to be executed - Name string // prefixes all output lines - AnsiColorCode string // colors the output - StartCheck string // text to match to indicate sucessful start. - StartCheckTimeout time.Duration // how long to wait to see StartCheck - Cleanup func() // invoked once the process exits -} - -/* -The ginkgomon Runner invokes a new process using gomega's gexec package. - -If a start check is defined, the runner will wait until it sees the start check -before declaring ready. - -Runner implements gexec.Exiter and gbytes.BufferProvider, so you can test exit -codes and process output using the appropriate gomega matchers: -http://onsi.github.io/gomega/#gexec-testing-external-processes -*/ -type Runner struct { - Command *exec.Cmd - Name string - AnsiColorCode string - StartCheck string - StartCheckTimeout time.Duration - Cleanup func() - session *gexec.Session - sessionReady chan struct{} -} - -// New creates a ginkgomon Runner from a config object. Runners must be created -// with New to properly initialize their internal state. -func New(config Config) *Runner { - return &Runner{ - Name: config.Name, - Command: config.Command, - AnsiColorCode: config.AnsiColorCode, - StartCheck: config.StartCheck, - StartCheckTimeout: config.StartCheckTimeout, - Cleanup: config.Cleanup, - sessionReady: make(chan struct{}), - } -} - -// ExitCode returns the exit code of the process, or -1 if the process has not -// exited. It can be used with the gexec.Exit matcher. -func (r *Runner) ExitCode() int { - if r.sessionReady == nil { - ginkgo.Fail(fmt.Sprintf("ginkgomon.Runner '%s' improperly created without using New", r.Name)) - } - <-r.sessionReady - return r.session.ExitCode() -} - -// Buffer returns a gbytes.Buffer, for use with the gbytes.Say matcher. -func (r *Runner) Buffer() *gbytes.Buffer { - if r.sessionReady == nil { - ginkgo.Fail(fmt.Sprintf("ginkgomon.Runner '%s' improperly created without using New", r.Name)) - } - <-r.sessionReady - return r.session.Buffer() -} - -func (r *Runner) Run(sigChan <-chan os.Signal, ready chan<- struct{}) error { - defer ginkgo.GinkgoRecover() - - allOutput := gbytes.NewBuffer() - - debugWriter := gexec.NewPrefixedWriter( - fmt.Sprintf("\x1b[32m[d]\x1b[%s[%s]\x1b[0m ", r.AnsiColorCode, r.Name), - ginkgo.GinkgoWriter, - ) - - session, err := gexec.Start( - r.Command, - gexec.NewPrefixedWriter( - fmt.Sprintf("\x1b[32m[o]\x1b[%s[%s]\x1b[0m ", r.AnsiColorCode, r.Name), - io.MultiWriter(allOutput, ginkgo.GinkgoWriter), - ), - gexec.NewPrefixedWriter( - fmt.Sprintf("\x1b[91m[e]\x1b[%s[%s]\x1b[0m ", r.AnsiColorCode, r.Name), - io.MultiWriter(allOutput, ginkgo.GinkgoWriter), - ), - ) - - Ω(err).ShouldNot(HaveOccurred()) - - fmt.Fprintf(debugWriter, "spawned %s (pid: %d)\n", r.Command.Path, r.Command.Process.Pid) - - r.session = session - if r.sessionReady != nil { - close(r.sessionReady) - } - - startCheckDuration := r.StartCheckTimeout - if startCheckDuration == 0 { - startCheckDuration = 5 * time.Second - } - - var startCheckTimeout <-chan time.Time - if r.StartCheck != "" { - startCheckTimeout = time.After(startCheckDuration) - } - - detectStartCheck := allOutput.Detect(r.StartCheck) - - for { - select { - case <-detectStartCheck: // works even with empty string - allOutput.CancelDetects() - startCheckTimeout = nil - detectStartCheck = nil - close(ready) - - case <-startCheckTimeout: - // clean up hanging process - session.Kill().Wait() - - // fail to start - return fmt.Errorf( - "did not see %s in command's output within %s. full output:\n\n%s", - r.StartCheck, - startCheckDuration, - string(allOutput.Contents()), - ) - - case signal := <-sigChan: - session.Signal(signal) - - case <-session.Exited: - if r.Cleanup != nil { - r.Cleanup() - } - - if session.ExitCode() == 0 { - return nil - } - - return fmt.Errorf("exit status %d", session.ExitCode()) - } - } -} diff --git a/vendor/github.com/tedsuo/ifrit/ginkgomon/helpers.go b/vendor/github.com/tedsuo/ifrit/ginkgomon/helpers.go deleted file mode 100644 index b5d08cdefd1..00000000000 --- a/vendor/github.com/tedsuo/ifrit/ginkgomon/helpers.go +++ /dev/null @@ -1,36 +0,0 @@ -package ginkgomon - -import ( - "fmt" - "os" - - "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/tedsuo/ifrit" -) - -func Invoke(runner ifrit.Runner) ifrit.Process { - process := ifrit.Background(runner) - - select { - case <-process.Ready(): - case err := <-process.Wait(): - ginkgo.Fail(fmt.Sprintf("process failed to start: %s", err), 1) - } - - return process -} - -func Interrupt(process ifrit.Process, intervals ...interface{}) { - if process != nil { - process.Signal(os.Interrupt) - EventuallyWithOffset(1, process.Wait(), intervals...).Should(Receive(), "interrupted ginkgomon process failed to exit in time") - } -} - -func Kill(process ifrit.Process, intervals ...interface{}) { - if process != nil { - process.Signal(os.Kill) - EventuallyWithOffset(1, process.Wait(), intervals...).Should(Receive(), "killed ginkgomon process failed to exit in time") - } -} diff --git a/vendor/github.com/tedsuo/ifrit/grouper/client.go b/vendor/github.com/tedsuo/ifrit/grouper/client.go deleted file mode 100644 index 5cc4514b99d..00000000000 --- a/vendor/github.com/tedsuo/ifrit/grouper/client.go +++ /dev/null @@ -1,153 +0,0 @@ -package grouper - -import ( - "sync" - - "github.com/tedsuo/ifrit" -) - -/* -DynamicClient provides a client with group controls and event notifications. -A client can use the insert channel to add members to the group. When the group -becomes full, the insert channel blocks until a running process exits the group. -Once there are no more members to be added, the client can close the dynamic -group, preventing new members from being added. -*/ -type DynamicClient interface { - - /* - EntranceListener provides a new buffered channel of entrance events, which are - emited every time an inserted process is ready. To help prevent race conditions, - every new channel is populated with previously emited events, up to it's buffer - size. - */ - EntranceListener() <-chan EntranceEvent - - /* - ExitListener provides a new buffered channel of exit events, which are emited - every time an inserted process exits. To help prevent race conditions, every - new channel is populated with previously emited events, up to it's buffer size. - */ - ExitListener() <-chan ExitEvent - - /* - CloseNotifier provides a new unbuffered channel, which will emit a single event - once the group has been closed. - */ - CloseNotifier() <-chan struct{} - /* - Inserter provides an unbuffered channel for adding members to a group. When the - group becomes full, the insert channel blocks until a running process exits. - Once the group is closed, insert channels block forever. - */ - Inserter() chan<- Member - - /* - Close causes a dynamic group to become a static group. This means that no new - members may be inserted, and the group will exit once all members have - completed. - */ - Close() - - Get(name string) (ifrit.Process, bool) -} - -type memberRequest struct { - Name string - Response chan ifrit.Process -} - -/* -dynamicClient implements DynamicClient. -*/ -type dynamicClient struct { - insertChannel chan Member - getMemberChannel chan memberRequest - completeNotifier chan struct{} - closeNotifier chan struct{} - closeOnce *sync.Once - entranceBroadcaster *entranceEventBroadcaster - exitBroadcaster *exitEventBroadcaster -} - -func newClient(bufferSize int) dynamicClient { - return dynamicClient{ - insertChannel: make(chan Member), - getMemberChannel: make(chan memberRequest), - completeNotifier: make(chan struct{}), - closeNotifier: make(chan struct{}), - closeOnce: new(sync.Once), - entranceBroadcaster: newEntranceEventBroadcaster(bufferSize), - exitBroadcaster: newExitEventBroadcaster(bufferSize), - } -} - -func (c dynamicClient) Get(name string) (ifrit.Process, bool) { - req := memberRequest{ - Name: name, - Response: make(chan ifrit.Process), - } - select { - case c.getMemberChannel <- req: - p, ok := <-req.Response - if !ok { - return nil, false - } - return p, true - case <-c.completeNotifier: - return nil, false - } -} - -func (c dynamicClient) memberRequests() chan memberRequest { - return c.getMemberChannel -} - -func (c dynamicClient) Inserter() chan<- Member { - return c.insertChannel -} - -func (c dynamicClient) insertEventListener() <-chan Member { - return c.insertChannel -} - -func (c dynamicClient) EntranceListener() <-chan EntranceEvent { - return c.entranceBroadcaster.Attach() -} - -func (c dynamicClient) broadcastEntrance(event EntranceEvent) { - c.entranceBroadcaster.Broadcast(event) -} - -func (c dynamicClient) closeEntranceBroadcaster() { - c.entranceBroadcaster.Close() -} - -func (c dynamicClient) ExitListener() <-chan ExitEvent { - return c.exitBroadcaster.Attach() -} - -func (c dynamicClient) broadcastExit(event ExitEvent) { - c.exitBroadcaster.Broadcast(event) -} - -func (c dynamicClient) closeExitBroadcaster() { - c.exitBroadcaster.Close() -} - -func (c dynamicClient) closeBroadcasters() error { - c.entranceBroadcaster.Close() - c.exitBroadcaster.Close() - close(c.completeNotifier) - return nil -} - -func (c dynamicClient) Close() { - c.closeOnce.Do(func() { - close(c.closeNotifier) - }) -} - -func (c dynamicClient) CloseNotifier() <-chan struct{} { - return c.closeNotifier -} diff --git a/vendor/github.com/tedsuo/ifrit/grouper/doc.go b/vendor/github.com/tedsuo/ifrit/grouper/doc.go deleted file mode 100644 index f5131f3267f..00000000000 --- a/vendor/github.com/tedsuo/ifrit/grouper/doc.go +++ /dev/null @@ -1,31 +0,0 @@ -/* -Grouper implements process orcestration. Runners are organized into groups, -which are then organized into an execution tree. If you have modeled your subsystems -as ifrit runners, startup and shutdown of your entire application can now -be controlled. - -Grouper provides three strategies for system startup: two static group -strategies, and one DynamicGroup. Each static group strategy takes a -list of members, and starts the members in the following manner: - - - Parallel: all processes are started simultaneously. - - Ordered: the next process is started when the previous is ready. - -The DynamicGroup allows up to N processes to be run concurrently. The dynamic -group runs indefinitely until it is closed or signaled. The DynamicGroup provides -a DynamicClient to allow interacting with the group. A dynamic group has the -following properties: - - - A dynamic group allows Members to be inserted until it is closed. - - A dynamic group can be manually closed via it's client. - - A dynamic group is automatically closed once it is signaled. - - Once a dynamic group is closed, it acts like a static group. - -Groups can optionally be configured with a termination signal, and all groups -have the same signaling and shutdown properties: - - - The group propogates all received signals to all running members. - - If a member exits before being signaled, the group propogates the - termination signal. A nil termination signal is not propogated. -*/ -package grouper diff --git a/vendor/github.com/tedsuo/ifrit/grouper/dynamic_group.go b/vendor/github.com/tedsuo/ifrit/grouper/dynamic_group.go deleted file mode 100644 index 572f1f76cd0..00000000000 --- a/vendor/github.com/tedsuo/ifrit/grouper/dynamic_group.go +++ /dev/null @@ -1,214 +0,0 @@ -package grouper - -import ( - "fmt" - "os" - - "github.com/tedsuo/ifrit" -) - -/* -A DynamicGroup begins empty, and runs members as they are inserted. A -dynamic group will continue to run, even when there are no members running -within it, until it is signaled to stop. Once a dynamic group is signaled to -stop, it will no longer accept new members, and waits for the currently running -members to complete before exiting. -*/ -type DynamicGroup interface { - ifrit.Runner - Client() DynamicClient -} - -type dynamicGroup struct { - client dynamicClient - terminationSignal os.Signal - poolSize int -} - -/* -NewDynamic creates a DynamicGroup. - -The maxCapacity argument sets the maximum number of concurrent processes. - -The eventBufferSize argument sets the number of entrance and exit events to be -retained by the system. When a new event listener attaches, it will receive -any previously emitted events, up to the eventBufferSize. Older events will be -thrown away. The event buffer is meant to be used to avoid race conditions when -the total number of members is known in advance. - -The signal argument sets the termination signal. If a member exits before -being signaled, the group propogates the termination signal. A nil termination -signal is not propogated. -*/ -func NewDynamic(terminationSignal os.Signal, maxCapacity int, eventBufferSize int) DynamicGroup { - return &dynamicGroup{ - client: newClient(eventBufferSize), - poolSize: maxCapacity, - terminationSignal: terminationSignal, - } -} - -func (p *dynamicGroup) Client() DynamicClient { - return p.client -} - -func (p *dynamicGroup) Run(signals <-chan os.Signal, ready chan<- struct{}) error { - processes := newProcessSet() - insertEvents := p.client.insertEventListener() - memberRequests := p.client.memberRequests() - closeNotifier := p.client.CloseNotifier() - entranceEvents := make(entranceEventChannel) - exitEvents := make(exitEventChannel) - - invoking := 0 - close(ready) - - for { - select { - case shutdown := <-signals: - processes.Signal(shutdown) - p.client.Close() - - case <-closeNotifier: - closeNotifier = nil - insertEvents = nil - if processes.Length() == 0 { - return p.client.closeBroadcasters() - } - if invoking == 0 { - p.client.closeEntranceBroadcaster() - } - - case memberRequest := <-memberRequests: - p, ok := processes.Get(memberRequest.Name) - if ok { - memberRequest.Response <- p - } - close(memberRequest.Response) - - case newMember, ok := <-insertEvents: - if !ok { - p.client.Close() - insertEvents = nil - break - } - - process := ifrit.Background(newMember) - processes.Add(newMember.Name, process) - - if processes.Length() == p.poolSize { - insertEvents = nil - } - - invoking++ - - go waitForEvents(newMember, process, entranceEvents, exitEvents) - - case entranceEvent := <-entranceEvents: - invoking-- - p.client.broadcastEntrance(entranceEvent) - - if closeNotifier == nil && invoking == 0 { - p.client.closeEntranceBroadcaster() - entranceEvents = nil - } - - case exitEvent := <-exitEvents: - processes.Remove(exitEvent.Member.Name) - p.client.broadcastExit(exitEvent) - - if !processes.Signaled() && p.terminationSignal != nil { - processes.Signal(p.terminationSignal) - p.client.Close() - insertEvents = nil - } - - if processes.Complete() || (processes.Length() == 0 && insertEvents == nil) { - return p.client.closeBroadcasters() - } - - if !processes.Signaled() && closeNotifier != nil { - insertEvents = p.client.insertEventListener() - } - } - } -} - -func waitForEvents( - member Member, - process ifrit.Process, - entrance entranceEventChannel, - exit exitEventChannel, -) { - select { - case <-process.Ready(): - entrance <- EntranceEvent{ - Member: member, - Process: process, - } - - exit <- ExitEvent{ - Member: member, - Err: <-process.Wait(), - } - - case err := <-process.Wait(): - entrance <- EntranceEvent{ - Member: member, - Process: process, - } - - exit <- ExitEvent{ - Member: member, - Err: err, - } - } -} - -type processSet struct { - processes map[string]ifrit.Process - shutdown os.Signal -} - -func newProcessSet() *processSet { - return &processSet{ - processes: map[string]ifrit.Process{}, - } -} - -func (g *processSet) Signaled() bool { - return g.shutdown != nil -} - -func (g *processSet) Signal(signal os.Signal) { - g.shutdown = signal - - for _, p := range g.processes { - p.Signal(signal) - } -} - -func (g *processSet) Length() int { - return len(g.processes) -} - -func (g *processSet) Complete() bool { - return len(g.processes) == 0 && g.shutdown != nil -} - -func (g *processSet) Get(name string) (ifrit.Process, bool) { - p, ok := g.processes[name] - return p, ok -} - -func (g *processSet) Add(name string, process ifrit.Process) { - _, ok := g.processes[name] - if ok { - panic(fmt.Errorf("member inserted twice: %#v", name)) - } - g.processes[name] = process -} - -func (g *processSet) Remove(name string) { - delete(g.processes, name) -} diff --git a/vendor/github.com/tedsuo/ifrit/grouper/entrance_events.go b/vendor/github.com/tedsuo/ifrit/grouper/entrance_events.go deleted file mode 100644 index 9fa9768986d..00000000000 --- a/vendor/github.com/tedsuo/ifrit/grouper/entrance_events.go +++ /dev/null @@ -1,74 +0,0 @@ -package grouper - -import ( - "sync" - - "github.com/tedsuo/ifrit" -) - -/* -An EntranceEvent occurs every time an invoked member becomes ready. -*/ -type EntranceEvent struct { - Member Member - Process ifrit.Process -} - -type entranceEventChannel chan EntranceEvent - -func newEntranceEventChannel(bufferSize int) entranceEventChannel { - return make(entranceEventChannel, bufferSize) -} - -type entranceEventBroadcaster struct { - channels []entranceEventChannel - buffer slidingBuffer - bufferSize int - lock *sync.Mutex -} - -func newEntranceEventBroadcaster(bufferSize int) *entranceEventBroadcaster { - return &entranceEventBroadcaster{ - channels: make([]entranceEventChannel, 0), - buffer: newSlidingBuffer(bufferSize), - bufferSize: bufferSize, - lock: new(sync.Mutex), - } -} - -func (b *entranceEventBroadcaster) Attach() entranceEventChannel { - b.lock.Lock() - defer b.lock.Unlock() - - channel := newEntranceEventChannel(b.bufferSize) - b.buffer.Range(func(event interface{}) { - channel <- event.(EntranceEvent) - }) - if b.channels != nil { - b.channels = append(b.channels, channel) - } else { - close(channel) - } - return channel -} - -func (b *entranceEventBroadcaster) Broadcast(entrance EntranceEvent) { - b.lock.Lock() - defer b.lock.Unlock() - - b.buffer.Append(entrance) - - for _, entranceChan := range b.channels { - entranceChan <- entrance - } -} - -func (b *entranceEventBroadcaster) Close() { - b.lock.Lock() - defer b.lock.Unlock() - - for _, channel := range b.channels { - close(channel) - } - b.channels = nil -} diff --git a/vendor/github.com/tedsuo/ifrit/grouper/exit_events.go b/vendor/github.com/tedsuo/ifrit/grouper/exit_events.go deleted file mode 100644 index 2d535bccfbe..00000000000 --- a/vendor/github.com/tedsuo/ifrit/grouper/exit_events.go +++ /dev/null @@ -1,97 +0,0 @@ -package grouper - -import ( - "fmt" - "sync" -) - -/* -An ExitEvent occurs every time an invoked member exits. -*/ -type ExitEvent struct { - Member Member - Err error -} - -type exitEventChannel chan ExitEvent - -func newExitEventChannel(bufferSize int) exitEventChannel { - return make(exitEventChannel, bufferSize) -} - -type exitEventBroadcaster struct { - channels []exitEventChannel - buffer slidingBuffer - bufferSize int - lock *sync.Mutex -} - -func newExitEventBroadcaster(bufferSize int) *exitEventBroadcaster { - return &exitEventBroadcaster{ - channels: make([]exitEventChannel, 0), - buffer: newSlidingBuffer(bufferSize), - bufferSize: bufferSize, - lock: new(sync.Mutex), - } -} - -func (b *exitEventBroadcaster) Attach() exitEventChannel { - b.lock.Lock() - defer b.lock.Unlock() - - channel := newExitEventChannel(b.bufferSize) - b.buffer.Range(func(event interface{}) { - channel <- event.(ExitEvent) - }) - if b.channels != nil { - b.channels = append(b.channels, channel) - } else { - close(channel) - } - return channel -} - -func (b *exitEventBroadcaster) Broadcast(exit ExitEvent) { - b.lock.Lock() - defer b.lock.Unlock() - b.buffer.Append(exit) - for _, exitChan := range b.channels { - exitChan <- exit - } -} - -func (b *exitEventBroadcaster) Close() { - b.lock.Lock() - defer b.lock.Unlock() - - for _, channel := range b.channels { - close(channel) - } - b.channels = nil -} - -type ErrorTrace []ExitEvent - -func (trace ErrorTrace) Error() string { - msg := "Exit trace for group:\n" - - for _, exit := range trace { - if exit.Err == nil { - msg += fmt.Sprintf("%s exited with nil\n", exit.Member.Name) - } else { - msg += fmt.Sprintf("%s exited with error: %s\n", exit.Member.Name, exit.Err.Error()) - } - } - - return msg -} - -func (trace ErrorTrace) ErrorOrNil() error { - for _, exit := range trace { - if exit.Err != nil { - return trace - } - } - - return nil -} diff --git a/vendor/github.com/tedsuo/ifrit/grouper/members.go b/vendor/github.com/tedsuo/ifrit/grouper/members.go deleted file mode 100644 index 22370e16c24..00000000000 --- a/vendor/github.com/tedsuo/ifrit/grouper/members.go +++ /dev/null @@ -1,71 +0,0 @@ -package grouper - -import ( - "fmt" - - "github.com/tedsuo/ifrit" -) - -/* -A Member associates a unique name with a Runner. -*/ -type Member struct { - Name string - ifrit.Runner -} - -/* -Members are treated as an ordered list. Member names must be unique. -*/ -type Members []Member - -/* -Validate checks that all member names in the list are unique. It returns an -error of type ErrDuplicateNames if duplicates are detected. -*/ -func (m Members) Validate() error { - foundNames := map[string]struct{}{} - foundToken := struct{}{} - duplicateNames := []string{} - - for _, member := range m { - _, present := foundNames[member.Name] - if present { - duplicateNames = append(duplicateNames, member.Name) - continue - } - foundNames[member.Name] = foundToken - } - - if len(duplicateNames) > 0 { - return ErrDuplicateNames{duplicateNames} - } - return nil -} - -/* -ErrDuplicateNames is returned to indicate two or more members with the same name -were detected. Because more than one duplicate name may be detected in a single -pass, ErrDuplicateNames contains a list of all duplicate names found. -*/ -type ErrDuplicateNames struct { - DuplicateNames []string -} - -func (e ErrDuplicateNames) Error() string { - var msg string - - switch len(e.DuplicateNames) { - case 0: - msg = fmt.Sprintln("ErrDuplicateNames initialized without any duplicate names.") - case 1: - msg = fmt.Sprintln("Duplicate member name:", e.DuplicateNames[0]) - default: - msg = fmt.Sprintln("Duplicate member names:") - for _, name := range e.DuplicateNames { - msg = fmt.Sprintln(name) - } - } - - return msg -} diff --git a/vendor/github.com/tedsuo/ifrit/grouper/ordered.go b/vendor/github.com/tedsuo/ifrit/grouper/ordered.go deleted file mode 100644 index 48b697840d2..00000000000 --- a/vendor/github.com/tedsuo/ifrit/grouper/ordered.go +++ /dev/null @@ -1,189 +0,0 @@ -package grouper - -import ( - "os" - "reflect" - - "github.com/tedsuo/ifrit" -) - -/* -NewOrdered starts it's members in order, each member starting when the previous -becomes ready. On shutdown, it will shut the started processes down in reverse order. -Use an ordered group to describe a list of dependent processes, where each process -depends upon the previous being available in order to function correctly. -*/ -func NewOrdered(terminationSignal os.Signal, members Members) ifrit.Runner { - return &orderedGroup{ - terminationSignal: terminationSignal, - pool: make(map[string]ifrit.Process), - members: members, - } -} - -type orderedGroup struct { - terminationSignal os.Signal - pool map[string]ifrit.Process - members Members -} - -func (g *orderedGroup) Run(signals <-chan os.Signal, ready chan<- struct{}) error { - err := g.validate() - if err != nil { - return err - } - - signal, errTrace := g.orderedStart(signals) - if errTrace != nil { - return g.stop(g.terminationSignal, signals, errTrace) - } - - if signal != nil { - return g.stop(signal, signals, errTrace) - } - - close(ready) - - signal, errTrace = g.waitForSignal(signals, errTrace) - return g.stop(signal, signals, errTrace) -} - -func (g *orderedGroup) validate() error { - return g.members.Validate() -} - -func (g *orderedGroup) orderedStart(signals <-chan os.Signal) (os.Signal, ErrorTrace) { - for _, member := range g.members { - p := ifrit.Background(member) - cases := make([]reflect.SelectCase, 0, len(g.pool)+3) - for i := 0; i < len(g.pool); i++ { - cases = append(cases, reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(g.pool[g.members[i].Name].Wait()), - }) - } - cases = append(cases, reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(p.Ready()), - }) - - cases = append(cases, reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(p.Wait()), - }) - - cases = append(cases, reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(signals), - }) - - chosen, recv, _ := reflect.Select(cases) - g.pool[member.Name] = p - switch chosen { - case len(cases) - 1: - // signals - return recv.Interface().(os.Signal), nil - case len(cases) - 2: - // p.Wait - var err error - if !recv.IsNil() { - err = recv.Interface().(error) - } - return nil, ErrorTrace{ - ExitEvent{Member: member, Err: err}, - } - case len(cases) - 3: - // p.Ready - default: - // other member has exited - var err error = nil - if e := recv.Interface(); e != nil { - err = e.(error) - } - return nil, ErrorTrace{ - ExitEvent{Member: g.members[chosen], Err: err}, - } - } - } - - return nil, nil -} - -func (g *orderedGroup) waitForSignal(signals <-chan os.Signal, errTrace ErrorTrace) (os.Signal, ErrorTrace) { - cases := make([]reflect.SelectCase, 0, len(g.pool)+1) - for i := 0; i < len(g.pool); i++ { - cases = append(cases, reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(g.pool[g.members[i].Name].Wait()), - }) - } - cases = append(cases, reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(signals), - }) - - chosen, recv, _ := reflect.Select(cases) - if chosen == len(cases)-1 { - return recv.Interface().(os.Signal), errTrace - } - - var err error - if !recv.IsNil() { - err = recv.Interface().(error) - } - - errTrace = append(errTrace, ExitEvent{ - Member: g.members[chosen], - Err: err, - }) - - return g.terminationSignal, errTrace -} - -func (g *orderedGroup) stop(signal os.Signal, signals <-chan os.Signal, errTrace ErrorTrace) error { - errOccurred := false - exited := map[string]struct{}{} - if len(errTrace) > 0 { - for _, exitEvent := range errTrace { - exited[exitEvent.Member.Name] = struct{}{} - if exitEvent.Err != nil { - errOccurred = true - } - } - } - - for i := len(g.pool) - 1; i >= 0; i-- { - m := g.members[i] - if _, found := exited[m.Name]; found { - continue - } - if p, ok := g.pool[m.Name]; ok { - p.Signal(signal) - Exited: - for { - select { - case err := <-p.Wait(): - errTrace = append(errTrace, ExitEvent{ - Member: m, - Err: err, - }) - if err != nil { - errOccurred = true - } - break Exited - case sig := <-signals: - if sig != signal { - signal = sig - p.Signal(signal) - } - } - } - } - } - - if errOccurred { - return errTrace - } - - return nil -} diff --git a/vendor/github.com/tedsuo/ifrit/grouper/parallel.go b/vendor/github.com/tedsuo/ifrit/grouper/parallel.go deleted file mode 100644 index d430d93880f..00000000000 --- a/vendor/github.com/tedsuo/ifrit/grouper/parallel.go +++ /dev/null @@ -1,195 +0,0 @@ -package grouper - -import ( - "os" - "reflect" - - "github.com/tedsuo/ifrit" -) - -/* -NewParallel starts it's members simultaneously. Use a parallel group to describe a set -of concurrent but independent processes. -*/ -func NewParallel(terminationSignal os.Signal, members Members) ifrit.Runner { - return parallelGroup{ - terminationSignal: terminationSignal, - pool: make(map[string]ifrit.Process), - members: members, - } -} - -type parallelGroup struct { - terminationSignal os.Signal - pool map[string]ifrit.Process - members Members -} - -func (g parallelGroup) Run(signals <-chan os.Signal, ready chan<- struct{}) error { - err := g.validate() - if err != nil { - return err - } - - signal, errTrace := g.parallelStart(signals) - if errTrace != nil { - return g.stop(g.terminationSignal, signals, errTrace).ErrorOrNil() - } - - if signal != nil { - return g.stop(signal, signals, errTrace).ErrorOrNil() - } - - close(ready) - - signal, errTrace = g.waitForSignal(signals, errTrace) - return g.stop(signal, signals, errTrace).ErrorOrNil() -} - -func (o parallelGroup) validate() error { - return o.members.Validate() -} - -func (g *parallelGroup) parallelStart(signals <-chan os.Signal) (os.Signal, ErrorTrace) { - numMembers := len(g.members) - - cases := make([]reflect.SelectCase, 2*numMembers+1) - - for i, member := range g.members { - process := ifrit.Background(member) - - g.pool[member.Name] = process - - cases[2*i] = reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(process.Wait()), - } - - cases[2*i+1] = reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(process.Ready()), - } - } - - cases[2*numMembers] = reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(signals), - } - - numReady := 0 - for { - chosen, recv, _ := reflect.Select(cases) - - switch { - case chosen == 2*numMembers: - return recv.Interface().(os.Signal), nil - case chosen%2 == 0: - recvError, _ := recv.Interface().(error) - return nil, ErrorTrace{ExitEvent{Member: g.members[chosen/2], Err: recvError}} - default: - cases[chosen].Chan = reflect.Zero(cases[chosen].Chan.Type()) - numReady++ - if numReady == numMembers { - return nil, nil - } - } - } -} - -func (g *parallelGroup) waitForSignal(signals <-chan os.Signal, errTrace ErrorTrace) (os.Signal, ErrorTrace) { - cases := make([]reflect.SelectCase, 0, len(g.pool)+1) - for i := 0; i < len(g.pool); i++ { - cases = append(cases, reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(g.pool[g.members[i].Name].Wait()), - }) - } - cases = append(cases, reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(signals), - }) - - chosen, recv, _ := reflect.Select(cases) - if chosen == len(cases)-1 { - return recv.Interface().(os.Signal), errTrace - } - - var err error - if !recv.IsNil() { - err = recv.Interface().(error) - } - - errTrace = append(errTrace, ExitEvent{ - Member: g.members[chosen], - Err: err, - }) - - return g.terminationSignal, errTrace -} - -func (g *parallelGroup) stop(signal os.Signal, signals <-chan os.Signal, errTrace ErrorTrace) ErrorTrace { - errOccurred := false - exited := map[string]struct{}{} - if len(errTrace) > 0 { - for _, exitEvent := range errTrace { - exited[exitEvent.Member.Name] = struct{}{} - if exitEvent.Err != nil { - errOccurred = true - } - } - } - - cases := make([]reflect.SelectCase, 0, len(g.members)) - liveMembers := make([]Member, 0, len(g.members)) - for _, member := range g.members { - if _, found := exited[member.Name]; found { - continue - } - - process := g.pool[member.Name] - - process.Signal(signal) - - cases = append(cases, reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(process.Wait()), - }) - - liveMembers = append(liveMembers, member) - } - - cases = append(cases, reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(signals), - }) - - // account for the signals channel - for numExited := 1; numExited < len(cases); numExited++ { - chosen, recv, _ := reflect.Select(cases) - cases[chosen].Chan = reflect.Zero(cases[chosen].Chan.Type()) - recvError, _ := recv.Interface().(error) - - if chosen == len(cases)-1 { - signal = recv.Interface().(os.Signal) - for _, member := range liveMembers { - g.pool[member.Name].Signal(signal) - } - continue - } - - errTrace = append(errTrace, ExitEvent{ - Member: liveMembers[chosen], - Err: recvError, - }) - - if recvError != nil { - errOccurred = true - } - } - - if errOccurred { - return errTrace - } - - return nil -} diff --git a/vendor/github.com/tedsuo/ifrit/grouper/sliding_buffer.go b/vendor/github.com/tedsuo/ifrit/grouper/sliding_buffer.go deleted file mode 100644 index 89ca990c64d..00000000000 --- a/vendor/github.com/tedsuo/ifrit/grouper/sliding_buffer.go +++ /dev/null @@ -1,35 +0,0 @@ -package grouper - -import "container/list" - -type slidingBuffer struct { - buffer *list.List - capacity int -} - -func newSlidingBuffer(capacity int) slidingBuffer { - return slidingBuffer{list.New(), capacity} -} - -func (b slidingBuffer) Append(item interface{}) { - if b.capacity == 0 { - return - } - - b.buffer.PushBack(item) - if b.buffer.Len() > b.capacity { - b.buffer.Remove(b.buffer.Front()) - } -} - -func (b slidingBuffer) Range(callback func(item interface{})) { - elem := b.buffer.Front() - for elem != nil { - callback(elem.Value) - elem = elem.Next() - } -} - -func (b slidingBuffer) Length() int { - return b.buffer.Len() -} diff --git a/vendor/github.com/tedsuo/ifrit/grpc_server/server.go b/vendor/github.com/tedsuo/ifrit/grpc_server/server.go deleted file mode 100644 index deb26de1bb9..00000000000 --- a/vendor/github.com/tedsuo/ifrit/grpc_server/server.go +++ /dev/null @@ -1,120 +0,0 @@ -package grpc_server - -import ( - "crypto/tls" - "net" - "os" - - "fmt" - "reflect" - - "errors" - - "github.com/tedsuo/ifrit" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" -) - -type grpcServerRunner struct { - listenAddress string - handler interface{} - serverRegistrar interface{} - tlsConfig *tls.Config -} - -// NewGRPCServer returns an ifrit.Runner for your GRPC server process, given artifacts normally generated from a -// protobuf service definition by protoc. -// -// tlsConfig is optional. If nil the server will run insecure. -// -// handler must be an implementation of the interface generated by protoc. -// -// serverRegistrar must be the "RegisterXXXServer" method generated by protoc. -// -// Type checking occurs at runtime. Poorly typed `handler` or `serverRegistrar` parameters will result in an error -// when the Runner is Invoked. -func NewGRPCServer(listenAddress string, tlsConfig *tls.Config, handler, serverRegistrar interface{}) ifrit.Runner { - return &grpcServerRunner{ - listenAddress: listenAddress, - handler: handler, - serverRegistrar: serverRegistrar, - tlsConfig: tlsConfig, - } -} - -func (s *grpcServerRunner) Validate() error { - if s.serverRegistrar == nil || s.handler == nil { - return errors.New("NewGRPCServer: `serverRegistrar` and `handler` must be non nil") - } - - vServerRegistrar := reflect.ValueOf(s.serverRegistrar) - vHandler := reflect.ValueOf(s.handler) - - registrarType := vServerRegistrar.Type() - handlerType := vHandler.Type() - - // registrar type must be `func(*grpc.Server, X)` - if registrarType.Kind() != reflect.Func { - return fmt.Errorf("NewGRPCServer: `serverRegistrar` should be %s but is %s", - reflect.Func, registrarType.Kind()) - } - if registrarType.NumIn() != 2 { - return fmt.Errorf("NewGRPCServer: `serverRegistrar` should have 2 parameters but it has %d parameters", - registrarType.NumIn()) - } - if registrarType.NumOut() != 0 { - return fmt.Errorf("NewGRPCServer: `serverRegistrar` should return no value but it returns %d values", - registrarType.NumOut()) - } - - // registrar's first parameter type must be a grpc server - if reflect.TypeOf((*grpc.Server)(nil)) != registrarType.In(0) { - return fmt.Errorf("NewGRPCServer: type of `serverRegistrar`'s first parameter must be `*grpc.Server` but is %s", - registrarType.In(0)) - } - - // registrar's second parameter type must be implemented by handler type. - if registrarType.In(1).Kind() != reflect.Interface || !handlerType.Implements(registrarType.In(1)) { - return fmt.Errorf("NewGRPCServer: type of `serverRegistrar`'s second parameter %s is not implemented by `handler` type %s", - registrarType.In(1), handlerType) - } - return nil -} - -func (s *grpcServerRunner) Run(signals <-chan os.Signal, ready chan<- struct{}) error { - err := s.Validate() - if err != nil { - return err - } - - vServerRegistrar := reflect.ValueOf(s.serverRegistrar) - vHandler := reflect.ValueOf(s.handler) - - lis, err := net.Listen("tcp", s.listenAddress) - if err != nil { - return err - } - - opts := []grpc.ServerOption{} - if s.tlsConfig != nil { - opts = append(opts, grpc.Creds(credentials.NewTLS(s.tlsConfig))) - } - server := grpc.NewServer(opts...) - args := []reflect.Value{reflect.ValueOf(server), vHandler} - vServerRegistrar.Call(args) - - errCh := make(chan error) - go func() { - errCh <- server.Serve(lis) - }() - - close(ready) - - select { - case <-signals: - case err = <-errCh: - } - - server.GracefulStop() - return err -} diff --git a/vendor/github.com/tedsuo/ifrit/http_server/http_server.go b/vendor/github.com/tedsuo/ifrit/http_server/http_server.go deleted file mode 100644 index a06d287795e..00000000000 --- a/vendor/github.com/tedsuo/ifrit/http_server/http_server.go +++ /dev/null @@ -1,176 +0,0 @@ -package http_server - -import ( - "crypto/tls" - "net" - "net/http" - "os" - "sync" - "time" - - "github.com/tedsuo/ifrit" -) - -const ( - TCP = "tcp" - UNIX = "unix" -) - -type httpServer struct { - protocol string - address string - handler http.Handler - - connectionWaitGroup *sync.WaitGroup - inactiveConnections map[net.Conn]struct{} - inactiveConnectionsMu *sync.Mutex - stoppingChan chan struct{} - - tlsConfig *tls.Config -} - -func newServerWithListener(protocol, address string, handler http.Handler, tlsConfig *tls.Config) ifrit.Runner { - return &httpServer{ - address: address, - handler: handler, - tlsConfig: tlsConfig, - protocol: protocol, - } -} - -func NewUnixServer(address string, handler http.Handler) ifrit.Runner { - return newServerWithListener(UNIX, address, handler, nil) -} - -func New(address string, handler http.Handler) ifrit.Runner { - return newServerWithListener(TCP, address, handler, nil) -} - -func NewUnixTLSServer(address string, handler http.Handler, tlsConfig *tls.Config) ifrit.Runner { - return newServerWithListener(UNIX, address, handler, tlsConfig) -} - -func NewTLSServer(address string, handler http.Handler, tlsConfig *tls.Config) ifrit.Runner { - return newServerWithListener(TCP, address, handler, tlsConfig) -} - -func (s *httpServer) Run(signals <-chan os.Signal, ready chan<- struct{}) error { - s.connectionWaitGroup = new(sync.WaitGroup) - s.inactiveConnectionsMu = new(sync.Mutex) - s.inactiveConnections = make(map[net.Conn]struct{}) - s.stoppingChan = make(chan struct{}) - - connCountCh := make(chan int) - - server := http.Server{ - Handler: s.handler, - TLSConfig: s.tlsConfig, - ConnState: func(conn net.Conn, state http.ConnState) { - switch state { - case http.StateNew: - connCountCh <- 1 - s.addInactiveConnection(conn) - - case http.StateIdle: - s.addInactiveConnection(conn) - - case http.StateActive: - s.removeInactiveConnection(conn) - - case http.StateHijacked, http.StateClosed: - s.removeInactiveConnection(conn) - connCountCh <- -1 - } - }, - } - - listener, err := s.getListener(server.TLSConfig) - if err != nil { - return err - } - - serverErrChan := make(chan error, 1) - go func() { - serverErrChan <- server.Serve(listener) - }() - - close(ready) - - connCount := 0 - for { - select { - case err = <-serverErrChan: - return err - - case delta := <-connCountCh: - connCount += delta - - case <-signals: - close(s.stoppingChan) - - listener.Close() - - s.inactiveConnectionsMu.Lock() - for c := range s.inactiveConnections { - c.Close() - } - s.inactiveConnectionsMu.Unlock() - - for connCount != 0 { - delta := <-connCountCh - connCount += delta - } - - return nil - } - } -} - -func (s *httpServer) getListener(tlsConfig *tls.Config) (net.Listener, error) { - listener, err := net.Listen(s.protocol, s.address) - if err != nil { - return nil, err - } - if tlsConfig == nil { - return listener, nil - } - switch s.protocol { - case TCP: - listener = tls.NewListener(tcpKeepAliveListener{listener.(*net.TCPListener)}, tlsConfig) - default: - listener = tls.NewListener(listener, tlsConfig) - } - - return listener, nil -} - -func (s *httpServer) addInactiveConnection(conn net.Conn) { - select { - case <-s.stoppingChan: - conn.Close() - default: - s.inactiveConnectionsMu.Lock() - s.inactiveConnections[conn] = struct{}{} - s.inactiveConnectionsMu.Unlock() - } -} - -func (s *httpServer) removeInactiveConnection(conn net.Conn) { - s.inactiveConnectionsMu.Lock() - delete(s.inactiveConnections, conn) - s.inactiveConnectionsMu.Unlock() -} - -type tcpKeepAliveListener struct { - *net.TCPListener -} - -func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) { - tc, err := ln.AcceptTCP() - if err != nil { - return - } - tc.SetKeepAlive(true) - tc.SetKeepAlivePeriod(3 * time.Minute) - return tc, nil -} diff --git a/vendor/github.com/tedsuo/ifrit/http_server/unix_transport/unix_transport.go b/vendor/github.com/tedsuo/ifrit/http_server/unix_transport/unix_transport.go deleted file mode 100644 index d755bb8383b..00000000000 --- a/vendor/github.com/tedsuo/ifrit/http_server/unix_transport/unix_transport.go +++ /dev/null @@ -1,105 +0,0 @@ -package unix_transport - -import ( - "crypto/tls" - "errors" - "fmt" - "net" - "net/http" - "net/http/httputil" - "net/url" - "strings" -) - -func NewWithTLS(socketPath string, tlsConfig *tls.Config) *http.Transport { - unixTransport := &http.Transport{TLSClientConfig: tlsConfig} - - unixTransport.RegisterProtocol("unix", NewUnixRoundTripperTls(socketPath, tlsConfig)) - return unixTransport -} - -func New(socketPath string) *http.Transport { - unixTransport := &http.Transport{} - unixTransport.RegisterProtocol("unix", NewUnixRoundTripper(socketPath)) - return unixTransport -} - -type UnixRoundTripper struct { - path string - conn httputil.ClientConn - useTls bool - tlsConfig *tls.Config -} - -func NewUnixRoundTripper(path string) *UnixRoundTripper { - return &UnixRoundTripper{path: path} -} - -func NewUnixRoundTripperTls(path string, tlsConfig *tls.Config) *UnixRoundTripper { - return &UnixRoundTripper{ - path: path, - useTls: true, - tlsConfig: tlsConfig, - } -} - -// The RoundTripper (http://golang.org/pkg/net/http/#RoundTripper) for the socket transport dials the socket -// each time a request is made. -func (roundTripper UnixRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - var conn net.Conn - var err error - if roundTripper.useTls { - - conn, err = tls.Dial("unix", roundTripper.path, roundTripper.tlsConfig) - if err != nil { - return nil, err - } - if conn == nil { - return nil, errors.New("net/http: Transport.DialTLS returned (nil, nil)") - } - if tc, ok := conn.(*tls.Conn); ok { - // Handshake here, in case DialTLS didn't. TLSNextProto below - // depends on it for knowing the connection state. - if err := tc.Handshake(); err != nil { - go conn.Close() - return nil, err - } - } - } else { - conn, err = net.Dial("unix", roundTripper.path) - if err != nil { - return nil, err - } - } - - socketClientConn := httputil.NewClientConn(conn, nil) - defer socketClientConn.Close() - - newReq, err := roundTripper.rewriteRequest(req) - if err != nil { - return nil, err - } - - return socketClientConn.Do(newReq) -} - -func (roundTripper *UnixRoundTripper) rewriteRequest(req *http.Request) (*http.Request, error) { - requestPath := req.URL.Path - if !strings.HasPrefix(requestPath, roundTripper.path) { - return nil, fmt.Errorf("Wrong unix socket [unix://%s]. Expected unix socket is [%s]", requestPath, roundTripper.path) - } - - reqPath := strings.TrimPrefix(requestPath, roundTripper.path) - newReqUrl := fmt.Sprintf("unix://%s", reqPath) - - var err error - newURL, err := url.Parse(newReqUrl) - if err != nil { - return nil, err - } - - req.URL.Path = newURL.Path - req.URL.Host = roundTripper.path - return req, nil - -} diff --git a/vendor/github.com/tedsuo/ifrit/process.go b/vendor/github.com/tedsuo/ifrit/process.go deleted file mode 100644 index 16f84181dc2..00000000000 --- a/vendor/github.com/tedsuo/ifrit/process.go +++ /dev/null @@ -1,97 +0,0 @@ -package ifrit - -import "os" - -/* -A Process represents a Runner that has been started. It is safe to call any -method on a Process even after the Process has exited. -*/ -type Process interface { - // Ready returns a channel which will close once the runner is active - Ready() <-chan struct{} - - // Wait returns a channel that will emit a single error once the Process exits. - Wait() <-chan error - - // Signal sends a shutdown signal to the Process. It does not block. - Signal(os.Signal) -} - -/* -Invoke executes a Runner and returns a Process once the Runner is ready. Waiting -for ready allows program initializtion to be scripted in a procedural manner. -To orcestrate the startup and monitoring of multiple Processes, please refer to -the ifrit/grouper package. -*/ -func Invoke(r Runner) Process { - p := Background(r) - - select { - case <-p.Ready(): - case <-p.Wait(): - } - - return p -} - -/* -Envoke is deprecated in favor of Invoke, on account of it not being a real word. -*/ -func Envoke(r Runner) Process { - return Invoke(r) -} - -/* -Background executes a Runner and returns a Process immediately, without waiting. -*/ -func Background(r Runner) Process { - p := newProcess(r) - go p.run() - return p -} - -type process struct { - runner Runner - signals chan os.Signal - ready chan struct{} - exited chan struct{} - exitStatus error -} - -func newProcess(runner Runner) *process { - return &process{ - runner: runner, - signals: make(chan os.Signal), - ready: make(chan struct{}), - exited: make(chan struct{}), - } -} - -func (p *process) run() { - p.exitStatus = p.runner.Run(p.signals, p.ready) - close(p.exited) -} - -func (p *process) Ready() <-chan struct{} { - return p.ready -} - -func (p *process) Wait() <-chan error { - exitChan := make(chan error, 1) - - go func() { - <-p.exited - exitChan <- p.exitStatus - }() - - return exitChan -} - -func (p *process) Signal(signal os.Signal) { - go func() { - select { - case p.signals <- signal: - case <-p.exited: - } - }() -} diff --git a/vendor/github.com/tedsuo/ifrit/proxy/proxy.go b/vendor/github.com/tedsuo/ifrit/proxy/proxy.go deleted file mode 100644 index f103e6a5e6e..00000000000 --- a/vendor/github.com/tedsuo/ifrit/proxy/proxy.go +++ /dev/null @@ -1,30 +0,0 @@ -package proxy - -import ( - "os" - - "github.com/tedsuo/ifrit" -) - -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() - }) -} - -func forwardSignals(signals <-chan os.Signal, process ifrit.Process) { - exit := process.Wait() - for { - select { - case sig := <-signals: - process.Signal(sig) - case <-exit: - return - } - } -} diff --git a/vendor/github.com/tedsuo/ifrit/restart/restart.go b/vendor/github.com/tedsuo/ifrit/restart/restart.go deleted file mode 100644 index 2f339b6747f..00000000000 --- a/vendor/github.com/tedsuo/ifrit/restart/restart.go +++ /dev/null @@ -1,63 +0,0 @@ -/* -The restart package implements common restart strategies for ifrit processes. - -The API is still experimental and subject to change. -*/ -package restart - -import ( - "errors" - "os" - - "github.com/tedsuo/ifrit" -) - -// ErrNoLoadCallback is returned by Restarter if it is Invoked without a Load function. -var ErrNoLoadCallback = errors.New("ErrNoLoadCallback") - -/* -Restarter takes an inital runner and a Load function. When the inital Runner -exits, the load function is called. If the Load function retuns a Runner, the -Restarter will invoke the Runner. This continues until the Load function returns -nil, or the Restarter is signaled to stop. The Restarter returns the error of -the final Runner it invoked. -*/ -type Restarter struct { - Runner ifrit.Runner - Load func(runner ifrit.Runner, err error) ifrit.Runner -} - -func (r Restarter) Run(signals <-chan os.Signal, ready chan<- struct{}) error { - if r.Load == nil { - return ErrNoLoadCallback - } - - process := ifrit.Background(r.Runner) - processReady := process.Ready() - exit := process.Wait() - signaled := false - - for { - select { - case signal := <-signals: - process.Signal(signal) - signaled = true - - case <-processReady: - close(ready) - processReady = nil - - case err := <-exit: - if signaled { - return err - } - - r.Runner = r.Load(r.Runner, err) - if r.Runner == nil { - return err - } - process = ifrit.Background(r.Runner) - exit = process.Wait() - } - } -} diff --git a/vendor/github.com/tedsuo/ifrit/restart/strategies.go b/vendor/github.com/tedsuo/ifrit/restart/strategies.go deleted file mode 100644 index ad8e4881b38..00000000000 --- a/vendor/github.com/tedsuo/ifrit/restart/strategies.go +++ /dev/null @@ -1,22 +0,0 @@ -package restart - -import "github.com/tedsuo/ifrit" - -/* -OnError is a restart strategy for Safely Restartable Runners. It will restart the -Runner only if it exits with a matching error. -*/ -func OnError(runner ifrit.Runner, err error, errors ...error) ifrit.Runner { - errors = append(errors, err) - return &Restarter{ - Runner: runner, - Load: func(runner ifrit.Runner, err error) ifrit.Runner { - for _, restartableError := range errors { - if err == restartableError { - return runner - } - } - return nil - }, - } -} diff --git a/vendor/github.com/tedsuo/ifrit/runner.go b/vendor/github.com/tedsuo/ifrit/runner.go deleted file mode 100644 index e09bc50f4a0..00000000000 --- a/vendor/github.com/tedsuo/ifrit/runner.go +++ /dev/null @@ -1,37 +0,0 @@ -package ifrit - -import "os" - -/* -A Runner defines the contents of a Process. A Runner implementation performs an -aribtrary unit of work, while waiting for a shutdown signal. The unit of work -should avoid any orchestration. Instead, it should be broken down into simpler -units of work in seperate Runners, which are then orcestrated by the ifrit -standard library. - -An implementation of Runner has the following responibilities: - - - setup within a finite amount of time. - - close the ready channel when setup is complete. - - once ready, perform the unit of work, which may be infinite. - - respond to shutdown signals by exiting within a finite amount of time. - - return nil if shutdown is successful. - - return an error if an exception has prevented a clean shutdown. - -By default, Runners are not considered restartable; Run will only be called once. -See the ifrit/restart package for details on restartable Runners. -*/ -type Runner interface { - Run(signals <-chan os.Signal, ready chan<- struct{}) error -} - -/* -The RunFunc type is an adapter to allow the use of ordinary functions as Runners. -If f is a function that matches the Run method signature, RunFunc(f) is a Runner -object that calls f. -*/ -type RunFunc func(signals <-chan os.Signal, ready chan<- struct{}) error - -func (r RunFunc) Run(signals <-chan os.Signal, ready chan<- struct{}) error { - return r(signals, ready) -} diff --git a/vendor/github.com/tedsuo/ifrit/sigmon/sigmon.go b/vendor/github.com/tedsuo/ifrit/sigmon/sigmon.go deleted file mode 100644 index fee1e7a3be6..00000000000 --- a/vendor/github.com/tedsuo/ifrit/sigmon/sigmon.go +++ /dev/null @@ -1,48 +0,0 @@ -package sigmon - -import ( - "os" - "os/signal" - "syscall" - - "github.com/tedsuo/ifrit" -) - -const SIGNAL_BUFFER_SIZE = 1024 - -type sigmon struct { - Signals []os.Signal - Runner ifrit.Runner -} - -func New(runner ifrit.Runner, signals ...os.Signal) ifrit.Runner { - signals = append(signals, syscall.SIGINT, syscall.SIGTERM) - return &sigmon{ - Signals: signals, - Runner: runner, - } -} - -func (s sigmon) Run(signals <-chan os.Signal, ready chan<- struct{}) error { - osSignals := make(chan os.Signal, SIGNAL_BUFFER_SIZE) - signal.Notify(osSignals, s.Signals...) - - process := ifrit.Background(s.Runner) - pReady := process.Ready() - pWait := process.Wait() - - for { - select { - case sig := <-signals: - process.Signal(sig) - case sig := <-osSignals: - process.Signal(sig) - case <-pReady: - close(ready) - pReady = nil - case err := <-pWait: - signal.Stop(osSignals) - return err - } - } -} diff --git a/vendor/github.com/tedsuo/ifrit/test_helpers/test_helpers.go b/vendor/github.com/tedsuo/ifrit/test_helpers/test_helpers.go deleted file mode 100644 index d7d2c69cb12..00000000000 --- a/vendor/github.com/tedsuo/ifrit/test_helpers/test_helpers.go +++ /dev/null @@ -1,85 +0,0 @@ -package test_helpers - -import ( - "errors" - "os" - "sync" - - "github.com/tedsuo/ifrit" -) - -// PingChan stops when you send it a single Ping -type PingChan chan Ping - -type Ping struct{} - -var PingerExitedFromPing = errors.New("pinger exited with a ping") -var PingerExitedFromSignal = errors.New("pinger exited with a signal") - -func (p PingChan) Load(err error) (ifrit.Runner, bool) { - 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{}{} - for _, signal := range exitSignals { - signalSet[signal] = struct{}{} - } - - return &SignalRecoder{ - exitSignals: signalSet, - } -} - -func (r *SignalRecoder) Load(err error) (ifrit.Runner, bool) { - return r, true -} - -func (r *SignalRecoder) Run(sigChan <-chan os.Signal, ready chan<- struct{}) error { - close(ready) - - for { - signal := <-sigChan - - r.Lock() - r.signals = append(r.signals, signal) - r.Unlock() - - _, ok := r.exitSignals[signal] - if ok { - return nil - } - } -} - -func (r *SignalRecoder) ReceivedSignals() []os.Signal { - defer r.RUnlock() - r.RLock() - return r.signals -}