func bootMachine(m machine.Machine) error { id := uuid.NewV4().String() err := initMachine(cloudcfg.Ubuntu(m.SSHKeys, "xenial"), m.Size, id) if err == nil { err = up(id) } if err != nil { destroy(id) } return err }
// Boot blocks while creating instances. func (clst *Cluster) Boot(bootSet []machine.Machine) error { // XXX: should probably have a better clean up routine if an error is encountered var names []string for _, m := range bootSet { name := "quilt-" + uuid.NewV4().String() _, err := clst.instanceNew(name, m.Size, m.Region, cloudcfg.Ubuntu(m.SSHKeys, "xenial")) if err != nil { log.WithFields(log.Fields{ "error": err, "id": m.ID, }).Error("Failed to start instance.") continue } names = append(names, name) } if err := clst.wait(names, true); err != nil { return err } return nil }
func TestBoot(t *testing.T) { t.Parallel() mc := new(mockClient) mc.On("DescribeSecurityGroups", mock.Anything).Return( &ec2.DescribeSecurityGroupsOutput{ SecurityGroups: []*ec2.SecurityGroup{ { GroupId: aws.String("groupId"), }, }, }, nil, ) mc.On("RequestSpotInstances", mock.Anything).Return( &ec2.RequestSpotInstancesOutput{ SpotInstanceRequests: []*ec2.SpotInstanceRequest{ { SpotInstanceRequestId: aws.String("spot1"), }, { SpotInstanceRequestId: aws.String("spot2"), }, }, }, nil, ) mc.On("CreateTags", mock.Anything).Return( &ec2.CreateTagsOutput{}, nil, ) mc.On("DescribeInstances", mock.Anything).Return( &ec2.DescribeInstancesOutput{}, nil, ) mc.On("DescribeSpotInstanceRequests", mock.Anything).Return( &ec2.DescribeSpotInstanceRequestsOutput{ SpotInstanceRequests: []*ec2.SpotInstanceRequest{ { SpotInstanceRequestId: aws.String("spot1"), State: aws.String(ec2.SpotInstanceStateActive), Tags: []*ec2.Tag{ { Key: aws.String(testNamespace), Value: aws.String(""), }, }, }, { SpotInstanceRequestId: aws.String("spot2"), State: aws.String(ec2.SpotInstanceStateActive), Tags: []*ec2.Tag{ { Key: aws.String(testNamespace), Value: aws.String(""), }, }, }, }, }, nil, ) amazonCluster := newAmazon(testNamespace) amazonCluster.newClient = func(region string) client { return mc } err := amazonCluster.Boot([]machine.Machine{ { Region: "us-west-1", Size: "m4.large", DiskSize: 32, }, { Region: "us-west-1", Size: "m4.large", DiskSize: 32, }, }) assert.Nil(t, err) cfg := cloudcfg.Ubuntu(nil, "xenial") mc.AssertCalled(t, "RequestSpotInstances", &ec2.RequestSpotInstancesInput{ SpotPrice: aws.String(spotPrice), LaunchSpecification: &ec2.RequestSpotLaunchSpecification{ ImageId: aws.String(amis["us-west-1"]), InstanceType: aws.String("m4.large"), UserData: aws.String(base64.StdEncoding.EncodeToString( []byte(cfg))), SecurityGroupIds: aws.StringSlice([]string{"groupId"}), BlockDeviceMappings: []*ec2.BlockDeviceMapping{ blockDevice(32)}, }, InstanceCount: aws.Int64(2), }, ) mc.AssertCalled(t, "CreateTags", &ec2.CreateTagsInput{ Tags: []*ec2.Tag{ { Key: aws.String(testNamespace), Value: aws.String(""), }, }, Resources: aws.StringSlice([]string{"spot1", "spot2"}), }, ) }
// Boot creates instances in the `clst` configured according to the `bootSet`. func (clst Cluster) Boot(bootSet []machine.Machine) error { if len(bootSet) <= 0 { return nil } type bootReq struct { cfg string size string region string diskSize int } bootReqMap := make(map[bootReq]int64) // From boot request to an instance count. for _, m := range bootSet { br := bootReq{ cfg: cloudcfg.Ubuntu(m.SSHKeys, "xenial"), size: m.Size, region: m.Region, diskSize: m.DiskSize, } bootReqMap[br] = bootReqMap[br] + 1 } var awsIDs []awsID for br, count := range bootReqMap { client := clst.getClient(br.region) groupID, _, err := clst.getCreateSecurityGroup(client) if err != nil { return err } cloudConfig64 := base64.StdEncoding.EncodeToString([]byte(br.cfg)) resp, err := client.RequestSpotInstances(&ec2.RequestSpotInstancesInput{ SpotPrice: aws.String(spotPrice), LaunchSpecification: &ec2.RequestSpotLaunchSpecification{ ImageId: aws.String(amis[br.region]), InstanceType: aws.String(br.size), UserData: &cloudConfig64, SecurityGroupIds: []*string{aws.String(groupID)}, BlockDeviceMappings: []*ec2.BlockDeviceMapping{ blockDevice(br.diskSize), }, }, InstanceCount: &count, }) if err != nil { return err } for _, request := range resp.SpotInstanceRequests { awsIDs = append(awsIDs, awsID{ spotID: *request.SpotInstanceRequestId, region: br.region}) } } if err := clst.tagSpotRequests(awsIDs); err != nil { return err } return clst.wait(awsIDs, true) }