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  }