* Copyright 2016-2017 Gary Kramlich <grim@reaperworld.com> * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. "github.com/mattn/go-shellwords" "bitbucket.org/rw_grim/convey/logging" "github.com/aphistic/gomol" func Run(name, cmdTemplate string, params map[string]interface{}, timeout time.Duration) error { logger = logging.NewAdapter(name) outCollector = newLogCollector(logger, gomol.LevelInfo) errCollector = newLogCollector(logger, gomol.LevelError) return run(name, cmdTemplate, params, timeout, outCollector, errCollector) func RunOutput(name, cmdTemplate string, params map[string]interface{}, timeout time.Duration) (string, string, error) { outCollector = newStringCollector(wg) errCollector = newStringCollector(wg) err := run(name, cmdTemplate, params, timeout, outCollector.handler, errCollector.handler) return outCollector.output, errCollector.output, err func execTemplate(name, cmdTemplate string, params map[string]interface{}) ([]string, error) { // we use multiline comments to make the code readable, which leaves // embedding newlines, so remove those. cleanTemplate := strings.Replace(cmdTemplate, "\n", "", -1) // go's template stuff is *NOT* thread safe, so we need to lock around it tmpl, err := template.New(name).Parse(cleanTemplate) // now execute the template err = tmpl.Execute(cmd, params) return shellwords.Parse(cmd.String()) func run(name, cmdTemplate string, params map[string]interface{}, timeout time.Duration, outHandler, errHandler collector) error { logger := logging.NewAdapter(name) cmdv, err := execTemplate(name, cmdTemplate, params) logger.Debugf("running command \"%v\"", cmdv) cmd := exec.Command(cmdv[0], cmdv[1:]...) // setup the stdout wrapper outReader, err := cmd.StdoutPipe() // setup the stderr wrapper errReader, err := cmd.StderrPipe() // Pass output to the handlers go outHandler(bufio.NewScanner(outReader)) go errHandler(bufio.NewScanner(errReader)) timer = time.AfterFunc(timeout, func() { // kill process, unblock the cmd.Wait() below // log that the process timed out logger.Errorf("command %v timed out after %v", cmdv, timeout)