github.com/coreos/mantle@v0.13.0/platform/api/aws/ami.go (about) 1 // Copyright 2017 CoreOS, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package aws 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "net/http" 21 "sync" 22 ) 23 24 // relaseAMIs matches the structure of the AMIs listed in our 25 // coreos_production_ami_all.json release file 26 type releaseAMIs struct { 27 AMIS []struct { 28 Name string `json:"name"` 29 PV string `json:"pv"` 30 HVM string `json:"hvm"` 31 } `json:"amis"` 32 } 33 34 var amiCache struct { 35 alphaOnce sync.Once 36 alphaAMIs *releaseAMIs 37 38 betaOnce sync.Once 39 betaAMIs *releaseAMIs 40 41 stableOnce sync.Once 42 stableAMIs *releaseAMIs 43 } 44 45 // resolveAMI is used to minimize network requests while allowing resolution of 46 // release channels to specific AMI ids. 47 // If any issue occurs attempting to resolve a given AMI, e.g. a network error, 48 // this method panics. 49 func resolveAMI(ami string, region string) string { 50 resolveChannel := func(channel string) *releaseAMIs { 51 resp, err := http.DefaultClient.Get(fmt.Sprintf("https://%s.release.core-os.net/amd64-usr/current/coreos_production_ami_all.json", channel)) 52 if err != nil { 53 panic(fmt.Errorf("unable to fetch %v AMI json: %v", channel, err)) 54 } 55 56 var amis releaseAMIs 57 err = json.NewDecoder(resp.Body).Decode(&amis) 58 if err != nil { 59 panic(fmt.Errorf("unable to parse release bucket %v AMI: %v", channel, err)) 60 } 61 return &amis 62 } 63 64 var channelAmis *releaseAMIs 65 switch ami { 66 case "alpha": 67 amiCache.alphaOnce.Do(func() { 68 amiCache.alphaAMIs = resolveChannel(ami) 69 }) 70 channelAmis = amiCache.alphaAMIs 71 case "beta": 72 amiCache.betaOnce.Do(func() { 73 amiCache.betaAMIs = resolveChannel(ami) 74 }) 75 channelAmis = amiCache.betaAMIs 76 case "stable": 77 amiCache.stableOnce.Do(func() { 78 amiCache.stableAMIs = resolveChannel(ami) 79 }) 80 channelAmis = amiCache.stableAMIs 81 default: 82 return ami 83 } 84 85 for _, ami := range channelAmis.AMIS { 86 if ami.Name == region { 87 return ami.HVM 88 } 89 } 90 panic(fmt.Sprintf("could not find %v ami in %+v", ami, amiCache.alphaAMIs.AMIS)) 91 }