github.com/cloudfoundry-attic/ltc@v0.0.0-20151123212628-098adc7919fc/cli_app_factory/cli_app_factory.go (about) 1 package cli_app_factory 2 3 import ( 4 "crypto/rand" 5 "errors" 6 "fmt" 7 "io" 8 "os" 9 "runtime" 10 11 "github.com/cloudfoundry-incubator/ltc/app_examiner" 12 "github.com/cloudfoundry-incubator/ltc/app_examiner/command_factory/graphical" 13 "github.com/cloudfoundry-incubator/ltc/app_runner" 14 "github.com/cloudfoundry-incubator/ltc/blob_store" 15 "github.com/cloudfoundry-incubator/ltc/blob_store/dav_blob_store" 16 "github.com/cloudfoundry-incubator/ltc/blob_store/s3_blob_store" 17 "github.com/cloudfoundry-incubator/ltc/cluster_test" 18 "github.com/cloudfoundry-incubator/ltc/config" 19 "github.com/cloudfoundry-incubator/ltc/config/target_verifier" 20 "github.com/cloudfoundry-incubator/ltc/docker_runner/docker_metadata_fetcher" 21 "github.com/cloudfoundry-incubator/ltc/droplet_runner" 22 "github.com/cloudfoundry-incubator/ltc/droplet_runner/command_factory/cf_ignore" 23 zipper_package "github.com/cloudfoundry-incubator/ltc/droplet_runner/command_factory/zipper" 24 "github.com/cloudfoundry-incubator/ltc/exit_handler" 25 "github.com/cloudfoundry-incubator/ltc/logs" 26 "github.com/cloudfoundry-incubator/ltc/logs/console_tailed_logs_outputter" 27 "github.com/cloudfoundry-incubator/ltc/receptor_client" 28 "github.com/cloudfoundry-incubator/ltc/ssh" 29 keygen_package "github.com/cloudfoundry-incubator/ltc/ssh/keygen" 30 "github.com/cloudfoundry-incubator/ltc/task_examiner" 31 "github.com/cloudfoundry-incubator/ltc/task_runner" 32 "github.com/cloudfoundry-incubator/ltc/terminal" 33 "github.com/cloudfoundry-incubator/ltc/version" 34 "github.com/cloudfoundry/noaa" 35 "github.com/codegangsta/cli" 36 "github.com/kardianos/osext" 37 "github.com/pivotal-golang/clock" 38 "github.com/pivotal-golang/lager" 39 40 app_examiner_command_factory "github.com/cloudfoundry-incubator/ltc/app_examiner/command_factory" 41 app_runner_command_factory "github.com/cloudfoundry-incubator/ltc/app_runner/command_factory" 42 cluster_test_command_factory "github.com/cloudfoundry-incubator/ltc/cluster_test/command_factory" 43 config_command_factory "github.com/cloudfoundry-incubator/ltc/config/command_factory" 44 docker_runner_command_factory "github.com/cloudfoundry-incubator/ltc/docker_runner/command_factory" 45 droplet_runner_command_factory "github.com/cloudfoundry-incubator/ltc/droplet_runner/command_factory" 46 logs_command_factory "github.com/cloudfoundry-incubator/ltc/logs/command_factory" 47 ssh_command_factory "github.com/cloudfoundry-incubator/ltc/ssh/command_factory" 48 task_examiner_command_factory "github.com/cloudfoundry-incubator/ltc/task_examiner/command_factory" 49 task_runner_command_factory "github.com/cloudfoundry-incubator/ltc/task_runner/command_factory" 50 version_command_factory "github.com/cloudfoundry-incubator/ltc/version/command_factory" 51 ) 52 53 var ( 54 nonTargetVerifiedCommandNames = map[string]struct{}{ 55 "target": {}, 56 "help": {}, 57 } 58 59 defaultAction = func(context *cli.Context) { 60 args := context.Args() 61 if len(args) > 0 { 62 cli.ShowCommandHelp(context, args[0]) 63 } else { 64 showAppHelp(context.App.Writer, appHelpTemplate(), context.App) 65 } 66 } 67 ) 68 69 const ( 70 LtcUsage = "Command line interface for Lattice." 71 AppName = "ltc" 72 latticeCliAuthor = "Pivotal" 73 latticeCliHomeVar = "LATTICE_CLI_HOME" 74 unknownCommand = "ltc: '%s' is not a registered command. See 'ltc help'" 75 ) 76 77 func init() { 78 cli.HelpPrinter = ShowHelp 79 cli.AppHelpTemplate = appHelpTemplate() 80 cli.CommandHelpTemplate = `NAME: 81 {{join .Names ", "}} - {{.Usage}} 82 {{with .ShortName}} 83 ALIAS: 84 {{.Aliases}} 85 {{end}} 86 USAGE: 87 {{.Description}}{{with .Flags}} 88 OPTIONS: 89 {{range .}} {{.}} 90 {{end}}{{else}} 91 {{end}}` 92 } 93 94 func MakeCliApp( 95 diegoVersion string, 96 latticeVersion string, 97 ltcConfigRoot string, 98 exitHandler exit_handler.ExitHandler, 99 config *config.Config, 100 logger lager.Logger, 101 receptorClientCreator receptor_client.Creator, 102 targetVerifier target_verifier.TargetVerifier, 103 cliStdout io.Writer, 104 ) *cli.App { 105 config.Load() 106 app := cli.NewApp() 107 app.Name = AppName 108 app.Author = latticeCliAuthor 109 app.Version = defaultVersion(diegoVersion, latticeVersion) 110 app.Usage = LtcUsage 111 app.Email = "cf-lattice@lists.cloudfoundry.org" 112 113 ui := terminal.NewUI(os.Stdin, cliStdout, terminal.NewPasswordReader()) 114 app.Writer = ui 115 116 app.Before = func(context *cli.Context) error { 117 args := context.Args() 118 command := app.Command(args.First()) 119 120 if command == nil { 121 return nil 122 } 123 124 if _, ok := nonTargetVerifiedCommandNames[command.Name]; ok || len(args) == 0 { 125 return nil 126 } 127 128 for _, arg := range args { 129 if arg == "-h" || arg == "--help" { 130 return nil 131 } 132 } 133 134 if receptorUp, authorized, err := targetVerifier.VerifyTarget(config.Receptor()); !receptorUp { 135 ui.SayLine(fmt.Sprintf("Error connecting to the receptor. Make sure your lattice target is set, and that lattice is up and running.\n\tUnderlying error: %s", err)) 136 return err 137 } else if !authorized { 138 ui.SayLine("Could not authenticate with the receptor. Please run ltc target with the correct credentials.") 139 return errors.New("Could not authenticate with the receptor.") 140 } 141 return nil 142 } 143 144 app.Action = defaultAction 145 app.CommandNotFound = func(c *cli.Context, command string) { 146 ui.SayLine(fmt.Sprintf(unknownCommand, command)) 147 exitHandler.Exit(1) 148 } 149 app.Commands = cliCommands(ltcConfigRoot, exitHandler, config, logger, receptorClientCreator, targetVerifier, ui, latticeVersion) 150 return app 151 } 152 153 func cliCommands(ltcConfigRoot string, exitHandler exit_handler.ExitHandler, config *config.Config, logger lager.Logger, receptorClientCreator receptor_client.Creator, targetVerifier target_verifier.TargetVerifier, ui terminal.UI, latticeVersion string) []cli.Command { 154 receptorClient := receptorClientCreator.CreateReceptorClient(config.Receptor()) 155 noaaConsumer := noaa.NewConsumer(LoggregatorUrl(config.Loggregator()), nil, nil) 156 appRunner := app_runner.New(receptorClient, config.Target(), &keygen_package.KeyGenerator{RandReader: rand.Reader}) 157 158 clock := clock.NewClock() 159 160 logReader := logs.NewLogReader(noaaConsumer) 161 tailedLogsOutputter := console_tailed_logs_outputter.NewConsoleTailedLogsOutputter(ui, logReader) 162 163 taskExaminer := task_examiner.New(receptorClient) 164 taskExaminerCommandFactory := task_examiner_command_factory.NewTaskExaminerCommandFactory(taskExaminer, ui, exitHandler) 165 166 taskRunner := task_runner.New(receptorClient, taskExaminer, clock) 167 taskRunnerCommandFactory := task_runner_command_factory.NewTaskRunnerCommandFactory(taskRunner, ui, exitHandler) 168 169 appExaminer := app_examiner.New(receptorClient, app_examiner.NewNoaaConsumer(noaaConsumer)) 170 graphicalVisualizer := graphical.NewGraphicalVisualizer(appExaminer) 171 dockerTerminal := &app_examiner_command_factory.DockerTerminal{} 172 appExaminerCommandFactory := app_examiner_command_factory.NewAppExaminerCommandFactory(appExaminer, ui, dockerTerminal, clock, exitHandler, graphicalVisualizer, taskExaminer, config.Target()) 173 174 appRunnerCommandFactoryConfig := app_runner_command_factory.AppRunnerCommandFactoryConfig{ 175 AppRunner: appRunner, 176 AppExaminer: appExaminer, 177 UI: ui, 178 Domain: config.Target(), 179 Env: os.Environ(), 180 Clock: clock, 181 Logger: logger, 182 TailedLogsOutputter: tailedLogsOutputter, 183 ExitHandler: exitHandler, 184 } 185 186 appRunnerCommandFactory := app_runner_command_factory.NewAppRunnerCommandFactory(appRunnerCommandFactoryConfig) 187 188 dockerRunnerCommandFactoryConfig := docker_runner_command_factory.DockerRunnerCommandFactoryConfig{ 189 AppRunner: appRunner, 190 AppExaminer: appExaminer, 191 UI: ui, 192 Domain: config.Target(), 193 Env: os.Environ(), 194 Clock: clock, 195 Logger: logger, 196 ExitHandler: exitHandler, 197 TailedLogsOutputter: tailedLogsOutputter, 198 DockerMetadataFetcher: docker_metadata_fetcher.New(docker_metadata_fetcher.NewDockerSessionFactory()), 199 } 200 dockerRunnerCommandFactory := docker_runner_command_factory.NewDockerRunnerCommandFactory(dockerRunnerCommandFactoryConfig) 201 202 logsCommandFactory := logs_command_factory.NewLogsCommandFactory(appExaminer, taskExaminer, ui, tailedLogsOutputter, exitHandler) 203 204 clusterTestRunner := cluster_test.NewClusterTestRunner(config, ltcConfigRoot) 205 clusterTestCommandFactory := cluster_test_command_factory.NewClusterTestCommandFactory(clusterTestRunner) 206 207 blobStore := blob_store.New(config) 208 blobStoreVerifier := blob_store.BlobStoreVerifier{ 209 DAVBlobStoreVerifier: dav_blob_store.Verifier{}, 210 S3BlobStoreVerifier: s3_blob_store.Verifier{}, 211 } 212 213 httpProxyConfReader := &droplet_runner.HTTPProxyConfReader{ 214 URL: fmt.Sprintf("http://%s:8444/proxyconf.json", config.Target()), 215 } 216 dropletRunner := droplet_runner.New(appRunner, taskRunner, config, blobStore, appExaminer, httpProxyConfReader) 217 cfIgnore := cf_ignore.New() 218 zipper := &zipper_package.DropletArtifactZipper{} 219 dropletRunnerCommandFactory := droplet_runner_command_factory.NewDropletRunnerCommandFactory(*appRunnerCommandFactory, blobStoreVerifier, taskExaminer, dropletRunner, cfIgnore, zipper, config) 220 221 versionManager := version.NewVersionManager(receptorClientCreator, &version.AppFileSwapper{}, defaultLatticeVersion(latticeVersion)) 222 configCommandFactory := config_command_factory.NewConfigCommandFactory(config, ui, targetVerifier, blobStoreVerifier, exitHandler, versionManager) 223 224 sshCommandFactory := ssh_command_factory.NewSSHCommandFactory(config, ui, exitHandler, appExaminer, ssh.New(exitHandler)) 225 226 ltcPath, _ := osext.Executable() 227 versionCommandFactory := version_command_factory.NewVersionCommandFactory(config, ui, exitHandler, runtime.GOOS, ltcPath, versionManager) 228 229 helpCommand := cli.Command{ 230 Name: "help", 231 Aliases: []string{"h"}, 232 Usage: "Shows a list of commands or help for one command", 233 Description: "ltc help", 234 Action: defaultAction, 235 } 236 237 return []cli.Command{ 238 appExaminerCommandFactory.MakeCellsCommand(), 239 dockerRunnerCommandFactory.MakeCreateAppCommand(), 240 appRunnerCommandFactory.MakeSubmitLrpCommand(), 241 logsCommandFactory.MakeDebugLogsCommand(), 242 appExaminerCommandFactory.MakeListAppCommand(), 243 logsCommandFactory.MakeLogsCommand(), 244 appRunnerCommandFactory.MakeRemoveAppCommand(), 245 appRunnerCommandFactory.MakeScaleAppCommand(), 246 appExaminerCommandFactory.MakeStatusCommand(), 247 taskRunnerCommandFactory.MakeSubmitTaskCommand(), 248 configCommandFactory.MakeTargetCommand(), 249 taskExaminerCommandFactory.MakeTaskCommand(), 250 taskRunnerCommandFactory.MakeDeleteTaskCommand(), 251 taskRunnerCommandFactory.MakeCancelTaskCommand(), 252 clusterTestCommandFactory.MakeClusterTestCommand(), 253 appRunnerCommandFactory.MakeUpdateCommand(), 254 appExaminerCommandFactory.MakeVisualizeCommand(), 255 dropletRunnerCommandFactory.MakeBuildDropletCommand(), 256 dropletRunnerCommandFactory.MakeListDropletsCommand(), 257 dropletRunnerCommandFactory.MakeLaunchDropletCommand(), 258 dropletRunnerCommandFactory.MakeRemoveDropletCommand(), 259 dropletRunnerCommandFactory.MakeImportDropletCommand(), 260 dropletRunnerCommandFactory.MakeExportDropletCommand(), 261 sshCommandFactory.MakeSSHCommand(), 262 versionCommandFactory.MakeSyncCommand(), 263 versionCommandFactory.MakeVersionCommand(), 264 helpCommand, 265 } 266 } 267 268 func LoggregatorUrl(loggregatorTarget string) string { 269 return "ws://" + loggregatorTarget 270 } 271 272 func defaultDiegoVersion(diegoVersion string) string { 273 if diegoVersion == "" { 274 diegoVersion = "unknown" 275 } 276 return diegoVersion 277 } 278 func defaultLatticeVersion(latticeVersion string) string { 279 if latticeVersion == "" { 280 latticeVersion = "development (not versioned)" 281 } 282 return latticeVersion 283 } 284 285 func defaultVersion(diegoVersion, latticeVersion string) string { 286 return fmt.Sprintf("%s (diego %s)", defaultLatticeVersion(latticeVersion), defaultDiegoVersion(diegoVersion)) 287 } 288 289 func appHelpTemplate() string { 290 return `NAME: 291 {{.Name}} - {{.Usage}} 292 293 USAGE: 294 {{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] 295 296 VERSION: 297 {{.Version}} 298 299 AUTHOR(S): 300 {{range .Authors}}{{.}} 301 {{end}} 302 303 COMMANDS: 304 {{range .Commands}} 305 {{.SubTitle .Name}}{{range .CommandSubGroups}} 306 {{range .}} {{.Name}} {{.Description}} 307 {{end}}{{end}}{{end}} 308 GLOBAL OPTIONS: 309 --version, -v Print the version 310 --help, -h Show help 311 ` 312 }