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() {