@@ -21,11 +21,11 @@ limitations under the License.
2121package imagebuilder
2222
2323import (
24- "fmt"
25- "time"
26-
2724 "crypto/md5"
2825 "encoding/hex"
26+ "fmt"
27+ "sync"
28+ "time"
2929
3030 "github.com/aws/aws-sdk-go/aws"
3131 "github.com/aws/aws-sdk-go/aws/awserr"
@@ -565,7 +565,8 @@ type AWSImage struct {
565565 region string
566566 imageID string
567567
568- cachedImage * ec2.Image
568+ cachedImageMutex sync.Mutex
569+ cachedImage * ec2.Image
569570}
570571
571572// ID returns the AWS identifier for the image
@@ -670,6 +671,9 @@ func waitSnapshotCompleted(client *ec2.EC2, snapshotID string) error {
670671}
671672
672673func (i * AWSImage ) image () (* ec2.Image , error ) {
674+ i .cachedImageMutex .Lock ()
675+ defer i .cachedImageMutex .Unlock ()
676+
673677 if i .cachedImage != nil {
674678 return i .cachedImage , nil
675679 }
@@ -781,7 +785,7 @@ func (i *AWSImage) ensurePublic() error {
781785
782786// ReplicateImage copies the image to all accessable AWS regions
783787func (i * AWSImage ) ReplicateImage (makePublic bool ) (map [string ]Image , error ) {
784- imagesByRegion := make ( map [ string ] Image )
788+ var results sync. Map
785789
786790 glog .V (2 ).Infof ("AWS DescribeRegions" )
787791 request := & ec2.DescribeRegionsInput {}
@@ -790,35 +794,63 @@ func (i *AWSImage) ReplicateImage(makePublic bool) (map[string]Image, error) {
790794 return nil , fmt .Errorf ("error listing ec2 regions: %v" , err )
791795
792796 }
793- imagesByRegion [i .region ] = i
797+ results .Store (i .region , i )
798+
799+ var wg sync.WaitGroup
794800
795801 for _ , region := range response .Regions {
796- regionName := aws .StringValue (region .RegionName )
797- if imagesByRegion [regionName ] != nil {
798- continue
799- }
802+ go func (regionName string ) {
803+ var image * AWSImage
804+ if v , ok := results .Load (regionName ); ok {
805+ image = v .(* AWSImage )
806+ }
800807
801- imageID , err := i .copyImageToRegion (regionName )
802- if err != nil {
803- return nil , fmt .Errorf ("error copying image to region %q: %v" , regionName , err )
804- }
805- targetEC2 := ec2 .New (session .New (), & aws.Config {Region : & regionName })
806- imagesByRegion [regionName ] = & AWSImage {
807- ec2 : targetEC2 ,
808- region : regionName ,
809- imageID : imageID ,
810- }
811- }
808+ if image == nil {
809+ imageID , err := i .copyImageToRegion (regionName )
810+ if err != nil {
811+ results .Store (regionName , fmt .Errorf ("error copying image to region %q: %v" , regionName , err ))
812+ wg .Done ()
813+ return
814+ }
815+ targetEC2 := ec2 .New (session .New (), & aws.Config {Region : & regionName })
816+ image = & AWSImage {
817+ ec2 : targetEC2 ,
818+ region : regionName ,
819+ imageID : imageID ,
820+ }
812821
813- if makePublic {
814- for regionName , image := range imagesByRegion {
815- err := image .EnsurePublic ()
816- if err != nil {
817- return nil , fmt .Errorf ("error making image public in region %q: %v" , regionName , err )
822+ results .Store (regionName , image )
818823 }
819- }
824+
825+ if makePublic {
826+ err := image .EnsurePublic ()
827+ if err != nil {
828+ results .Store (regionName , fmt .Errorf ("error making image public in region %q: %v" , regionName , err ))
829+ wg .Done ()
830+ return
831+ }
832+ }
833+
834+ wg .Done ()
835+ }(aws .StringValue (region .RegionName ))
836+ wg .Add (1 )
820837 }
821838
839+ wg .Wait ()
840+
841+ imagesByRegion := make (map [string ]Image )
842+ var returnError error
843+ results .Range (func (k , v interface {}) bool {
844+ if err , ok := v .(error ); ok {
845+ returnError = err
846+ return false
847+ }
848+ imagesByRegion [k .(string )] = v .(* AWSImage )
849+ return true
850+ })
851+ if returnError != nil {
852+ return nil , returnError
853+ }
822854 return imagesByRegion , nil
823855}
824856
0 commit comments