Beispiel #1
0
// ListAppTasks lists all the tasks for the app.
func (c *Client) ListAppTasks(ctx context.Context, appID string, input *ecs.ListTasksInput) (*ecs.ListTasksOutput, error) {
	var arns []*string

	resp, err := c.ListAppServices(ctx, appID, &ecs.ListServicesInput{
		Cluster: input.Cluster,
	})
	if err != nil {
		return nil, err
	}

	for _, s := range resp.ServiceARNs {
		id, err := arn.ResourceID(*s)
		if err != nil {
			return nil, err
		}

		t, err := c.ListTasks(ctx, &ecs.ListTasksInput{
			Cluster:     input.Cluster,
			ServiceName: aws.String(id),
		})
		if err != nil {
			return nil, err
		}

		if len(t.TaskARNs) == 0 {
			continue
		}

		arns = append(arns, t.TaskARNs...)
	}

	return &ecs.ListTasksOutput{
		TaskARNs: arns,
	}, nil
}
Beispiel #2
0
// ListAppServices lists all services for the app.
func (c *Client) ListAppServices(ctx context.Context, appID string, input *ecs.ListServicesInput) (*ecs.ListServicesOutput, error) {
	var serviceArns []*string
	if err := c.ListServicesPages(ctx, input, func(resp *ecs.ListServicesOutput, lastPage bool) bool {
		serviceArns = append(serviceArns, resp.ServiceArns...)
		return true
	}); err != nil {
		return nil, err
	}

	var arns []*string
	for _, a := range serviceArns {
		if a == nil {
			continue
		}

		id, err := arn.ResourceID(*a)
		if err != nil {
			return nil, err
		}

		appName, _ := c.split(&id)

		if appName == appID {
			arns = append(arns, a)
		}
	}

	return &ecs.ListServicesOutput{
		ServiceArns: arns,
	}, nil
}
Beispiel #3
0
// ListAppServices lists all services for the app.
func (c *Client) ListAppServices(ctx context.Context, appID string, input *ecs.ListServicesInput) (*ecs.ListServicesOutput, error) {
	resp, err := c.ListServices(ctx, input)
	if err != nil {
		return resp, err
	}

	var arns []*string
	for _, a := range resp.ServiceARNs {
		if a == nil {
			continue
		}

		id, err := arn.ResourceID(*a)
		if err != nil {
			return resp, err
		}

		appName, _ := c.split(&id)

		if appName == appID {
			arns = append(arns, a)
		}
	}

	return &ecs.ListServicesOutput{
		ServiceARNs: arns,
	}, nil
}
Beispiel #4
0
// tasks returns all of the ECS tasks for this app.
func (s *Scheduler) tasks(app string) ([]*ecs.Task, error) {
	services, err := s.Services(app)
	if err != nil {
		return nil, err
	}

	var arns []*string

	// Find all of the tasks started by the ECS services.
	for process, serviceArn := range services {
		id, err := arn.ResourceID(serviceArn)
		if err != nil {
			return nil, err
		}

		var taskArns []*string
		if err := s.ecs.ListTasksPages(&ecs.ListTasksInput{
			Cluster:     aws.String(s.Cluster),
			ServiceName: aws.String(id),
		}, func(resp *ecs.ListTasksOutput, lastPage bool) bool {
			taskArns = append(taskArns, resp.TaskArns...)
			return true
		}); err != nil {
			return nil, fmt.Errorf("error listing tasks for %s: %v", process, err)
		}

		if len(taskArns) == 0 {
			continue
		}

		arns = append(arns, taskArns...)
	}

	// Find all of the tasks started by Run.
	if err := s.ecs.ListTasksPages(&ecs.ListTasksInput{
		Cluster:   aws.String(s.Cluster),
		StartedBy: aws.String(app),
	}, func(resp *ecs.ListTasksOutput, lastPage bool) bool {
		arns = append(arns, resp.TaskArns...)
		return true
	}); err != nil {
		return nil, fmt.Errorf("error listing tasks started by %s: %v", app, err)
	}

	var tasks []*ecs.Task
	for _, chunk := range chunkStrings(arns, MaxDescribeTasks) {
		resp, err := s.ecs.DescribeTasks(&ecs.DescribeTasksInput{
			Cluster: aws.String(s.Cluster),
			Tasks:   chunk,
		})
		if err != nil {
			return nil, fmt.Errorf("error describing %d tasks: %v", len(chunk), err)
		}

		tasks = append(tasks, resp.Tasks...)
	}

	return tasks, nil
}
Beispiel #5
0
// Instances returns all of the running tasks for this application.
func (s *Scheduler) Instances(ctx context.Context, app string) ([]*scheduler.Instance, error) {
	var instances []*scheduler.Instance

	tasks, err := s.tasks(app)
	if err != nil {
		return nil, err
	}

	taskDefinitions := make(map[string]*ecs.TaskDefinition)
	for _, t := range tasks {
		k := *t.TaskDefinitionArn

		if _, ok := taskDefinitions[k]; !ok {
			resp, err := s.ecs.DescribeTaskDefinition(&ecs.DescribeTaskDefinitionInput{
				TaskDefinition: t.TaskDefinitionArn,
			})
			if err != nil {
				return nil, err
			}
			taskDefinitions[k] = resp.TaskDefinition
		}
	}

	for _, t := range tasks {
		taskDefinition := taskDefinitions[*t.TaskDefinitionArn]

		id, err := arn.ResourceID(*t.TaskArn)
		if err != nil {
			return instances, err
		}

		p, err := taskDefinitionToProcess(taskDefinition)
		if err != nil {
			return instances, err
		}

		state := safeString(t.LastStatus)
		var updatedAt time.Time
		switch state {
		case "PENDING":
			updatedAt = *t.CreatedAt
		case "RUNNING":
			updatedAt = *t.StartedAt
		case "STOPPED":
			updatedAt = *t.StoppedAt
		}

		instances = append(instances, &scheduler.Instance{
			Process:   p,
			State:     state,
			ID:        id,
			UpdatedAt: updatedAt,
		})
	}

	return instances, nil
}
Beispiel #6
0
// Instances returns all instances that are currently running, pending or
// draining.
func (m *Scheduler) Instances(ctx context.Context, appID string) ([]*scheduler.Instance, error) {
	var instances []*scheduler.Instance

	tasks, err := m.describeAppTasks(ctx, appID)
	if err != nil {
		return instances, err
	}

	for _, t := range tasks {
		resp, err := m.ecs.DescribeTaskDefinition(ctx, &ecs.DescribeTaskDefinitionInput{
			TaskDefinition: t.TaskDefinitionArn,
		})
		if err != nil {
			return instances, err
		}

		id, err := arn.ResourceID(*t.TaskArn)
		if err != nil {
			return instances, err
		}

		p, err := taskDefinitionToProcess(resp.TaskDefinition)
		if err != nil {
			return instances, err
		}

		state := safeString(t.LastStatus)
		var updatedAt time.Time
		switch state {
		case "PENDING":
			updatedAt = *t.CreatedAt
		case "RUNNING":
			updatedAt = *t.StartedAt
		case "STOPPED":
			updatedAt = *t.StoppedAt
		}

		instances = append(instances, &scheduler.Instance{
			Process:   p,
			State:     state,
			ID:        id,
			UpdatedAt: updatedAt,
		})
	}

	return instances, nil
}
Beispiel #7
0
// ListAppTasks lists all the tasks for the app.
func (c *Client) ListAppTasks(ctx context.Context, appID string, input *ecs.ListTasksInput) (*ecs.ListTasksOutput, error) {
	var arns []*string

	resp, err := c.ListAppServices(ctx, appID, &ecs.ListServicesInput{
		Cluster: input.Cluster,
	})
	if err != nil {
		return nil, err
	}

	// TODO(ejholmes): Parallelize the calls to list the tasks.
	for _, s := range resp.ServiceArns {
		id, err := arn.ResourceID(*s)
		if err != nil {
			return nil, err
		}

		var taskArns []*string
		if err := c.ListTasksPages(ctx, &ecs.ListTasksInput{
			Cluster:     input.Cluster,
			ServiceName: aws.String(id),
		}, func(resp *ecs.ListTasksOutput, lastPage bool) bool {
			taskArns = append(taskArns, resp.TaskArns...)
			return true
		}); err != nil {
			return nil, err
		}

		if len(taskArns) == 0 {
			continue
		}

		arns = append(arns, taskArns...)
	}

	return &ecs.ListTasksOutput{
		TaskArns: arns,
	}, nil
}
Beispiel #8
0
// Instances returns all instances that are currently running, pending or
// draining.
func (m *Scheduler) Instances(ctx context.Context, appID string) ([]*scheduler.Instance, error) {
	var instances []*scheduler.Instance

	tasks, err := m.describeAppTasks(ctx, appID)
	if err != nil {
		return instances, err
	}

	for _, t := range tasks {
		resp, err := m.ecs.DescribeTaskDefinition(ctx, &ecs.DescribeTaskDefinitionInput{
			TaskDefinition: t.TaskDefinitionArn,
		})
		if err != nil {
			return instances, err
		}

		id, err := arn.ResourceID(*t.TaskArn)
		if err != nil {
			return instances, err
		}

		p, err := taskDefinitionToProcess(resp.TaskDefinition)
		if err != nil {
			return instances, err
		}

		instances = append(instances, &scheduler.Instance{
			Process:   p,
			State:     safeString(t.LastStatus),
			ID:        id,
			UpdatedAt: timex.Now(),
		})
	}

	return instances, nil
}
Beispiel #9
0
// Instances returns all of the running tasks for this application.
func (s *Scheduler) Instances(ctx context.Context, app string) ([]*scheduler.Instance, error) {
	var instances []*scheduler.Instance

	tasks, err := s.tasks(app)
	if err != nil {
		return nil, err
	}

	taskDefinitions := make(map[string]*ecs.TaskDefinition)
	for _, t := range tasks {
		k := *t.TaskDefinitionArn

		if _, ok := taskDefinitions[k]; !ok {
			resp, err := s.ecs.DescribeTaskDefinition(&ecs.DescribeTaskDefinitionInput{
				TaskDefinition: t.TaskDefinitionArn,
			})
			if err != nil {
				return nil, err
			}
			taskDefinitions[k] = resp.TaskDefinition
		}
	}

	// Map from clusterARN to containerInstanceARN pointers to batch tasks from the same cluster
	clusterMap := make(map[string][]*string)

	for _, t := range tasks {
		k := *t.ClusterArn
		clusterMap[k] = append(clusterMap[k], t.ContainerInstanceArn)
	}

	// Map from containerInstanceARN to ec2-instance-id
	hostMap := make(map[string]string)

	for clusterArn, containerArnPtrs := range clusterMap {
		for _, chunk := range chunkStrings(containerArnPtrs, MaxDescribeContainerInstances) {
			resp, err := s.ecs.DescribeContainerInstances(&ecs.DescribeContainerInstancesInput{
				Cluster:            aws.String(clusterArn),
				ContainerInstances: chunk,
			})
			if err != nil {
				return nil, err
			}
			for _, f := range resp.Failures {
				return nil, fmt.Errorf("error describing container instance %s: %s", aws.StringValue(f.Arn), aws.StringValue(f.Reason))
			}

			for _, ci := range resp.ContainerInstances {
				hostMap[aws.StringValue(ci.ContainerInstanceArn)] = aws.StringValue(ci.Ec2InstanceId)
			}
		}
	}

	for _, t := range tasks {
		taskDefinition := taskDefinitions[*t.TaskDefinitionArn]

		id, err := arn.ResourceID(*t.TaskArn)
		if err != nil {
			return instances, err
		}

		hostId := hostMap[*t.ContainerInstanceArn]

		p, err := taskDefinitionToProcess(taskDefinition)
		if err != nil {
			return instances, err
		}

		state := aws.StringValue(t.LastStatus)
		var updatedAt time.Time
		switch state {
		case "PENDING":
			updatedAt = *t.CreatedAt
		case "RUNNING":
			updatedAt = *t.StartedAt
		case "STOPPED":
			updatedAt = *t.StoppedAt
		}

		instances = append(instances, &scheduler.Instance{
			Process:   p,
			State:     state,
			ID:        id,
			Host:      scheduler.Host{ID: hostId},
			UpdatedAt: updatedAt,
		})
	}

	return instances, nil
}