/*******************************************************************************
* 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;
}
}
}