/******************************************************************************* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"). You may not use * this file except in compliance with the License. A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and * limitations under the License. * ***************************************************************************** * __ _ _ ___ * ( )( \/\/ )/ __) * /__\ \ / \__ \ * (_)(_) \/\/ (___/ * * AWS SDK for .NET */ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading; using Amazon.EC2.Model; using Amazon.Runtime.Internal.Util; using ThirdParty.Json.LitJson; using Amazon.Runtime; #pragma warning disable 1591 namespace Amazon.EC2.Util { /// /// This class has utility methods for finding common Amazon machine images. /// public static partial class ImageUtilities { /// /// Returns the ImageDescriptor instance for a known key. /// /// The version-independent key identifying the descriptor /// Matching descriptor containing the name filter to search on public static ImageDescriptor DescriptorFromKey(string key) { return DescriptorFromKey(key, null); } /// /// Returns the ImageDescriptor instance for a known key. /// /// /// The version-independent key identifying the descriptor /// /// /// /// Optional. Configured client object from which proxy settings, if needed, can be /// determined. If no client is supplied the application configuration will be /// inspected for proxy details. /// /// /// If a proxy is configured (either on the client or in the configuration file) it /// will be used when downloading the metadata file containing the key to filter /// mappings. /// /// /// Matching descriptor containing the name filter to search on public static ImageDescriptor DescriptorFromKey(string key, IAmazonEC2 ec2Client) { LoadDefinitionsFromWeb(ConfigFromClient(ec2Client)); return FindDescriptorWithKey(key); } private static void LoadDefinitionsFromWeb(AmazonEC2Config ec2Config) { lock (LOCK_OBJECT) { if (ImageDefinitionsLoaded) return; } IWebProxy webProxy = null; if (ec2Config != null) webProxy = ec2Config.GetWebProxy(); int retries = 0; while (retries < MAX_DOWNLOAD_RETRIES) { try { HttpWebResponse response = null; foreach (var location in DownloadLocations) { try { response = DownloadControlFile(location, webProxy); if (response != null) break; } catch (Exception e) { Logger.InfoFormat("Failed to download stockamis.json from {0}, exception {1}", location, e); } } if (response == null) throw new AmazonClientException("Failed to download ImageUtilities metadata file stockamis.json from known locations."); using (response) { using (var reader = new StreamReader(response.GetResponseStream())) { lock (LOCK_OBJECT) { ParseAMIDefinitions(reader); ImageDefinitionsLoaded = true; return; } } } } catch (AmazonClientException e) { retries++; if (retries == MAX_DOWNLOAD_RETRIES) { Logger.Error(e, "Error downloading AMI definition file, ImageDescriptors were not initialized."); break; } } int delay = (int)(Math.Pow(4, retries) * 100); delay = Math.Min(delay, 30 * 1000); Thread.Sleep(delay); } } private static HttpWebResponse DownloadControlFile(string location, IWebProxy proxy) { var request = WebRequest.Create(location) as HttpWebRequest; if (proxy != null) request.Proxy = proxy; return request.GetResponse() as HttpWebResponse; } /// /// Find the Amazon machine image identified by the version-independent key name. /// /// The EC2 client used to search for the image. /// The keyname used to identify the image. /// The Amazon machine image. public static Image FindImage(IAmazonEC2 ec2Client, string imageKey) { ImageDescriptor descriptor = DescriptorFromKey(imageKey); if (descriptor != null) return FindImage(ec2Client, descriptor); else throw new ArgumentException("Image key '{0}' is not recognized.", imageKey); } /// /// Find the Amazon machine image identified by the ImageDescriptor. /// /// The EC2 client used to search for the image. /// The descriptor used to identify the image. /// The Amazon machine image. public static Image FindImage(IAmazonEC2 ec2Client, ImageDescriptor descriptor) { AmazonEC2Config config = CreateConfigFromClient(ec2Client, descriptor); LoadDefinitionsFromWeb(config); int retryCount = 1; Image image = null; do { var result = ec2Client.DescribeImages(CreateDescribeImagesRequest(descriptor)); if (result.Images.Any()) image = result.Images.OrderByDescending(x => x.Name).First(); else { // backing control file may be outdated, reload and try once more if (retryCount == 1) { Logger.InfoFormat("FindImage - DescribeImages call for image descriptor '{0}' (name prefix '{1}') yielded no results, assuming outdated control file and reloading", descriptor.DefinitionKey, descriptor.NamePrefix); lock (LOCK_OBJECT) { ImageDefinitionsLoaded = false; } LoadDefinitionsFromWeb(config); } retryCount++; } } while (image == null && retryCount <= 2); if (image == null) Logger.InfoFormat("FindImage - failed to find valid AMI image for descriptor '{0}' (name prefix '{1}')", descriptor.DefinitionKey, descriptor.NamePrefix); return image; } } }