func (ctx *CommandContext) deployContainers(c *cobra.Command, args []string) { if len(args) < 1 { cmd.Fail(1, "Valid arguments: <deployment_file|URL> <host> ...") } t := ctx.Transport.Get() path := args[0] if path == "" { cmd.Fail(1, "Argument 1 must be deployment file or URL describing how the containers are related") } u, err := url.Parse(path) if nil != err { cmd.Fail(1, "Cannot Parse Argument 1: %s", err.Error()) } var deploy *deployment.Deployment switch u.Scheme { case "": deploy, err = deployment.NewDeploymentFromFile(u.Path) case "file": deploy, err = deployment.NewDeploymentFromFile(u.Path) case "http", "https": deploy, err = deployment.NewDeploymentFromURL(u.String(), *ctx.Insecure, time.Duration(ctx.timeout)) default: cmd.Fail(1, "Unsupported URL Scheme '%s' for deployment", u.Scheme) } if nil != err { cmd.Fail(1, "Unable to load deployment from %s: %s", path, err.Error()) } if len(args) == 1 { args = append(args, transport.Local.String()) } servers, err := transport.NewTransportLocators(t, args[1:]...) if err != nil { cmd.Fail(1, "You must pass zero or more valid host names (use '%s' or pass no arguments for the current server): %s", transport.Local.String(), err.Error()) } re := regexp.MustCompile("\\.\\d{8}\\-\\d{6}\\z") now := time.Now().Format(".20060102-150405") base := filepath.Base(path) base = re.ReplaceAllString(base, "") newPath := base + now fmt.Printf("==> Deploying %s\n", path) changes, removed, err := deploy.Describe(deployment.SimplePlacement(servers), t) if err != nil { cmd.Fail(1, "Deployment is not valid: %s", err.Error()) } if len(removed) > 0 { removedIds, err := LocatorsForDeploymentInstances(t, removed) if err != nil { cmd.Fail(1, "Unable to generate deployment info: %s", err.Error()) } failures := cmd.Executor{ On: removedIds, Serial: func(on cmd.Locator) cmd.JobRequest { return &cjobs.DeleteContainerRequest{ Id: cloc.AsIdentifier(on), } }, Output: os.Stdout, OnSuccess: func(r *cmd.CliJobResponse, w io.Writer, job cmd.RequestedJob) { fmt.Fprintf(w, "==> Deleted %s", string(job.Request.(*cjobs.DeleteContainerRequest).Id)) }, Transport: t, }.Stream() for i := range failures { fmt.Fprintf(os.Stderr, failures[i].Error()) } } addedIds, err := LocatorsForDeploymentInstances(t, changes.Instances.Added()) if err != nil { cmd.Fail(1, "Unable to generate deployment info: %s", err.Error()) } errors := cmd.Executor{ On: addedIds, Serial: func(on cmd.Locator) cmd.JobRequest { instance, _ := changes.Instances.Find(cloc.AsIdentifier(on)) links := instance.NetworkLinks() return &cjobs.InstallContainerRequest{ RequestIdentifier: jobs.NewRequestIdentifier(), Id: instance.Id, Image: instance.Image, Environment: instance.EnvironmentVariables(), Isolate: ctx.isolate, Ports: instance.Ports.PortPairs(), NetworkLinks: &links, } }, OnSuccess: func(r *cmd.CliJobResponse, w io.Writer, job cmd.RequestedJob) { installJob := job.Request.(*cjobs.InstallContainerRequest) instance, _ := changes.Instances.Find(installJob.Id) if pairs, ok := installJob.PortMappingsFrom(r.Pending); ok { if !instance.Ports.Update(pairs) { fmt.Fprintf(os.Stderr, "Not all ports listed %+v were returned by the server %+v", instance.Ports, pairs) } } }, Output: os.Stdout, Transport: t, }.Stream() changes.UpdateLinks() for _, c := range changes.Containers { instances := c.Instances() if len(instances) > 0 { for _, link := range instances[0].NetworkLinks() { fmt.Printf("==> Linking %s: %s:%d -> %s:%d\n", c.Name, link.FromHost, link.FromPort, link.ToHost, link.ToPort) } } } contents, _ := json.MarshalIndent(changes, "", " ") contents = append(contents, []byte("\n")...) if err := ioutil.WriteFile(newPath, contents, 0664); err != nil { fmt.Fprintf(os.Stderr, "Unable to write %s: %s\n", newPath, err.Error()) } linkedIds, err := LocatorsForDeploymentInstances(t, changes.Instances.Linked()) if err != nil { cmd.Fail(1, "Unable to generate deployment info: %s", err.Error()) } cmd.Executor{ On: linkedIds, Group: func(on ...cmd.Locator) cmd.JobRequest { links := []containers.ContainerLink{} for i := range on { instance, _ := changes.Instances.Find(cloc.AsIdentifier(on[i])) network := instance.NetworkLinks() if len(network) > 0 { links = append(links, containers.ContainerLink{instance.Id, network}) } } return &cjobs.LinkContainersRequest{&containers.ContainerLinks{links}} }, Output: os.Stdout, Transport: t, }.Stream() cmd.Executor{ On: addedIds, Serial: func(on cmd.Locator) cmd.JobRequest { return &cjobs.StartedContainerStateRequest{ Id: cloc.AsIdentifier(on), } }, Output: os.Stdout, Transport: t, }.Stream() fmt.Printf("==> Deployed as %s\n", newPath) if len(errors) > 0 { for i := range errors { fmt.Fprintf(os.Stderr, "Error: %s\n", errors[i]) } os.Exit(1) } }