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)
	}
}
								"wan": ["wan-server1", "wan-server2", "wan-server3"]
							},
							"dns_config": {
								"allow_stale": true,
								"max_stale": "15s",
								"recursor_timeout": "15s"
							}
						},
						"encrypt_keys": ["key-1", "key-2"]
					},
					"confab": {
						"timeout_in_seconds": 30
					}
				}`)

				cfg, err := config.ConfigFromJSON(json)
				Expect(err).NotTo(HaveOccurred())
				Expect(cfg).To(Equal(config.Config{
					Path: config.ConfigPath{
						AgentPath:       "/path/to/agent",
						ConsulConfigDir: "/consul/config/dir",
						PIDFile:         "/path/to/pidfile",
						KeyringFile:     "/path/to/keyring",
						DataDir:         "/path/to/data/dir",
					},
					Node: config.ConfigNode{
						Name:       "nodename",
						Index:      1234,
						ExternalIP: "10.0.0.1",
					},
					Consul: config.ConfigConsul{