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  }