コード例 #1
0
ファイル: scheduler.go プロジェクト: devick/flynn
func (s *Scheduler) handleFormation(ef *ct.ExpandedFormation) (formation *Formation) {
	log := logger.New("fn", "handleFormation", "app.id", ef.App.ID, "release.id", ef.Release.ID)

	defer func() {
		// ensure the formation has the correct omni job counts
		if formation.RectifyOmni(len(s.hosts)) {
			s.triggerRectify(formation.key())
		}

		// update any formation-less jobs
		if jobs, ok := s.formationlessJobs[formation.key()]; ok {
			for _, job := range jobs {
				job.Formation = formation
			}
			s.triggerRectify(formation.key())
			delete(s.formationlessJobs, formation.key())
		}
	}()

	formation = s.formations.Get(ef.App.ID, ef.Release.ID)
	if formation == nil {
		log.Info("adding new formation", "processes", ef.Processes)
		formation = s.formations.Add(NewFormation(ef))
	} else {
		if formation.OriginalProcesses.Equals(ef.Processes) && utils.FormationTagsEqual(formation.Tags, ef.Tags) {
			return
		} else {
			log.Info("updating processes and tags of existing formation", "processes", ef.Processes, "tags", ef.Tags)
			formation.Tags = ef.Tags
			formation.SetProcesses(ef.Processes)
		}
	}
	s.triggerRectify(formation.key())
	return
}
コード例 #2
0
ファイル: scheduler.go プロジェクト: eldarion-gondor/cli
func (s *Scheduler) handleFormation(ef *ct.ExpandedFormation) (formation *Formation) {
	log := s.logger.New("fn", "handleFormation", "app.id", ef.App.ID, "release.id", ef.Release.ID)

	defer func() {
		// ensure the formation has the correct omni job counts
		if formation.RectifyOmni(s.activeHostCount()) {
			s.triggerRectify(formation.key())
		}

		// update any formation-less jobs
		if jobs, ok := s.formationlessJobs[formation.key()]; ok {
			for _, job := range jobs {
				job.Formation = formation
			}
			s.triggerRectify(formation.key())
			delete(s.formationlessJobs, formation.key())
		}
	}()

	formation = s.formations.Get(ef.App.ID, ef.Release.ID)
	if formation == nil {
		log.Info("adding new formation", "processes", ef.Processes)
		formation = s.formations.Add(NewFormation(ef))
	} else {
		diff := Processes(ef.Processes).Diff(formation.OriginalProcesses)
		if diff.IsEmpty() && utils.FormationTagsEqual(formation.Tags, ef.Tags) {
			return
		}

		// do not completely scale down critical apps for which this is the only active formation
		// (this prevents for example scaling down discoverd which breaks the cluster)
		if diff.IsScaleDownOf(formation.OriginalProcesses) && formation.App.Critical() && s.activeFormationCount(formation.App.ID) < 2 {
			log.Info("refusing to scale down critical app")
			return
		}

		log.Info("updating processes and tags of existing formation", "processes", ef.Processes, "tags", ef.Tags)
		formation.Tags = ef.Tags
		formation.SetProcesses(ef.Processes)
	}
	s.triggerRectify(formation.key())
	return
}
コード例 #3
0
ファイル: scale.go プロジェクト: devick/flynn
// takes args of the form "web=1[,key=val...]", "worker=3[,key=val...]", etc
func runScale(args *docopt.Args, client *controller.Client) error {
	app := mustApp()

	typeSpecs := args.All["<type>=<spec>"].([]string)

	showAll := args.Bool["--all"]

	if len(typeSpecs) > 0 && showAll {
		return fmt.Errorf("ERROR: Can't use --all when scaling")
	}

	releaseID := args.String["--release"]
	if releaseID != "" && showAll {
		return fmt.Errorf("ERROR: Can't use --all in combination with --release")
	}

	if len(typeSpecs) == 0 {
		return showFormations(client, releaseID, showAll, app)
	}

	release, err := determineRelease(client, releaseID, app)
	if err != nil {
		return err
	}

	formation, err := client.GetFormation(app, release.ID)
	if err == controller.ErrNotFound {
		formation = &ct.Formation{
			AppID:     app,
			ReleaseID: release.ID,
			Processes: make(map[string]int),
		}
	} else if err != nil {
		return err
	}
	if formation.Processes == nil {
		formation.Processes = make(map[string]int, len(typeSpecs))
	}
	if formation.Tags == nil {
		formation.Tags = make(map[string]map[string]string, len(typeSpecs))
	}

	currentProcs := formation.Processes
	currentTags := formation.Tags
	processes := make(map[string]int, len(currentProcs)+len(typeSpecs))
	tags := make(map[string]map[string]string, len(currentTags)+len(typeSpecs))
	for k, v := range currentProcs {
		processes[k] = v
	}
	invalid := make([]string, 0, len(release.Processes))
	for _, arg := range typeSpecs {
		i := strings.IndexRune(arg, '=')
		if i < 0 {
			return fmt.Errorf("ERROR: scale args must be of the form <typ>=<spec>")
		}

		countTags := strings.Split(arg[i+1:], ",")

		count, err := strconv.Atoi(countTags[0])
		if err != nil {
			return fmt.Errorf("ERROR: could not parse quantity in %q", arg)
		} else if count < 0 {
			return fmt.Errorf("ERROR: process quantities cannot be negative in %q", arg)
		}

		processType := arg[:i]
		if _, ok := release.Processes[processType]; ok {
			processes[processType] = count
		} else {
			invalid = append(invalid, fmt.Sprintf("%q", processType))
			continue
		}

		if len(countTags) > 1 {
			processTags := make(map[string]string, len(countTags)-1)
			for i := 1; i < len(countTags); i++ {
				keyVal := strings.SplitN(countTags[i], "=", 2)
				if len(keyVal) == 1 && keyVal[0] != "" {
					processTags[keyVal[0]] = "true"
				} else if len(keyVal) == 2 {
					processTags[keyVal[0]] = keyVal[1]
				}
			}
			tags[processType] = processTags
		}
	}
	if len(invalid) > 0 {
		return fmt.Errorf("ERROR: unknown process types: %s", strings.Join(invalid, ", "))
	}
	formation.Processes = processes
	formation.Tags = tags

	if scalingComplete(currentProcs, processes) {
		if !utils.FormationTagsEqual(currentTags, tags) {
			// TODO: determine the effect of changing tags and wait
			//       for appropriate events
			fmt.Println("persisting tag change")
			return client.PutFormation(formation)
		}
		fmt.Println("requested scale equals current scale, nothing to do!")
		return nil
	}

	scale := make([]string, 0, len(release.Processes))
	for typ := range release.Processes {
		if currentProcs[typ] != processes[typ] {
			scale = append(scale, fmt.Sprintf("%s: %d=>%d", typ, currentProcs[typ], processes[typ]))
		}
	}
	fmt.Printf("scaling %s\n\n", strings.Join(scale, ", "))

	expected := client.ExpectedScalingEvents(currentProcs, processes, release.Processes, 1)
	watcher, err := client.WatchJobEvents(app, release.ID)
	if err != nil {
		return err
	}
	defer watcher.Close()

	err = client.PutFormation(formation)
	if err != nil || args.Bool["--no-wait"] {
		return err
	}

	start := time.Now()
	err = watcher.WaitFor(expected, scaleTimeout, func(job *ct.Job) error {
		id := job.ID
		if id == "" {
			id = job.UUID
		}
		fmt.Printf("%s ==> %s %s %s\n", time.Now().Format("15:04:05.000"), job.Type, id, job.State)
		return nil
	})

	if err != nil {
		return err
	}
	fmt.Printf("\nscale completed in %s\n", time.Since(start))
	return nil
}