示例#1
0
func (clst amazonCluster) Stop(machines []Machine) error {
	var awsIDs []awsID
	for _, m := range machines {
		awsIDs = append(awsIDs, awsID{
			region: m.Region,
			spotID: m.ID,
		})
	}
	for region, ids := range groupByRegion(awsIDs) {
		session := clst.getSession(region)
		spotIDs := getSpotIDs(ids)

		spots, err := session.DescribeSpotInstanceRequests(
			&ec2.DescribeSpotInstanceRequestsInput{
				SpotInstanceRequestIds: aws.StringSlice(spotIDs),
			})
		if err != nil {
			return err
		}

		instIds := []string{}
		for _, spot := range spots.SpotInstanceRequests {
			if spot.InstanceId != nil {
				instIds = append(instIds, *spot.InstanceId)
			}
		}

		if len(instIds) > 0 {
			_, err = session.TerminateInstances(&ec2.TerminateInstancesInput{
				InstanceIds: aws.StringSlice(instIds),
			})
			if err != nil {
				return err
			}
		}

		_, err = session.CancelSpotInstanceRequests(
			&ec2.CancelSpotInstanceRequestsInput{
				SpotInstanceRequestIds: aws.StringSlice(spotIDs),
			})
		if err != nil {
			return err
		}

		if err := clst.wait(ids, false); err != nil {
			return err
		}
	}

	return nil
}
示例#2
0
func (clst amazonCluster) List() ([]Machine, error) {
	machines := []Machine{}
	for region := range amis {
		session := clst.getSession(region)

		spots, err := session.DescribeSpotInstanceRequests(nil)
		if err != nil {
			return nil, err
		}

		insts, err := session.DescribeInstances(&ec2.DescribeInstancesInput{
			Filters: []*ec2.Filter{
				{
					Name:   aws.String("instance.group-name"),
					Values: []*string{aws.String(clst.namespace)},
				},
			},
		})
		if err != nil {
			return nil, err
		}

		instMap := make(map[string]*ec2.Instance)
		for _, res := range insts.Reservations {
			for _, inst := range res.Instances {
				instMap[*inst.InstanceId] = inst
			}
		}

		for _, spot := range spots.SpotInstanceRequests {
			if *spot.State != ec2.SpotInstanceStateActive &&
				*spot.State != ec2.SpotInstanceStateOpen {
				continue
			}

			var inst *ec2.Instance
			if spot.InstanceId != nil {
				inst = instMap[*spot.InstanceId]
			}

			// Due to a race condition in the AWS API, it's possible that
			// spot requests might lose their Tags. If handled naively,
			// those spot requests would technically be without a namespace,
			// meaning the instances they create would be live forever as
			// zombies.
			//
			// To mitigate this issue, we rely not only on the spot request
			// tags, but additionally on the instance security group. If a
			// spot request has a running instance in the appropriate
			// security group, it is by definition in our namespace.
			// Thus, we only check the tags for spot requests without
			// running instances.
			if inst == nil {
				var isOurs bool
				for _, tag := range spot.Tags {
					ns := clst.namespace
					if tag != nil && tag.Key != nil &&
						*tag.Key == ns {
						isOurs = true
						break
					}
				}

				if !isOurs {
					continue
				}
			}

			machine := Machine{
				ID:       *spot.SpotInstanceRequestId,
				Region:   region,
				Provider: db.Amazon,
			}

			if inst == nil {
				continue
			}
			if *inst.State.Name != ec2.InstanceStateNamePending &&
				*inst.State.Name != ec2.InstanceStateNameRunning {
				continue
			}

			if inst.PublicIpAddress != nil {
				machine.PublicIP = *inst.PublicIpAddress
			}

			if inst.PrivateIpAddress != nil {
				machine.PrivateIP = *inst.PrivateIpAddress
			}

			if inst.InstanceType != nil {
				machine.Size = *inst.InstanceType
			}

			if len(inst.BlockDeviceMappings) != 0 {
				volumeID := inst.BlockDeviceMappings[0].Ebs.VolumeId
				filters := []*ec2.Filter{
					{
						Name: aws.String("volume-id"),
						Values: []*string{
							aws.String(*volumeID),
						},
					},
				}

				volumeInfo, err := session.DescribeVolumes(
					&ec2.DescribeVolumesInput{
						Filters: filters,
					})
				if err != nil {
					return nil, err
				}
				if len(volumeInfo.Volumes) == 1 {
					machine.DiskSize = int(
						*volumeInfo.Volumes[0].Size)
				}
			}

			machines = append(machines, machine)
		}
	}

	return machines, nil
}