github.com/askholme/packer@v0.7.2-0.20140924152349-70d9566a6852/builder/amazon/common/step_ami_region_copy.go (about) 1 package common 2 3 import ( 4 "fmt" 5 "github.com/mitchellh/goamz/aws" 6 "github.com/mitchellh/goamz/ec2" 7 "github.com/mitchellh/multistep" 8 "github.com/mitchellh/packer/packer" 9 "sync" 10 ) 11 12 type StepAMIRegionCopy struct { 13 Regions []string 14 } 15 16 func (s *StepAMIRegionCopy) Run(state multistep.StateBag) multistep.StepAction { 17 ec2conn := state.Get("ec2").(*ec2.EC2) 18 ui := state.Get("ui").(packer.Ui) 19 amis := state.Get("amis").(map[string]string) 20 ami := amis[ec2conn.Region.Name] 21 22 if len(s.Regions) == 0 { 23 return multistep.ActionContinue 24 } 25 26 ui.Say(fmt.Sprintf("Copying AMI (%s) to other regions...", ami)) 27 28 var lock sync.Mutex 29 var wg sync.WaitGroup 30 errs := new(packer.MultiError) 31 for _, region := range s.Regions { 32 wg.Add(1) 33 ui.Message(fmt.Sprintf("Copying to: %s", region)) 34 35 go func(region string) { 36 defer wg.Done() 37 id, err := amiRegionCopy(state, ec2conn.Auth, ami, 38 aws.Regions[region], ec2conn.Region) 39 40 lock.Lock() 41 defer lock.Unlock() 42 amis[region] = id 43 if err != nil { 44 errs = packer.MultiErrorAppend(errs, err) 45 } 46 }(region) 47 } 48 49 // TODO(mitchellh): Wait but also allow for cancels to go through... 50 ui.Message("Waiting for all copies to complete...") 51 wg.Wait() 52 53 // If there were errors, show them 54 if len(errs.Errors) > 0 { 55 state.Put("error", errs) 56 ui.Error(errs.Error()) 57 return multistep.ActionHalt 58 } 59 60 state.Put("amis", amis) 61 return multistep.ActionContinue 62 } 63 64 func (s *StepAMIRegionCopy) Cleanup(state multistep.StateBag) { 65 // No cleanup... 66 } 67 68 // amiRegionCopy does a copy for the given AMI to the target region and 69 // returns the resulting ID or error. 70 func amiRegionCopy(state multistep.StateBag, auth aws.Auth, imageId string, 71 target aws.Region, source aws.Region) (string, error) { 72 73 // Connect to the region where the AMI will be copied to 74 regionconn := ec2.New(auth, target) 75 resp, err := regionconn.CopyImage(&ec2.CopyImage{ 76 SourceRegion: source.Name, 77 SourceImageId: imageId, 78 }) 79 80 if err != nil { 81 return "", fmt.Errorf("Error Copying AMI (%s) to region (%s): %s", 82 imageId, target, err) 83 } 84 85 stateChange := StateChangeConf{ 86 Pending: []string{"pending"}, 87 Target: "available", 88 Refresh: AMIStateRefreshFunc(regionconn, resp.ImageId), 89 StepState: state, 90 } 91 92 if _, err := WaitForState(&stateChange); err != nil { 93 return "", fmt.Errorf("Error waiting for AMI (%s) in region (%s): %s", 94 resp.ImageId, target, err) 95 } 96 97 return resp.ImageId, nil 98 }