예제 #1
0
        /// <summary>
        /// Creates a consolidated pricing term from a regularly formatted pricing term
        /// that comes directly from the price list api. Used when you've grouped the price list by
        /// SKU which gives pricing terms for all on demand and reserved terms in the group. This
        /// will identify the on demand term and then construct the reserved terms.
        /// </summary>
        /// <param name="commonSkus"></param>
        /// <param name="product"></param>
        /// <returns></returns>
        public static IEnumerable <ReservedInstancePricingTerm> Build(IGrouping <string, PricingTerm> commonSkus, Product product)
        {
            if (commonSkus == null)
            {
                throw new ArgumentNullException("commonSkus");
            }

            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            PricingTerm onDemand = commonSkus.FirstOrDefault(x => x.TermAttributes.PurchaseOption == PurchaseOption.ON_DEMAND);

            if (onDemand == null)
            {
                throw new KeyNotFoundException($"{product.ProductFamily} - An on demand price data term was not found for sku: {commonSkus.Key}.");
            }

            IEnumerable <PricingTerm> reservedTerms = commonSkus.Where(x => x.TermAttributes.PurchaseOption != PurchaseOption.ON_DEMAND);

            if (!reservedTerms.Any())
            {
                return(Enumerable.Empty <ReservedInstancePricingTerm>());
            }

            return(Build(product, onDemand, reservedTerms));
        }
예제 #2
0
        /// <summary>
        /// Creates a consolidated pricing term from a regularly formatted pricing term
        /// that comes directly from the price list API. Used when you've already identified the on
        /// demand pricing term and have separated out just the reserved pricing terms.
        /// </summary>
        /// <param name="product"></param>
        /// <param name="ondemand"></param>
        /// <param name="reservedterms"></param>
        /// <returns></returns>
        public static IEnumerable <ReservedInstancePricingTerm> Build(Product product, PricingTerm ondemand, IEnumerable <PricingTerm> reservedterms)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            if (ondemand == null)
            {
                throw new ArgumentNullException("ondemand");
            }

            if (reservedterms == null)
            {
                throw new ArgumentNullException("reservedterms");
            }

            if (!reservedterms.Any())
            {
                throw new ArgumentException("You must supply at least 1 reserved term.");
            }

            double onDemandCost = -1;

            // Get the on demand hourly cost
            // DynamoDB has free tier price dimensions in the same on demand object, so make
            // sure we pick the first that does not have free tier in the description
            KeyValuePair <string, PriceDimension> dimension = ondemand.PriceDimensions.FirstOrDefault(x => !x.Value.Description.Contains(FREE_TIER, StringComparison.OrdinalIgnoreCase));

            if (dimension.Value == null)
            {
                onDemandCost = 0;
            }
            else if (!Double.TryParse(dimension.Value.PricePerUnit.First().Value, out onDemandCost))
            {
                throw new FormatException($"Could not parse the on demand price {dimension.Value.PricePerUnit.First().Value} for sku: {product.Sku}.");
            }

            string platform = GetPlatform(product);
            string region   = RegionMapper.GetRegionFromUsageType(product.Attributes.GetValueOrDefault("usagetype"));

            // Only EC2 has tenancy
            if (!product.Attributes.TryGetValue("tenancy", out string tenancy))
            {
                tenancy = "Shared";
            }

            // Each pricing term will have the price dimensions for the upfront and recurring costs
            foreach (PricingTerm term in reservedterms)
            {
                PriceDimension upfront = term.PriceDimensions
                                         .Select(x => x.Value)
                                         .FirstOrDefault(x => !String.IsNullOrEmpty(x.Description) && x.Description.Equals("upfront fee", StringComparison.OrdinalIgnoreCase));

                PriceDimension recurring = term.PriceDimensions
                                           .Select(x => x.Value)
                                           .FirstOrDefault(x => !String.IsNullOrEmpty(x.Description) && !x.Description.Equals("upfront fee", StringComparison.OrdinalIgnoreCase));

                double hourlyRecurring = 0;

                // Only check for recurring, since some may have no upfront
                if (recurring == null)
                {
                    // This should never happen
                    throw new KeyNotFoundException($"The pricing term in {product.Attributes.GetValueOrDefault("servicecode")} for sku {term.Sku} and offer term code {term.OfferTermCode} did not contain a price dimension for hourly usage charges.");
                }
                else
                {
                    // Parse out the rate
                    if (!Double.TryParse(recurring.PricePerUnit.First().Value, out hourlyRecurring))
                    {
                        throw new FormatException($"Could not parse the recurring price per unit of {recurring.PricePerUnit.First().Value} for sku {term.Sku}, offer term code {term.OfferTermCode}, in service {product.Attributes.GetValueOrDefault("servicecode")}.");
                    }
                }

                double upfrontFee = 0;

                if (upfront != null)
                {
                    // Parse out upfront fee
                    if (!Double.TryParse(upfront.PricePerUnit.First().Value, out upfrontFee))
                    {
                        throw new FormatException($"Could not parse the upfront cost of {upfront.PricePerUnit.First().Value} for sku {term.Sku}, offer term code {term.OfferTermCode}, in service {product.Attributes.GetValueOrDefault("servicecode")}.");
                    }
                }

                string operatingSystem = String.Empty;

                if (product.Attributes.ContainsKey("operatingsystem"))
                {
                    operatingSystem = product.Attributes.GetValueOrDefault("operatingsystem");
                }
                else
                {
                    operatingSystem = platform;
                }

                int vCPU = 0;

                if (product.Attributes.ContainsKey("vcpu"))
                {
                    Int32.TryParse(product.Attributes.GetValueOrDefault("vcpu"), out vCPU);
                }

                double memory = 0;

                if (product.Attributes.ContainsKey("memory"))
                {
                    string memoryString = product.Attributes.GetValueOrDefault("memory").Replace(",", "");

                    Match memoryMatch = _MemoryRegex.Match(memoryString);

                    if (memoryMatch.Success)
                    {
                        Double.TryParse(memoryMatch.Groups[1].Value, out memory);
                    }
                }

                string usageType = product.Attributes.GetValueOrDefault("usagetype");

                string instanceType = usageType;

                if (product.Attributes.ContainsKey("instancetype"))
                {
                    instanceType = product.Attributes.GetValueOrDefault("usagetype");
                }

                yield return(new ReservedInstancePricingTerm(
                                 term.Sku,
                                 term.OfferTermCode,
                                 product.Attributes.GetValueOrDefault("servicecode"),
                                 platform,
                                 operatingSystem,
                                 instanceType,
                                 product.Attributes.GetValueOrDefault("operation"),
                                 usageType,
                                 tenancy,
                                 region,
                                 vCPU,
                                 memory,
                                 onDemandCost,
                                 hourlyRecurring,
                                 upfrontFee,
                                 term.TermAttributes.LeaseContractLength,
                                 term.TermAttributes.PurchaseOption,
                                 term.TermAttributes.OfferingClass,
                                 AWSPriceListApi.Model.Term.RESERVED
                                 ));
            }
        }