func (factory *DockerRunnerCommandFactory) createApp(context *cli.Context) {
	workingDirFlag := context.String("working-dir")
	envVarsFlag := context.StringSlice("env")
	instancesFlag := context.Int("instances")
	cpuWeightFlag := uint(context.Int("cpu-weight"))
	memoryMBFlag := context.Int("memory-mb")
	diskMBFlag := context.Int("disk-mb")
	userFlag := context.String("user")
	runAsRootFlag := context.Bool("run-as-root")
	privilegedFlag := context.Bool("privileged")
	portsFlag := context.String("ports")
	noMonitorFlag := context.Bool("no-monitor")
	portMonitorFlag := context.Int("monitor-port")
	urlMonitorFlag := context.String("monitor-url")
	monitorTimeoutFlag := context.Duration("monitor-timeout")
	monitorCommandFlag := context.String("monitor-command")
	httpRouteFlag := context.StringSlice("http-route")
	tcpRouteFlag := context.StringSlice("tcp-route")
	noRoutesFlag := context.Bool("no-routes")
	timeoutFlag := context.Duration("timeout")
	name := context.Args().Get(0)
	dockerPath := context.Args().Get(1)
	terminator := context.Args().Get(2)
	startCommand := context.Args().Get(3)

	var appArgs []string
	switch {
	case len(context.Args()) < 2:
		factory.UI.SayIncorrectUsage("<app-name> and <docker-image> are required")
		factory.ExitHandler.Exit(exit_codes.InvalidSyntax)
		return
	case startCommand != "" && terminator != "--":
		factory.UI.SayIncorrectUsage("'--' Required before start command")
		factory.ExitHandler.Exit(exit_codes.InvalidSyntax)
		return
	case len(context.Args()) > 4:
		appArgs = context.Args()[4:]
	case cpuWeightFlag < 1 || cpuWeightFlag > 100:
		factory.UI.SayIncorrectUsage("Invalid CPU Weight")
		factory.ExitHandler.Exit(exit_codes.InvalidSyntax)
		return
	}

	httpRoutesFlag := context.String("http-routes")
	if httpRoutesFlag != "" {
		factory.UI.SayIncorrectUsage("Unable to parse routes\n  Pass multiple --http-route flags instead of comma-delimiting.  See help page for details.")
		factory.ExitHandler.Exit(exit_codes.InvalidSyntax)
		return
	}

	tcpRoutesFlag := context.String("tcp-routes")
	if tcpRoutesFlag != "" {
		factory.UI.SayIncorrectUsage("Unable to parse routes\n  Pass multiple --tcp-route flags instead of comma-delimiting.  See help page for details.")
		factory.ExitHandler.Exit(exit_codes.InvalidSyntax)
		return
	}

	imageMetadata, err := factory.dockerMetadataFetcher.FetchMetadata(dockerPath)
	if err != nil {
		factory.UI.SayLine(fmt.Sprintf("Error fetching image metadata: %s", err))
		factory.ExitHandler.Exit(exit_codes.BadDocker)
		return
	}

	if privilegedFlag {
		factory.UI.SayLine("Warning: It is possible for a privileged app to break out of its container and access the host OS!")
	}

	if runAsRootFlag {
		userFlag = "root"
		factory.UI.SayLine("Warning: run-as-root has been deprecated, please use '--user=root' instead)")
	}

	if userFlag == "" {
		if imageMetadata.User != "" {
			userFlag = imageMetadata.User
			factory.UI.SayLine("Setting the user to %s (obtained from docker image metadata)...", imageMetadata.User)
		} else {
			userFlag = "root"
			factory.UI.SayLine("Warning: No container user specified to run your app, your app will be run as root!")
		}
	} else {
		factory.UI.SayLine("Setting the user to %s from option...", userFlag)
	}

	exposedPorts, err := factory.getExposedPortsFromArgs(portsFlag, imageMetadata)
	if err != nil {
		factory.UI.SayLine(err.Error())
		factory.ExitHandler.Exit(exit_codes.InvalidSyntax)
		return
	}

	monitorConfig, err := factory.GetMonitorConfig(exposedPorts, portMonitorFlag, noMonitorFlag, urlMonitorFlag, monitorCommandFlag, monitorTimeoutFlag)
	if err != nil {
		factory.UI.SayLine(err.Error())
		if err.Error() == command_factory.MonitorPortNotExposed {
			factory.ExitHandler.Exit(exit_codes.CommandFailed)
		} else {
			factory.ExitHandler.Exit(exit_codes.InvalidSyntax)
		}
		return
	}

	if workingDirFlag == "" {
		factory.UI.SayLine("No working directory specified, using working directory from the image metadata...")
		if imageMetadata.WorkingDir != "" {
			workingDirFlag = imageMetadata.WorkingDir
			factory.UI.SayLine("Working directory is:")
			factory.UI.SayLine(workingDirFlag)
		} else {
			workingDirFlag = "/"
		}
	}

	switch {
	case monitorCommandFlag != "":
		factory.UI.SayLine(fmt.Sprintf("Monitoring the app with command %s", monitorConfig.CustomCommand))
	case !noMonitorFlag:
		factory.UI.SayLine(fmt.Sprintf("Monitoring the app on port %d...", monitorConfig.Port))
	default:
		factory.UI.SayLine("No ports will be monitored.")
	}

	if startCommand == "" {
		if len(imageMetadata.StartCommand) == 0 {
			factory.UI.SayLine("Unable to determine start command from image metadata.")
			factory.ExitHandler.Exit(exit_codes.BadDocker)
			return
		}

		factory.UI.SayLine("No start command specified, using start command from the image metadata...")
		startCommand = imageMetadata.StartCommand[0]

		factory.UI.SayLine("Start command is:")
		factory.UI.SayLine(strings.Join(imageMetadata.StartCommand, " "))

		appArgs = imageMetadata.StartCommand[1:]
	}

	routeOverrides, err := factory.ParseRouteOverrides(httpRouteFlag, exposedPorts)
	if err != nil {
		factory.UI.SayLine(err.Error())
		factory.ExitHandler.Exit(exit_codes.InvalidSyntax)
		return
	}

	tcpRoutes, err := factory.ParseTcpRoutes(tcpRouteFlag, exposedPorts)
	if err != nil {
		factory.UI.SayLine(err.Error())
		factory.ExitHandler.Exit(exit_codes.InvalidSyntax)
		return
	}

	rootFS, err := docker_repository_name_formatter.FormatForReceptor(dockerPath)
	if err != nil {
		factory.UI.SayLine(err.Error())
		factory.ExitHandler.Exit(exit_codes.CommandFailed)
		return
	}

	envVars := map[string]string{}

	for _, dockerEnv := range imageMetadata.Env {
		split := strings.SplitN(dockerEnv, "=", 2)
		if len(split) == 2 {
			envVars[split[0]] = split[1]
		}
	}

	appEnvVars := factory.BuildAppEnvironment(envVarsFlag, name)
	for appEnvKey := range appEnvVars {
		envVars[appEnvKey] = appEnvVars[appEnvKey]
	}

	err = factory.AppRunner.CreateApp(app_runner.CreateAppParams{
		AppEnvironmentParams: app_runner.AppEnvironmentParams{
			EnvironmentVariables: envVars,
			User:                 userFlag,
			Privileged:           privilegedFlag,
			Monitor:              monitorConfig,
			Instances:            instancesFlag,
			CPUWeight:            cpuWeightFlag,
			MemoryMB:             memoryMBFlag,
			DiskMB:               diskMBFlag,
			ExposedPorts:         exposedPorts,
			WorkingDir:           workingDirFlag,
			RouteOverrides:       routeOverrides,
			TcpRoutes:            tcpRoutes,
			NoRoutes:             noRoutesFlag,
		},

		Name:         name,
		RootFS:       rootFS,
		StartCommand: startCommand,
		AppArgs:      appArgs,
		Timeout:      timeoutFlag,
	})
	if err != nil {
		factory.UI.SayLine(fmt.Sprintf("Error creating app: %s", err))
		factory.ExitHandler.Exit(exit_codes.CommandFailed)
		return
	}

	factory.WaitForAppCreation(name, timeoutFlag, instancesFlag)
}
package docker_repository_name_formatter_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/cloudfoundry-incubator/ltc/docker_runner/docker_repository_name_formatter"
)

var _ = Describe("DockerRepositoryNameFormatter", func() {

	Describe("FormatForReceptor", func() {
		Context("with a well-formed docker repo name", func() {
			Context("with a fully qualified docker repo name", func() {
				It("Formats it as a url that the receptor can use as a rootfs", func() {
					formattedName, err := docker_repository_name_formatter.FormatForReceptor("jimbo/my-docker-app")
					Expect(err).NotTo(HaveOccurred())
					Expect(formattedName).To(Equal("docker:///jimbo/my-docker-app#latest"))
				})

				Context("when a tag is specified", func() {
					It("Converts it to a tagged url that receptor can use as a rootfs", func() {
						formattedName, err := docker_repository_name_formatter.FormatForReceptor("jimbo/my-docker-app:test")
						Expect(err).NotTo(HaveOccurred())
						Expect(formattedName).To(Equal("docker:///jimbo/my-docker-app#test"))
					})
				})
			})

			Context("with a shortened official docker repo name", func() {
				It("Formats it as a url that the receptor can use as a rootfs", func() {