/* * 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. */ using System; using System.Globalization; using Amazon.Runtime.Internal.Util; using System.Collections.Generic; using Amazon.Util; using Amazon.Runtime.CredentialManagement; namespace Amazon.Runtime { /// /// Base class for determining region based on inspection. /// public abstract class AWSRegion { public RegionEndpoint Region { get; protected set; } /// /// Sets the Region property by looking up the corresponding RegionEndpoint /// from the supplied region system name (us-east-1, us-west-2 etc). /// /// The system name of the region. protected void SetRegionFromName(string regionSystemName) { Region = RegionEndpoint.GetBySystemName(regionSystemName); } } /// /// Determines region based on application configuration settings. If the configuration does not contain /// the region setting key an InvalidOperationException is thrown. /// public class AppConfigAWSRegion : AWSRegion { /// /// Attempts to construct an instance of ApplicationConfigAWSRegion. If no region is found in the /// application configuration file then an InvalidOperationException is thrown. /// public AppConfigAWSRegion() { var region = AWSConfigs.RegionEndpoint; if (region != null) { this.Region = region; var logger = Logger.GetLogger(typeof(AppConfigAWSRegion)); logger.InfoFormat("Region {0} found using {1} setting in application configuration file.", region.SystemName, AWSConfigs.AWSRegionKey); } else throw new InvalidOperationException("The app.config/web.config files for the application did not contain region information"); } } /// /// Determines region based on an environment variable. If the environment does not contain /// the region setting key an InvalidOperationException is thrown. /// public class EnvironmentVariableAWSRegion : AWSRegion { public const string ENVIRONMENT_VARIABLE_REGION = "AWS_REGION"; public const string ENVIRONMENT_VARIABLE_DEFAULT_REGION = "AWS_DEFAULT_REGION"; /// /// Attempts to construct an instance of EnvironmentVariableAWSRegion. If no region is found in the /// environment then an InvalidOperationException is thrown. /// public EnvironmentVariableAWSRegion() { string regionName = Environment.GetEnvironmentVariable(ENVIRONMENT_VARIABLE_REGION); if (string.IsNullOrEmpty(regionName)) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The environment variable {0} was not set with AWS region data.", ENVIRONMENT_VARIABLE_REGION)); } SetRegionFromName(regionName); var logger = Logger.GetLogger(typeof(EnvironmentVariableAWSRegion)); logger.InfoFormat("Region found using environment variable."); } } /// /// Determines region based on inspection of the instance metadata if running on an EC2 instance. /// If instance metadata cannot be read or does not contain region information an InvalidOperationException is thrown. /// public class InstanceProfileAWSRegion : AWSRegion { /// /// Attempts to construct an instance of InstanceProfileAWSRegion. If no region is found in the /// metadata or we are not running on an EC2 instance an InvalidOperationException is thrown. /// public InstanceProfileAWSRegion() { var region = EC2InstanceMetadata.Region; if (region == null) { throw new InvalidOperationException("EC2 instance metadata was not available or did not contain region information."); } this.Region = region; var logger = Logger.GetLogger(typeof(InstanceProfileAWSRegion)); logger.InfoFormat("Region found using EC2 instance metadata."); } } /// /// Determines region based on a stored in an . /// If the profile doesn't exist or there is no region information an InvalidOperationException is thrown. /// public class ProfileAWSRegion : AWSRegion { /// /// Attempts to construct an instance of . /// If the AWS_PROFILE environment variable is set the instance will be constructed using that profile, /// otherwise it will use the default profile. /// /// If the profile doesn't exist or there is no region information an InvalidOperationException is thrown. /// /// The ICredentialProfileSource to read the profile from. public ProfileAWSRegion(ICredentialProfileSource source) { var profileName = FallbackCredentialsFactory.GetProfileName(); Setup(source, profileName); } /// /// Attempts to construct an instance of . /// If the profile doesn't exist or there is no region information an InvalidOperationException is thrown. /// /// The ICredentialProfileSource to read the profile from. /// The name of the profile. public ProfileAWSRegion(ICredentialProfileSource source, string profileName) { Setup(source, profileName); } private void Setup(ICredentialProfileSource source, string profileName) { RegionEndpoint region = null; CredentialProfile profile; if (source.TryGetProfile(profileName, out profile)) { region = profile.Region; } else throw new InvalidOperationException("Unable to find a profile named '" + profileName + "' in store " + source.GetType()); if (region == null) throw new InvalidOperationException("There is no Region set in the profile named '" + profileName + "' in store " + source.GetType()); else { this.Region = region; var logger = Logger.GetLogger(typeof(ProfileAWSRegion)); logger.InfoFormat("Region found in profile '" + profileName + "' in store " + source.GetType()); } } } /// /// Probing mechanism to determine region from various sources. /// public static class FallbackRegionFactory { private static CredentialProfileStoreChain credentialProfileChain = new CredentialProfileStoreChain(); private static object _lock = new object(); static FallbackRegionFactory() { Reset(); } private delegate AWSRegion RegionGenerator(); private static List AllGenerators { get; set; } private static List NonMetadataGenerators { get; set; } public static void Reset() { cachedRegion = null; AllGenerators = new List { () => new AppConfigAWSRegion(), () => new EnvironmentVariableAWSRegion(), () => new ProfileAWSRegion(credentialProfileChain), () => new InstanceProfileAWSRegion() }; NonMetadataGenerators = new List { () => new AppConfigAWSRegion(), () => new EnvironmentVariableAWSRegion(), () => new ProfileAWSRegion(credentialProfileChain), }; } private static AWSRegion cachedRegion; public static RegionEndpoint GetRegionEndpoint() { return GetRegionEndpoint(true); } public static RegionEndpoint GetRegionEndpoint(bool includeInstanceMetadata) { lock(_lock) { if (cachedRegion != null) return cachedRegion.Region; List errors = new List(); IEnumerable generators = includeInstanceMetadata ? AllGenerators : NonMetadataGenerators; foreach (var generator in generators) { try { cachedRegion = generator(); } catch (Exception e) { cachedRegion = null; errors.Add(e); } if (cachedRegion != null) break; } return cachedRegion != null ? cachedRegion.Region : null; } } } }