// templateRunner returns a consul-template runner for the given templates and a // lookup by destination to the template. If no templates are given, a nil // template runner and lookup is returned. func templateRunner(tmpls []*structs.Template, config *config.Config, vaultToken, taskDir string, taskEnv *env.TaskEnvironment) ( *manager.Runner, map[string][]*structs.Template, error) { if len(tmpls) == 0 { return nil, nil, nil } runnerConfig, err := runnerConfig(config, vaultToken) if err != nil { return nil, nil, err } // Parse the templates allowAbs := config.ReadBoolDefault(hostSrcOption, true) ctmplMapping, err := parseTemplateConfigs(tmpls, taskDir, taskEnv, allowAbs) if err != nil { return nil, nil, err } // Set the config flat := make([]*ctconf.ConfigTemplate, 0, len(ctmplMapping)) for ctmpl := range ctmplMapping { local := ctmpl flat = append(flat, &local) } runnerConfig.ConfigTemplates = flat runner, err := manager.NewRunner(runnerConfig, false, false) if err != nil { return nil, nil, err } // Build the lookup idMap := runner.ConfigTemplateMapping() lookup := make(map[string][]*structs.Template, len(idMap)) for id, ctmpls := range idMap { for _, ctmpl := range ctmpls { templates := lookup[id] templates = append(templates, ctmplMapping[ctmpl]) lookup[id] = templates } } return runner, lookup, nil }
// Run accepts a slice of arguments and returns an int representing the exit // status from the command. func (cli *CLI) Run(args []string) int { // Parse the flags config, once, dry, version, err := cli.ParseFlags(args[1:]) if err != nil { if err == flag.ErrHelp { return 0 } return cli.handleError(err, ExitCodeParseFlagsError) } // Save original config (defaults + parsed flags) for handling reloads baseConfig := config.Copy() // Setup the config and logging config, err = cli.setup(config) if err != nil { return cli.handleError(err, ExitCodeConfigError) } // Print version information for debugging log.Printf("[INFO] %s", humanVersion) // If the version was requested, return an "error" containing the version // information. This might sound weird, but most *nix applications actually // print their version on stderr anyway. if version { log.Printf("[DEBUG] (cli) version flag was given, exiting now") fmt.Fprintf(cli.errStream, "%s\n", humanVersion) return ExitCodeOK } // Initial runner runner, err := manager.NewRunner(config, dry, once) if err != nil { return cli.handleError(err, ExitCodeRunnerError) } go runner.Start() // Listen for signals signal.Notify(cli.signalCh) for { select { case err := <-runner.ErrCh: // Check if the runner's error returned a specific exit status, and return // that value. If no value was given, return a generic exit status. code := ExitCodeRunnerError if typed, ok := err.(manager.ErrExitable); ok { code = typed.ExitStatus() } return cli.handleError(err, code) case <-runner.DoneCh: return ExitCodeOK case s := <-cli.signalCh: log.Printf("[DEBUG] (cli) receiving signal %q", s) switch s { case *config.ReloadSignal: fmt.Fprintf(cli.errStream, "Reloading configuration...\n") runner.Stop() // Load the new configuration from disk config, err = cli.setup(baseConfig) if err != nil { return cli.handleError(err, ExitCodeConfigError) } runner, err = manager.NewRunner(config, dry, once) if err != nil { return cli.handleError(err, ExitCodeRunnerError) } go runner.Start() case *config.KillSignal: fmt.Fprintf(cli.errStream, "Cleaning up...\n") runner.Stop() return ExitCodeInterrupt case signals.SignalLookup["SIGCHLD"]: // The SIGCHLD signal is sent to the parent of a child process when it // exits, is interrupted, or resumes after being interrupted. We ignore // this signal because the child process is monitored on its own. // // Also, the reason we do a lookup instead of a direct syscall.SIGCHLD // is because that isn't defined on Windows. default: // Propogate the signal to the child process runner.Signal(s) } case <-cli.stopCh: return ExitCodeOK } } }