func changeUnits(a provision.App, units int, processName string, w io.Writer) error { if a.GetDeploys() == 0 { return errors.New("units can only be modified after the first deploy") } if units == 0 { return errors.New("cannot change 0 units") } client, err := chooseDBSwarmNode() if err != nil { return err } imageId, err := image.AppCurrentImageName(a.GetName()) if err != nil { return err } if processName == "" { _, processName, err = dockercommon.ProcessCmdForImage(processName, imageId) if err != nil { return errors.WithStack(err) } } return deployProcesses(client, a, imageId, processSpec{processName: processState{increment: units}}) }
func (p *dockerProvisioner) RemoveUnits(a provision.App, units uint, processName string, w io.Writer) error { if a == nil { return errors.New("remove units: app should not be nil") } if units == 0 { return errors.New("cannot remove zero units") } var err error if w == nil { w = ioutil.Discard } imgId, err := image.AppCurrentImageName(a.GetName()) if err != nil { return err } _, processName, err = dockercommon.ProcessCmdForImage(processName, imgId) if err != nil { return err } containers, err := p.listContainersByProcess(a.GetName(), processName) if err != nil { return err } if len(containers) < int(units) { return errors.Errorf("cannot remove %d units from process %q, only %d available", units, processName, len(containers)) } fmt.Fprintf(w, "\n---- Removing %d %s ----\n", units, pluralize("unit", int(units))) p, err = p.cloneProvisioner(nil) if err != nil { return err } toRemove := make([]container.Container, 0, units) for i := 0; i < int(units); i++ { var ( containerID string cont *container.Container ) containerID, err = p.scheduler.GetRemovableContainer(a.GetName(), processName) if err != nil { return err } cont, err = p.GetContainer(containerID) if err != nil { return err } p.scheduler.ignoredContainers = append(p.scheduler.ignoredContainers, cont.ID) toRemove = append(toRemove, *cont) } args := changeUnitsPipelineArgs{ app: a, toRemove: toRemove, writer: w, provisioner: p, } pipeline := action.NewPipeline( &removeOldRoutes, &provisionRemoveOldUnits, &provisionUnbindOldUnits, ) err = pipeline.Execute(args) if err != nil { return errors.Wrap(err, "error removing routes, units weren't removed") } return nil }
func addContainersWithHost(args *changeUnitsPipelineArgs) ([]container.Container, error) { a := args.app w := args.writer var units int processMsg := make([]string, 0, len(args.toAdd)) imageId := args.imageId for processName, v := range args.toAdd { units += v.Quantity if processName == "" { _, processName, _ = dockercommon.ProcessCmdForImage(processName, imageId) } processMsg = append(processMsg, fmt.Sprintf("[%s: %d]", processName, v.Quantity)) } var destinationHost []string if args.toHost != "" { destinationHost = []string{args.toHost} } if w == nil { w = ioutil.Discard } fmt.Fprintf(w, "\n---- Starting %d new %s %s ----\n", units, pluralize("unit", units), strings.Join(processMsg, " ")) oldContainers := make([]container.Container, 0, units) for processName, cont := range args.toAdd { for i := 0; i < cont.Quantity; i++ { oldContainers = append(oldContainers, container.Container{ ProcessName: processName, Status: cont.Status.String(), }) } } rollbackCallback := func(c *container.Container) { log.Errorf("Removing container %q due failed add units.", c.ID) errRem := c.Remove(args.provisioner) if errRem != nil { log.Errorf("Unable to destroy container %q: %s", c.ID, errRem) } } var ( createdContainers []*container.Container m sync.Mutex ) err := runInContainers(oldContainers, func(c *container.Container, toRollback chan *container.Container) error { c, startErr := args.provisioner.start(c, a, imageId, w, args.exposedPort, destinationHost...) if startErr != nil { return startErr } toRollback <- c m.Lock() createdContainers = append(createdContainers, c) m.Unlock() fmt.Fprintf(w, " ---> Started unit %s [%s]\n", c.ShortID(), c.ProcessName) return nil }, rollbackCallback, true) if err != nil { return nil, err } result := make([]container.Container, len(createdContainers)) i := 0 for _, c := range createdContainers { result[i] = *c i++ } return result, nil }