Example #1
0
func relocateRouteAnyTasks(sess *session, agent *model.AgentDTO) ([]event.Event, error) {
	events := make([]event.Event, 0)
	// get list of tasks.
	var twm taskWithMetrics
	sess.Join("LEFT", "task_metric", "task.id = task_metric.task_id")
	sess.Join("INNER", "route_by_any_index", "route_by_any_index.task_id = task.id").Where("route_by_any_index.agent_id=?", agent.Id)
	sess.Cols("`task_metric`.*", "`task`.*")
	err := sess.Find(&twm)
	if err != nil {
		return nil, err
	}
	tasks := twm.ToTaskDTO()
	if len(tasks) == 0 {
		return nil, nil
	}
	for _, t := range tasks {
		candidates, err := taskRouteAnyCandidates(sess, t.Id)
		if err != nil {
			return nil, err
		}
		if len(candidates) == 0 {
			log.Error(3, "Cant re-locate task %d, no online agents capable of providing requested metrics.", t.Id)
			continue
		}
		newAgent := candidates[rand.Intn(len(candidates))]
		if newAgent == agent.Id {
			log.Debug("No need to re-allocated task as the agent it was running on is back online")
			continue
		}
		_, err = sess.Exec("UPDATE route_by_any_index set agent_id=? where task_id=?", newAgent, t.Id)
		if err != nil {
			return nil, err
		}
		log.Info("Task %d rescheduled to agent %d", t.Id, newAgent)
		e := new(event.TaskUpdated)
		e.Ts = time.Now()
		e.Payload.Last = t
		e.Payload.Current = t
		events = append(events, e)
	}
	return events, nil
}
Example #2
0
func updateTask(sess *session, t *model.TaskDTO) ([]event.Event, error) {
	events := make([]event.Event, 0)
	existing, err := getTaskById(sess, t.Id, t.OrgId)
	if err != nil {
		return nil, err
	}
	if existing == nil {
		return nil, model.TaskNotFound
	}
	task := model.Task{
		Id:       t.Id,
		Name:     t.Name,
		OrgId:    t.OrgId,
		Interval: t.Interval,
		Enabled:  t.Enabled,
		Config:   t.Config,
		Route:    t.Route,
		Created:  existing.Created,
		Updated:  time.Now(),
	}
	sess.UseBool("enabled")
	_, err = sess.Id(task.Id).Update(&task)
	if err != nil {
		return nil, err
	}
	t.Updated = task.Updated

	// Update taskMetrics
	metricsToAdd := make([]*model.TaskMetric, 0)
	metricsToDel := make([]*model.TaskMetric, 0)
	metricsMap := make(map[string]*model.TaskMetric)
	seenMetrics := make(map[string]struct{})

	for m, v := range existing.Metrics {
		metricsMap[fmt.Sprintf("%s:%d", m, v)] = &model.TaskMetric{
			TaskId:    t.Id,
			Namespace: m,
			Version:   v,
		}
	}
	for m, v := range t.Metrics {
		key := fmt.Sprintf("%s:%d", m, v)
		seenMetrics[key] = struct{}{}
		if _, ok := metricsMap[key]; !ok {
			metricsToAdd = append(metricsToAdd, &model.TaskMetric{
				TaskId:    t.Id,
				Namespace: m,
				Version:   v,
				Created:   time.Now(),
			})
		}
	}

	for key, m := range metricsMap {
		if _, ok := seenMetrics[key]; !ok {
			metricsToDel = append(metricsToDel, m)
		}
	}

	if len(metricsToDel) > 0 {
		_, err := sess.Delete(&metricsToDel)
		if err != nil {
			return nil, err
		}
	}
	newMetrics := false
	if len(metricsToAdd) > 0 {
		_, err := sess.Insert(&metricsToAdd)
		if err != nil {
			return nil, err
		}
		newMetrics = true
	}

	// handle task routes.
	if existing.Route.Type != t.Route.Type {
		if err := deleteTaskRoute(sess, existing); err != nil {
			return nil, err
		}
		if err := addTaskRoute(sess, t); err != nil {
			return nil, err
		}
	} else {
		switch t.Route.Type {
		case model.RouteAny:
			// we only need to consider changing the agent this task is allocated to
			// if new metrics have been added.
			if newMetrics {
				currentAgent := struct{ AgentId int64 }{}
				found, err := sess.Sql("SELECT agent_id from route_by_any_index where task_id = ?", t.Id).Get(&currentAgent)
				if err != nil {
					return nil, err
				}
				if !found {
					log.Error(3, "no entry for task %d found in route_by_any_index", t.Id)
				}

				candidates, err := taskRouteAnyCandidates(sess, t.Id)
				if err != nil {
					return nil, err
				}
				if len(candidates) == 0 {
					return nil, fmt.Errorf("No agent found that can provide all requested metrics.")
				}
				for _, id := range candidates {
					if id == currentAgent.AgentId {
						// no need to change the assigned agent.
						break
					}
				}
				// need to assign a new agent.
				_, err = sess.Exec("DELETE from route_by_any_index where task_id = ?", t.Id)
				if err != nil {
					return nil, err
				}

				idx := model.RouteByAnyIndex{
					TaskId:  t.Id,
					AgentId: candidates[rand.Intn(len(candidates))],
					Created: time.Now(),
				}
				if _, err := sess.Insert(&idx); err != nil {
					return nil, err
				}
			}
		case model.RouteByTags:
			existingTags := make(map[string]struct{})
			tagsToAdd := make([]string, 0)
			tagsToDel := make([]string, 0)
			currentTags := make(map[string]struct{})

			for _, tag := range existing.Route.Config["tags"].([]string) {
				existingTags[tag] = struct{}{}
			}
			for _, tag := range t.Route.Config["tags"].([]string) {
				currentTags[tag] = struct{}{}
				if _, ok := existingTags[tag]; !ok {
					tagsToAdd = append(tagsToAdd, tag)
				}
			}
			for tag := range existingTags {
				if _, ok := currentTags[tag]; !ok {
					tagsToDel = append(tagsToDel, tag)
				}
			}
			if len(tagsToDel) > 0 {
				tagRoutes := make([]*model.RouteByTagIndex, len(tagsToDel))
				for i, tag := range tagsToDel {
					tagRoutes[i] = &model.RouteByTagIndex{
						TaskId: t.Id,
						Tag:    tag,
					}
				}
				_, err := sess.Delete(&tagRoutes)
				if err != nil {
					return nil, err
				}
			}
			if len(tagsToAdd) > 0 {
				tagRoutes := make([]*model.RouteByTagIndex, len(tagsToAdd))
				for i, tag := range tagsToAdd {
					tagRoutes[i] = &model.RouteByTagIndex{
						TaskId:  t.Id,
						Tag:     tag,
						Created: time.Now(),
					}
				}
				_, err := sess.Insert(&tagRoutes)
				if err != nil {
					return nil, err
				}
			}

		case model.RouteByIds:
			existingIds := make(map[int64]struct{})
			idsToAdd := make([]int64, 0)
			idsToDel := make([]int64, 0)
			currentIds := make(map[int64]struct{})

			for _, id := range existing.Route.Config["ids"].([]int64) {
				existingIds[id] = struct{}{}
			}
			for _, id := range t.Route.Config["ids"].([]int64) {
				currentIds[id] = struct{}{}
				if _, ok := existingIds[id]; !ok {
					idsToAdd = append(idsToAdd, id)
				}
			}
			for id := range existingIds {
				if _, ok := currentIds[id]; !ok {
					idsToDel = append(idsToDel, id)
				}
			}
			if len(idsToDel) > 0 {
				idRoutes := make([]*model.RouteByIdIndex, len(idsToDel))
				for i, id := range idsToDel {
					idRoutes[i] = &model.RouteByIdIndex{
						TaskId:  t.Id,
						AgentId: id,
					}
				}
				_, err := sess.Delete(&idRoutes)
				if err != nil {
					return nil, err
				}
			}
			if len(idsToAdd) > 0 {
				idRoutes := make([]*model.RouteByIdIndex, len(idsToAdd))
				for i, id := range idsToAdd {
					idRoutes[i] = &model.RouteByIdIndex{
						TaskId:  t.Id,
						AgentId: id,
						Created: time.Now(),
					}
				}
				_, err := sess.Insert(&idRoutes)
				if err != nil {
					return nil, err
				}
			}
		default:
			return nil, model.UnknownRouteType
		}
	}
	e := new(event.TaskUpdated)
	e.Ts = time.Now()
	e.Payload.Last = t
	e.Payload.Current = t
	events = append(events, e)
	return events, nil
}