* 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/alecthomas/kingpin" "github.com/aphistic/gomol" "bitbucket.org/rw_grim/convey/config" "bitbucket.org/rw_grim/convey/environment" "bitbucket.org/rw_grim/convey/loaders/bitbucket" "bitbucket.org/rw_grim/convey/loaders/convey" "bitbucket.org/rw_grim/convey/logging" "bitbucket.org/rw_grim/convey/runners" "bitbucket.org/rw_grim/convey/ssh" "bitbucket.org/rw_grim/convey/state" app = kingpin.New("convey", "container runner").Version(version) color = app.Flag("color", "Enable colorized output").Default("true").Bool() configLoader = app.Flag("config-loader", "Select the configuration loader").Short('l').Default("convey").Enum("convey", "bitbucket") configFile = app.Flag("config", "The config file name to use").Short('f').String() cpuShares = app.Flag("cpu-shares", "The amount of cpu shares to give to a run task").Short('c').String() dockerConfig = app.Flag("docker-config", "Location of docker client config files").String() env = app.Flag("env", "Set environment variables").Short('e').Strings() forceSequential = app.Flag("force-sequential", "Don't run anything concurrently").Short('S').Default("False").Bool() graphviz = app.Flag("graphviz", "Output a graphviz diagram of the config file").Short('g').Default("False").Bool() keep = app.Flag("keep", "Keep the workspace volume").Short('k').Hidden().Default("False").Bool() listTasks = app.Flag("list-tasks", "List the supported tasks").Short('L').Default("false").Bool() listMetaPlans = app.Flag("list-meta-plans", "List the meta plans that are available").Short('M').Default("false").Bool() listPlans = app.Flag("list-plans", "List the plans that are available").Short('P').Default("false").Bool() memory = app.Flag("memory", "The ammount of memor to give the run task").Short('m').String() showConfig = app.Flag("show-config", "Show a dump of the config file").Short('C').Hidden().Default("false").Bool() sshAgent = app.Flag("ssh-agent", "A shortcut for --ssh-identity=*").Default("false").Bool() sshIdentities = app.Flag("ssh-identity", "Enable ssh-agent for the given identities").Strings() taskTimeout = app.Flag("timeout", "The maximum amount of time a task can run. 0 to disable. Units must be specified.").Default("15m").Duration() verbose = app.Flag("verbose", "Be more verbose").Short('v').Default("False").Bool() planNames = app.Arg("plan", "The plan or list of plans to run in specified order").Strings() loader = &convey.Loader{} loader = &bitbucket.Loader{} // if a config file was not provided search for the loader's default file for _, filename := range loader.Filenames() { if _, err := os.Stat(filename); os.IsNotExist(err) { // now make sure we found a config file fmt.Printf("config file not found, looking for %s\n", strings.Join(loader.Filenames(), ",")) cfg, err := config.LoadFile(*configFile, loader) if err := logging.Setup(*color, *verbose); err != nil { fmt.Printf("failed to setup logging: %s\n", err) defer gomol.ShutdownLoggers() // find our default environment variables and then update them with the // values from the command line defEnv := environment.Initialize() // if the user specified the shortcut, add * to the list of acceptable keys *sshIdentities = append(*sshIdentities, "*") // now merge in the keys from the config *sshIdentities = append(*sshIdentities, cfg.SSHIdentities...) // now check if we have any keys and make sure one of them is usable enableSSHAgent, err := ssh.ShouldEnable(*sshIdentities) ForceSequential: *forceSequential, EnableSSHAgent: enableSSHAgent, TaskTimeout: *taskTimeout, Environment: environment.Merge(defEnv, *env), DockerConfig: *dockerConfig, if err := st.Valid(); err != nil { var runner runners.Runner runner = &runners.Graphviz{} } else if *listMetaPlans { runner = &runners.ListMetaPlans{} runner = &runners.ListPlans{} runner = &runners.ListTasks{} runner = &runners.ShowConfig{} runner = &runners.Default{} if len(*planNames) == 0 { *planNames = []string{loader.DefaultPlan()} // resolve the plan name with the load and options for _, planName := range *planNames { if metaPlan, found := cfg.MetaPlans[planName]; found { realPlans = append(realPlans, metaPlan.Plans...) realPlans = append(realPlans, loader.ResolvePlanName(planName, cfg, st)) exitCode = runner.Run(cfg, realPlans, *env, st)