Example #1
0
File: filter.go Project: pulcy/j2
// createUnitNameFilter creates a predicate that return true if a given
// unit name belongs to the configured job and task-group selection.
func (d *Deployment) createUnitNamePredicate() func(string) bool {
	if d.groupSelection.IncludeAll() {
		// Select everything in the job
		return func(unitName string) bool {
			if !d.scalingGroupSelection.IncludeAll() {
				if !jobs.IsUnitForScalingGroup(unitName, d.job.Name, uint(d.scalingGroupSelection)) {
					return false
				}
			}
			return jobs.IsUnitForJob(unitName, d.job.Name)
		}
	}

	// Select everything in one of the groups
	return func(unitName string) bool {
		if !d.scalingGroupSelection.IncludeAll() {
			if !jobs.IsUnitForScalingGroup(unitName, d.job.Name, uint(d.scalingGroupSelection)) {
				return false
			}
		}
		for _, g := range d.groupSelection {
			if jobs.IsUnitForTaskGroup(unitName, d.job.Name, g) {
				return true
			}
		}
		return false
	}
}
Example #2
0
File: run.go Project: pulcy/j2
// Run creates all applicable unit files and deploys them onto the configured cluster.
func (d *Deployment) Run() error {
	// Fetch all current units
	s, err := d.orchestrator.Scheduler(d.cluster)
	if err != nil {
		return maskAny(err)
	}

	allUnits, err := s.List()
	if err != nil {
		return maskAny(err)
	}

	// Prepare UI
	ui := newStateUI(d.verbose)
	defer ui.Close()

	// Find out which current units belong to the configured job
	remainingLoadedJobUnitNames := selectUnitNames(allUnits, d.createUnitNamePredicate())

	// Create scaling group units
	if err := d.generateScalingGroups(); err != nil {
		return maskAny(err)
	}

	// Ask for confirmation
	maxScale := d.scalingGroups[len(d.scalingGroups)-1].scalingGroup

	// Go over every scale
	step := 1
	totalModifications := 0
	waitBeforeNextStep := false
	for sgIndex, sg := range d.scalingGroups {
		// Select the loaded units that belong to this scaling group
		correctScalingGroupPredicate := func(unitName string) bool {
			return jobs.IsUnitForScalingGroup(unitName, d.job.Name, sg.scalingGroup)
		}
		loadedScalingGroupUnitNames := selectUnitNames(remainingLoadedJobUnitNames, correctScalingGroupPredicate)
		// Update remainingLoadedJobUnitNames
		remainingLoadedJobUnitNames = selectUnitNames(remainingLoadedJobUnitNames, notPredicate(containsPredicate(loadedScalingGroupUnitNames)))

		// Select the loaded unit name that have become obsolete
		sgUnitNames := sg.unitNames()
		obsoleteUnitNames := selectUnitNames(loadedScalingGroupUnitNames, notPredicate(containsPredicate(sgUnitNames)))
		notObsoleteUnitNames := selectUnitNames(loadedScalingGroupUnitNames, containsPredicate(sgUnitNames))

		// Select the unit names that are modified and need an update
		isModifiedPredicate := d.isModifiedPredicate(sg, s, ui)
		modifiedUnitNames := selectUnitNames(notObsoleteUnitNames, isModifiedPredicate)
		isFailedPredicate := d.isFailedPredicate(sg, s, ui)
		failedUnitNames := selectUnitNames(notObsoleteUnitNames, isFailedPredicate)
		unitNamesToDestroy := append(append(obsoleteUnitNames, modifiedUnitNames...), failedUnitNames...)
		newUnitNames := selectUnitNames(sgUnitNames, notPredicate(containsPredicate(loadedScalingGroupUnitNames)))

		// Are there any changes?
		anyModifications := (len(loadedScalingGroupUnitNames) != len(sg.units)) || (len(unitNamesToDestroy) > 0)

		// Wait a bit before proceeding
		if waitBeforeNextStep && anyModifications {
			InterruptibleSleep(ui.MessageSink, d.SliceDelay, fmt.Sprintf("Waiting %s before continuing with scaling group %d of %d...", "%s", (sgIndex+1), maxScale))
			ui.Clear()
		}

		// Confirm modifications
		if anyModifications && !d.force {
			curScale := sg.scalingGroup
			changes := []string{"# Unit | Action"}
			changes = append(changes, formatChanges("# ", obsoleteUnitNames, "Remove (is obsolete) !!!")...)
			changes = append(changes, formatChanges("# ", modifiedUnitNames, "Update")...)
			changes = append(changes, formatChanges("# ", failedUnitNames, "Failed state")...)
			changes = append(changes, formatChanges("# ", newUnitNames, "Create")...)
			sort.Strings(changes[1:])
			formattedChanges := strings.Replace(columnize.SimpleFormat(changes), "#", " ", -1)
			ui.HeaderSink <- fmt.Sprintf("Step %d: Update scaling group %d of %d on '%s'.\n%s\n", step, curScale, maxScale, d.cluster.Stack, formattedChanges)
			if !d.autoContinue {
				if err := ui.Confirm("Are you sure you want to continue?"); err != nil {
					return maskAny(err)
				}
			}
		}

		// Destroy the obsolete & modified units
		if len(unitNamesToDestroy) > 0 {
			if err := d.destroyUnits(s, unitNamesToDestroy, ui); err != nil {
				return maskAny(err)
			}

			InterruptibleSleep(ui.MessageSink, d.DestroyDelay, "Waiting for %s...")
		}

		// Now launch everything
		unitsToLaunch := sg.selectByNames(modifiedUnitNames, failedUnitNames, newUnitNames)
		if unitsToLaunch.Len() > 0 {
			if err := launchUnits(s, unitsToLaunch, ui); err != nil {
				return maskAny(err)
			}
		}

		// Update counters
		if anyModifications {
			waitBeforeNextStep = true
			totalModifications++
		}
		step++
		ui.Clear()
	}

	// Destroy remaining units
	if len(remainingLoadedJobUnitNames) > 0 {
		changes := []string{"# Unit | Action"}
		changes = append(changes, formatChanges("# ", remainingLoadedJobUnitNames, "Remove (is obsolete) !!!")...)
		sort.Strings(changes[1:])
		formattedChanges := strings.Replace(columnize.SimpleFormat(changes), "#", " ", -1)
		ui.HeaderSink <- fmt.Sprintf("Step %d: Cleanup of obsolete units on '%s'.\n%s\n", step, d.cluster.Stack, formattedChanges)
		if err := ui.Confirm("Are you sure you want to continue?"); err != nil {
			return maskAny(err)
		}

		if err := d.destroyUnits(s, remainingLoadedJobUnitNames, ui); err != nil {
			return maskAny(err)
		}

		totalModifications++
	}

	// Notify in case we did nothing
	if totalModifications == 0 {
		ui.MessageSink <- "No modifications needed."
	} else {
		ui.MessageSink <- "Done."
	}

	return nil
}