pidFile *os.File
		)

		BeforeEach(func() {
			var err error

			pidFile, err = ioutil.TempFile("", "")
			Expect(err).NotTo(HaveOccurred())
		})

		DescribeTable("when the pidfile exists",
			func(pid string, isRunning bool) {
				err := ioutil.WriteFile(pidFile.Name(), []byte(pid), os.ModePerm)
				Expect(err).NotTo(HaveOccurred())

				processIsRunning := utils.IsRunningProcess(pidFile.Name())
				Expect(processIsRunning).To(Equal(isRunning))
			},
			Entry("returns false if the process is not running", "-1", false),
			Entry("returns true if the process is running", strconv.Itoa(os.Getpid()), true),
			Entry("returns false if the pidfile contains garbage", "something-bad", false),
		)

		It("returns false if the pidfile does not exist", func() {
			processIsRunning := utils.IsRunningProcess("/nonexistent/pidfile")
			Expect(processIsRunning).To(BeFalse())
		})
	})

	DescribeTable("IsPIDRunning",
		func(pid int, expected bool) {
					conn.Close()
				}
				return err
			}, "5s").Should(Succeed())

			pid, err := getPID(pidFile.Name())
			Expect(err).NotTo(HaveOccurred())

			cmd = exec.Command(pathToConfab,
				"stop",
				"--config-file", configFile.Name(),
			)
			Eventually(cmd.Run, COMMAND_TIMEOUT, COMMAND_TIMEOUT).Should(Succeed())

			Eventually(func() bool {
				return utils.IsRunningProcess(pidFile.Name())
			}, "5s").Should(BeFalse())

			Eventually(func() (FakeAgentOutputData, error) {
				return fakeAgentOutputFromFile(consulConfigDir, "fake-output-2.json")
			}, COMMAND_TIMEOUT, POLL_INTERVAL).Should(Equal(FakeAgentOutputData{
				PID: pid,
				Args: []string{
					"agent",
					fmt.Sprintf("-config-dir=%s", consulConfigDir),
				},
				ConsulConfig: ConsulConfig{
					Server:    true,
					Bootstrap: true,
				},
				LeaveCallCount:      1,
func main() {
	flagSet := flag.NewFlagSet("flags", flag.ContinueOnError)
	flagSet.Var(&recursors, "recursor", "specifies the address of an upstream DNS `server`, may be specified multiple times")
	flagSet.StringVar(&configFile, "config-file", "", "specifies the config `file`")
	flagSet.BoolVar(&foreground, "foreground", false, "if true confab will wait for consul to exit")

	if len(os.Args) < 2 {
		printUsageAndExit("invalid number of arguments", flagSet)
	}

	if err := flagSet.Parse(os.Args[2:]); err != nil {
		os.Exit(1)
	}

	configFileContents, err := ioutil.ReadFile(configFile)
	if err != nil {
		stderr.Printf("error reading configuration file: %s", err)
		os.Exit(1)
	}

	cfg, err := config.ConfigFromJSON(configFileContents)
	if err != nil {
		stderr.Printf("error reading configuration file: %s", err)
		os.Exit(1)
	}

	path, err := exec.LookPath(cfg.Path.AgentPath)
	if err != nil {
		printUsageAndExit(fmt.Sprintf("\"agent_path\" %q cannot be found", cfg.Path.AgentPath), flagSet)
	}

	if len(cfg.Path.PIDFile) == 0 {
		printUsageAndExit("\"pid_file\" cannot be empty", flagSet)
	}

	logger := lager.NewLogger("confab")
	logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.INFO))

	agentRunner := &agent.Runner{
		Path:      path,
		PIDFile:   cfg.Path.PIDFile,
		ConfigDir: cfg.Path.ConsulConfigDir,
		Recursors: recursors,
		Stdout:    os.Stdout,
		Stderr:    os.Stderr,
		Logger:    logger,
	}

	consulAPIClient, err := api.NewClient(api.DefaultConfig())
	if err != nil {
		panic(err) // not tested, NewClient never errors
	}

	agentClient := &agent.Client{
		ExpectedMembers: cfg.Consul.Agent.Servers.LAN,
		ConsulAPIAgent:  consulAPIClient.Agent(),
		ConsulRPCClient: nil,
		Logger:          logger,
	}

	retrier := utils.NewRetrier(clock.NewClock(), 1*time.Second)

	controller := chaperon.Controller{
		AgentRunner:    agentRunner,
		AgentClient:    agentClient,
		Retrier:        retrier,
		EncryptKeys:    cfg.Consul.EncryptKeys,
		Logger:         logger,
		ServiceDefiner: config.ServiceDefiner{logger},
		ConfigDir:      cfg.Path.ConsulConfigDir,
		Config:         cfg,
	}

	keyringRemover := chaperon.NewKeyringRemover(cfg.Path.KeyringFile, logger)
	configWriter := chaperon.NewConfigWriter(cfg.Path.ConsulConfigDir, logger)

	var r runner = chaperon.NewClient(controller, consulagent.NewRPCClient, keyringRemover, configWriter)
	if controller.Config.Consul.Agent.Mode == "server" {
		bootstrapChecker := chaperon.NewBootstrapChecker(logger, agentClient, status.Client{ConsulAPIStatus: consulAPIClient.Status()}, time.Sleep)
		r = chaperon.NewServer(controller, configWriter, consulagent.NewRPCClient, bootstrapChecker)
	}

	switch os.Args[1] {
	case "start":
		_, err = os.Stat(controller.Config.Path.ConsulConfigDir)
		if err != nil {
			printUsageAndExit(fmt.Sprintf("\"consul_config_dir\" %q could not be found",
				controller.Config.Path.ConsulConfigDir), flagSet)
		}

		if utils.IsRunningProcess(agentRunner.PIDFile) {
			stderr.Println("consul_agent is already running, please stop it first")
			os.Exit(1)
		}

		if len(agentClient.ExpectedMembers) == 0 {
			printUsageAndExit("at least one \"expected-member\" must be provided", flagSet)
		}

		timeout := utils.NewTimeout(time.After(time.Duration(controller.Config.Confab.TimeoutInSeconds) * time.Second))

		if err := r.Start(cfg, timeout); err != nil {
			stderr.Printf("error during start: %s", err)
			r.Stop()
			os.Exit(1)
		}
		if foreground {
			if err := agentRunner.Wait(); err != nil {
				stderr.Printf("error during wait: %s", err)
				r.Stop()
				os.Exit(1)
			}
		}
	case "stop":
		if err := r.Stop(); err != nil {
			stderr.Printf("error during stop: %s", err)
			os.Exit(1)
		}
	default:
		printUsageAndExit(fmt.Sprintf("invalid COMMAND %q", os.Args[1]), flagSet)
	}
}