示例#1
0
        public static void Main(string[] args)
        {
            // Get the last months billing data
            DateTime startDateTime = DateTime.Now.Date.AddMonths(-1);
            DateTime endDateTime   = DateTime.Now.Date;

            // Get AAD token
            string token = GetOAuthTokenFromAAD(clientId, clientSecret, tennantId, resource, authority).Result;

            // Get rate card
            RateCardPayload rateCardPayload = GetRateCard(token, billingService, subscriptionId).Result;

            // Get usage
            UsagePayload usagePayload = GetUsage(token, billingService, subscriptionId, startDateTime, endDateTime).Result;

            // Create aggregates by resource group
            List <ResourceGroupAggregate> resourceGroupAggregates = CreateResourceGroupAggregates(usagePayload, rateCardPayload);

            // Write headers to console
            Console.WriteLine("Resource Group\tDate\tCost");

            // Write daily output to console
            foreach (ResourceGroupAggregate resourceGroupAggregate in resourceGroupAggregates)
            {
                foreach (DateTime date in resourceGroupAggregate.ResourceItems.SelectMany(x => x.ResourceDateItems.Select(y => y.UsageStartTime)).Distinct().ToList())
                {
                    Console.WriteLine(resourceGroupAggregate.ResourceGroupName + "\t" + date.ToString("dd/MM/yyyy") + "\t" + resourceGroupAggregate.ResourceItems.SelectMany(x => x.ResourceDateItems.Where(y => y.UsageStartTime == date)).Sum(z => z.Cost).ToString("F"));
                }
            }

            Console.ReadLine();
        }
        private static double Calculate(IEnumerable <UsagePayload> usagePayload, RateCardPayload rateCardPayload, TraceWriter log)
        {
            double totalSpend = 0;

            if (usagePayload == null || rateCardPayload == null)
            {
                return(totalSpend);
            }
            foreach (var usageGroup in usagePayload.SelectMany(usage => usage.Value).GroupBy(usage => $"{usage.Properties.MeterCategory} {usage.Properties.MeterSubCategory}"))
            {
                double typeSpend = 0;
                foreach (var usage in usageGroup)
                {
                    var meter = rateCardPayload.Meters.FirstOrDefault(iterMeter => iterMeter.MeterId.Equals(usage.Properties.MeterId));
                    if (meter != null)
                    {
                        typeSpend += CalcMeterPerUsage(usage, meter, log);
                    }
                    else
                    {
                        log.Info($"could not find meter for usage: {usage.Name}");
                    }
                }
                log.Info($"total spend in month on {usageGroup.Key} is {typeSpend}");
                totalSpend += typeSpend;
            }
            log.Info($"total spend in month {totalSpend}");
            return(totalSpend);
        }
        /// <summary>
        /// Method to get project rates.
        /// </summary>
        /// <param name="rates">Rate card information.</param>
        /// <param name="projects">Projects collection.</param>
        /// <returns>Project rates.</returns>
        public static IEnumerable <ProjectRate> GetProjectRates(RateCardPayload rates, IEnumerable <ProjectUsage> projects)
        {
            IEnumerable <ProjectRate> ratesList = from p in projects
                                                  select new ProjectRate(
                p.ProjectName, GetMeterIDRates(p.MeterIdTotals, rates));

            return(ratesList);
        }
        /// <summary>
        /// Method to get Rate Card object.
        /// </summary>
        /// <returns>Rate Card object.</returns>
        public static RateCardPayload GetRateCardPayload()
        {
            RateCardPayload resourceRatesRootObject =
                JsonConvert.DeserializeObject <RateCardPayload>(
                    File.ReadAllText(@"C:\Users\MoinakBandyopadhyay\Desktop\response.json"));

            return(resourceRatesRootObject);
        }
        /// <summary>
        /// Method to get included quantity for meter Id
        /// </summary>
        /// <param name="rates">rates information</param>
        /// <param name="meterId">meter id</param>
        /// <returns>included quantity</returns>
        public static double GetIncludedQuantityForMeterID(RateCardPayload rates, string meterId)
        {
            List <Resource> resources = rates.Meters;

            IEnumerable <double> includedquantity = from r in resources
                                                    where r.MeterId == meterId
                                                    select r.IncludedQuantity;

            return(includedquantity.FirstOrDefault());
        }
        /// <summary>
        /// method to get Resource Name by Meter Id
        /// </summary>
        /// <param name="rates">rates information</param>
        /// <param name="meterId">Meter id</param>
        /// <returns>Resource name</returns>
        public static string GetResourceNameByMeterId(RateCardPayload rates, string meterId)
        {
            List <Resource> resources = rates.Meters;

            IEnumerable <string> rate = from r in resources
                                        where r.MeterId == meterId
                                        select r.MeterName;

            return(rate.FirstOrDefault());
        }
        /// <summary>
        /// Method to get Resource rates.
        /// </summary>
        /// <param name="rates">Rate card information.</param>
        /// <param name="resourceUsage">Resource usage collection.</param>
        /// <returns>Resource rate collection.</returns>
        public static IEnumerable <ResourceRate> GetResourceRates(
            RateCardPayload rates,
            IEnumerable <ResourceUsage> resourceUsage)
        {
            IEnumerable <ResourceRate> ratesList = from r in resourceUsage
                                                   select new ResourceRate(
                r.ResourceName, GetMeterIDRates(r.MeterIdTotals, rates));

            return(ratesList);
        }
        /// <summary>
        /// Method to get rates for Meter ID.
        /// </summary>
        /// <param name="rates">Rates information.</param>
        /// <param name="meterId">Meter id.</param>
        /// <returns>Meter rates.</returns>
        public static Dictionary <double, double> GetRatesForMeterID(RateCardPayload rates, string meterId)
        {
            List <Resource> resources = rates.Meters;
            Resource        r         = resources.Find(x => x.MeterId == meterId);

            if (r == null)
            {
                r = GetUndefinedResource();
            }

            return(r.MeterRates);
        }
示例#9
0
        public static async Task <RateCardPayload> GetRateCard(string token, string billingService, string subscriptionId)
        {
            /*Setup API call to RateCard API
             * Callouts:
             * See the App.config file for all AppSettings key/value pairs
             * You can get a list of offer numbers from this URL: http://azure.microsoft.com/en-us/support/legal/offer-details/
             * You can configure an OfferID for this API by updating 'MS-AZR-{Offer Number}'
             * The RateCard Service/API is currently in preview; please use "2015-06-01-preview" or "2016-08-31-preview" for api-version (see https://msdn.microsoft.com/en-us/library/azure/mt219005 for details)
             * Please see the readme if you are having problems configuring or authenticating: https://github.com/Azure-Samples/billing-dotnet-ratecard-api
             */
            // Build up the HttpWebRequest
            string requestURL = String.Format("{0}/{1}/{2}/{3}",
                                              billingService,
                                              "subscriptions",
                                              subscriptionId,
                                              "providers/Microsoft.Commerce/RateCard?api-version=2016-08-31-preview&$filter=OfferDurableId eq 'MS-AZR-0063P' and Currency eq 'GBP' and Locale eq 'en-GB' and RegionInfo eq 'GB'");

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);

            // Add the OAuth Authorization header, and Content Type header
            request.Headers["Authorization"] = "Bearer " + token;
            request.ContentType = "application/json";

            RateCardPayload payload = new RateCardPayload();

            // Call the RateCard API
            try
            {
                // Call the REST endpoint
                WebResponse response = await request.GetResponseAsync();

                Stream receiveStream = response.GetResponseStream();

                // Pipes the stream to a higher level stream reader with the required encoding format.
                StreamReader readStream       = new StreamReader(receiveStream, Encoding.UTF8);
                var          rateCardResponse = readStream.ReadToEnd();

                // Convert the Stream to a strongly typed RateCardPayload object.
                // You can also walk through this object to manipulate the individuals member objects.
                payload = JsonConvert.DeserializeObject <RateCardPayload>(rateCardResponse);
                response.Dispose();
                readStream.Dispose();
            }
            catch (Exception e)
            {
                Console.WriteLine(String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : ""));
                Console.ReadLine();
            }

            return(payload);
        }
示例#10
0
        public static RateCardPayload GetRateCardInfo(string restUrl, Guid orgId)
        {
            HttpWebResponse httpWebResponse = AzureResourceManagerUtil.RateCardRestApiCall(restUrl, orgId);

            try {
                if (httpWebResponse == null)
                {
                    Trace.TraceWarning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                    Trace.TraceWarning($"{nameof(httpWebResponse)} == null");
                    Trace.TraceWarning($"     {nameof(GetRateCardInfo)}({nameof(restUrl)}, {nameof(orgId)})");
                    Trace.TraceWarning($"     {nameof(restUrl)}: {restUrl}");
                    Trace.TraceWarning($"     {nameof(orgId)}: {orgId}");
                    // throw exception to start from scretch and retry.
                    //throw new Exception("Possible reason: Bad request (400), Forbidden (403) to access. Server busy. Client blacklisted.");
                }
                else
                {
                    // look response codes @ https://msdn.microsoft.com/en-us/library/azure/mt219001.aspx
                    // see: https://msdn.microsoft.com/en-us/library/azure/mt219004.aspx
                    if (httpWebResponse.StatusCode == HttpStatusCode.OK)
                    {
                        Trace.TraceInformation($"Received Rest Call Response: {nameof(HttpStatusCode.OK)}. Processing...");
                        string streamContent;

                        using (Stream receiveStream = httpWebResponse.GetResponseStream()) {
                            // Pipes the stream to a higher level stream reader with the required encoding format.
                            using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8)) {
                                streamContent = readStream.ReadToEnd();
                            }
                        }

                        RateCardPayload rateCardPayload = JsonConvert.DeserializeObject <RateCardPayload>(streamContent);
                        return(rateCardPayload);
                    }
                    else if (httpWebResponse.StatusCode == HttpStatusCode.Accepted)
                    {
                        Trace.TraceWarning($"Data not ready. {nameof(HttpStatusCode.Accepted)}. Not capable of handling this.");
                    }
                    else
                    {
                        Trace.TraceWarning("NEW RESPONSE TYPE. HANDLE THIS - GetRateCardInfo!");
                        Trace.TraceWarning($"code:{httpWebResponse.StatusCode} desc:{httpWebResponse.StatusDescription}");
                    }
                }

                return(null);
            } finally {
                httpWebResponse?.Dispose();
            }
        }
        /// <summary>
        /// Method to get Meter id rates.
        /// </summary>
        /// <param name="meterIdTotals">Meter id totals.</param>
        /// <param name="rates">Rate card information.</param>
        /// <returns>Rated usage.</returns>
        public static IEnumerable <RatedUsage> GetMeterIDRates(
            IEnumerable <MeterIDTotal> meterIdTotals,
            RateCardPayload rates)
        {
            IEnumerable <RatedUsage> ratesList = from m in meterIdTotals
                                                 select new RatedUsage(
                m.MeterId,
                m.ResourceTotals,
                GetRatesForMeterID(rates, m.MeterId),
                ComputeRatedUsagePerMeter(GetRatesForMeterID(rates, m.MeterId), GetRatableUsage(m.ResourceTotals, GetIncludedQuantityForMeterID(rates, m.MeterId))),
                GetMeterSubCategoryByMeterId(rates, m.MeterId),
                GetServiceByMeterId(rates, m.MeterId),
                GetResourceNameByMeterId(rates, m.MeterId));

            return(ratesList);
        }
示例#12
0
        private async Task <List <Resource> > GetPrice(string token, string subscription)
        {
            var filter = "&$filter=OfferDurableId eq 'MS-AZR-0003p' and Currency eq 'KRW' and Locale eq 'en-us' and RegionInfo eq 'KR'";
            var uri    = "/subscriptions/" + subscription + "/providers/Microsoft.Commerce/RateCard?api-version=2015-06-01-preview" + filter;

            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://management.azure.com");

                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);

                var             resultContent = client.GetStringAsync(uri);
                RateCardPayload payload       = JsonConvert.DeserializeObject <RateCardPayload>(await resultContent);

                return(payload.Meters);
            }
        }
示例#13
0
        public static RateCardPayload GetRateCardInfo(string restURL, string orgID)
        {
            HttpWebResponse httpWebResponse = null;

            httpWebResponse = AzureResourceManagerUtil.RateCardRestApiCall(restURL, orgID);

            if (httpWebResponse == null)
            {
                Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                Console.WriteLine("httpWebResponse == null");
                Console.WriteLine("     GetRateCardInfo(string restURL, string orgID)");
                Console.WriteLine("     restURL: {0}", restURL);
                Console.WriteLine("     orgID: {0}", orgID);

                // throw exception to start from scretch and retry.
                //throw new Exception("Possible reason: Bad request (400), Forbidden (403) to access. Server busy. Client blacklisted.");
            }
            else
            {
                // look response codes @ https://msdn.microsoft.com/en-us/library/azure/mt219001.aspx
                if (httpWebResponse.StatusCode == HttpStatusCode.OK)
                {
                    Console.WriteLine("Received Rest Call Response: HttpStatusCode.OK. Processing...");
                    Stream receiveStream = httpWebResponse.GetResponseStream();

                    // Pipes the stream to a higher level stream reader with the required encoding format.
                    StreamReader readStream    = new StreamReader(receiveStream, Encoding.UTF8);
                    string       streamContent = readStream.ReadToEnd();

                    RateCardPayload rateCardPayload = JsonConvert.DeserializeObject <RateCardPayload>(streamContent);
                    return(rateCardPayload);
                }
                else if (httpWebResponse.StatusCode == HttpStatusCode.Accepted)
                {
                    Console.WriteLine("Data not ready. HttpStatusCode.Accepted. Not capable of handling this.");
                }
                else
                {
                    Console.WriteLine("NEW RESPONSE TYPE. HANDLE THIS - GetRateCardInfo!");
                    Console.WriteLine("code:{0} desc:{1}", httpWebResponse.StatusCode, httpWebResponse.StatusDescription);
                }
            }
            return(null);
        }
示例#14
0
        /// <summary>
        /// Method to collect azure usage records from Azure APIs.
        /// </summary>
        /// <returns>Collection of Usage records.</returns>
        private IEnumerable <UsageInfoModel> GetUsageInfo()
        {
            // Loop for every subscription
            foreach (var subscription in this.subscriptions)
            {
                // Get usage details for subscription
                RateCardPayload rates = AzureResourceManagerUtil.GetRates(subscription.Id, org.Id, authResult);

                List <UsageAggregate> usageList = AzureResourceManagerUtil.GetUsage(
                    subscription.Id,
                    org.Id,
                    authResult,
                    this.startDate,
                    this.endDate);

                IEnumerable <string> projects = AzureResourceManagerUtil.GetUniqueProjects(usageList);
                subscription.Projects = projects;

                IEnumerable <ProjectUsage> projectTotals =
                    AzureResourceManagerUtil.GetProjectIDTotals(usageList, projects);
                subscription.ProjectTotals = projectTotals;

                IEnumerable <ProjectRate> projectRates = AzureResourceManagerUtil.GetProjectRates(
                    rates,
                    projectTotals);
                subscription.ProjectRates = projectRates;

                IEnumerable <ProjectEstimate> projectEstimateTotals =
                    AzureResourceManagerUtil.RatedEstimateForProject(projectRates);
                subscription.ProjectEstimateTotals = projectEstimateTotals;

                IEnumerable <string> resourceList = AzureResourceManagerUtil.GetResources(usageList);

                IEnumerable <ResourceUsage> resourceUsages =
                    AzureResourceManagerUtil.GetResourceUsage(usageList, resourceList);
                subscription.ResourceTotals = AzureResourceManagerUtil.GetResourceTotals(resourceList, usageList);

                IEnumerable <ResourceRate> resourceRates =
                    AzureResourceManagerUtil.GetResourceRates(rates, resourceUsages);

                IEnumerable <ResourceEstimate> resourceEstimates =
                    AzureResourceManagerUtil.RatedEstimateForResource(resourceRates);
                subscription.ResourceEstimates = resourceEstimates;

                subscription.MeterIdTotals = AzureResourceManagerUtil.GetMeterIdTotals(usageList);
                subscription.ServiceTotals = AzureResourceManagerUtil.GetServiceTotals(usageList);

                var result = JsonConvert.SerializeObject(subscription.MeterIdTotals); // Input to graphing solution
                subscription.UsageDetails = result;

                IEnumerable <RatedUsage> ratedUsageList =
                    AzureResourceManagerUtil.GetMeterIDRates(
                        AzureResourceManagerUtil.GetMeterIdTotals(usageList), rates);
                subscription.ratedUsage    = ratedUsageList;
                subscription.RatedEstimate = AzureResourceManagerUtil.RatedEstimate(ratedUsageList);

                foreach (var usg in usageList)
                {
                    double usgtot =
                        AzureResourceManagerUtil.ComputeRatedUsagePerMeter(
                            AzureResourceManagerUtil.GetRatesForMeterID(rates, usg.properties.meterId),
                            usg.properties.quantity);

                    this.usageInfo.Add(new UsageInfoModel()
                    {
                        OrganizationId     = org.Id,
                        SubceriptionId     = subscription.Id,
                        UsageStartTime     = usg.properties.usageStartTime,
                        UsageEndTime       = usg.properties.usageEndTime,
                        MeteredRegion      = usg.properties.infoFields.MeteredRegion,
                        MeterName          = usg.properties.meterName,
                        MeteredService     = usg.properties.infoFields.MeteredService,
                        MeteredServiceType = usg.properties.infoFields.MeteredServiceType,
                        MeterCategory      = usg.properties.meterCategory,
                        MeterSubCategory   = usg.properties.meterSubCategory,
                        UserProject        = usg.properties.infoFields.Project,
                        Quantity           = usg.properties.quantity,
                        ItemTotal          = usgtot
                    });
                }
            }

            return(this.usageInfo);
        }
 private static double SpendDuringCurrentMonth(string token, string armBillingService,
                                               string subscriptionId, string subscriptionType, TraceWriter log, int currentMonth) =>
 Math.Round(
     Calculate(UsagePayloads.GetUsagePayLoads(token, armBillingService, subscriptionId, log, currentMonth),
               RateCardPayload.GetRateCardPayLoad(token, armBillingService, subscriptionId, subscriptionType, log),
               log), 1);
示例#16
0
        public static void ProcessQueueMessage([QueueTrigger("billingdatarequests")] BillingRequest br)
        {
            Console.WriteLine("Start webjob process. SubscriptionID: {0}", br.SubscriptionId);
            int retriesLeft = Convert.ToInt32(ConfigurationManager.AppSettings["ida:RetryCountToProcessMessage"].ToString());

            while (retriesLeft > 0)
            {
                --retriesLeft;
                if (retriesLeft < 1)
                {
                    Console.WriteLine("Finished internal retries, throwing exception. Time:{0}", DateTime.UtcNow.ToString());
                    throw new Exception();
                }

                Console.WriteLine("Start time:{0} Retries Left: {1}", DateTime.UtcNow.ToString(), retriesLeft);

                try
                {
                    //Fetch RateCard information First
                    string rateCardURL = AzureResourceManagerUtil.GetRateCardRestApiCallURL(br.SubscriptionId,
                                                                                            ConfigurationManager.AppSettings["ida:OfferCode"].ToString(),
                                                                                            ConfigurationManager.AppSettings["ida:Currency"].ToString(),
                                                                                            ConfigurationManager.AppSettings["ida:Locale"].ToString(),
                                                                                            ConfigurationManager.AppSettings["ida:RegionInfo"].ToString());
                    Console.WriteLine("Request cost info from RateCard service.");
                    RateCardPayload rateCardInfo = GetRateCardInfo(rateCardURL, br.OrganizationId);
                    if (rateCardInfo == null)
                    {
                        Console.WriteLine("Problem receiving cost info occured - see log for details.");
                        continue;
                    }
                    else
                    {
                        Console.WriteLine("Received cost info: " + rateCardInfo.ToString());
                    }

                    // if granularity=hourly then report up to prev. hour,
                    // if granularity=daily then report up to prev. day. Othervise will get 400 error
                    //DateTime sdt = DateTime.Now.AddYears(-3);
                    //DateTime edt = DateTime.Now.AddDays(-1);

                    string restURL = AzureResourceManagerUtil.GetBillingRestApiCallURL(br.SubscriptionId, false, true, br.StartDate, br.EndDate);

                    Console.WriteLine("Request usage data from Billing service.");
                    List <UsageRecord> urs = GetUsageDetails(restURL, br.OrganizationId, rateCardInfo);
                    Console.WriteLine("Received record count: {0}", urs.Count);

                    Console.WriteLine("Insert usage data into SQL Server.");
                    InsertIntoSQLDB(urs);

                    break;
                }
                catch (Exception e)
                {
                    Console.WriteLine("Exception: ProcessQueueMessage->e.Message: " + e.Message);

                    if (retriesLeft == 0)
                    {
                        throw;
                    }
                }

                Console.WriteLine("Sleeping in ProcessQueueMessage while loop for 5 min. DateTime: {0}", DateTime.Now.ToString());
                Thread.Sleep(1000 * 60 * 5);
            }   // while

            Commons.Utils.UpdateSubscriptionStatus(br.SubscriptionId, DataGenStatus.Completed, DateTime.UtcNow);

            Console.WriteLine("Complete webjob process. SubscriptionID: {0}", br.SubscriptionId);
        }
示例#17
0
        public static List <UsageRecord> GetUsageDetails(string restURL, string orgID, RateCardPayload rateCardInfo)
        {
            string             nextLink     = "";
            List <UsageRecord> usageRecords = new List <UsageRecord>();

            do
            {
                HttpWebResponse httpWebResponse = null;

                if (nextLink != "")
                {
                    httpWebResponse = AzureResourceManagerUtil.BillingRestApiCall(nextLink, orgID);
                }
                else
                {
                    httpWebResponse = AzureResourceManagerUtil.BillingRestApiCall(restURL, orgID);
                }

                if (httpWebResponse == null)
                {
                    Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                    Console.WriteLine("httpWebResponse == null");
                    Console.WriteLine("     GetUsageDetails(string restURL, string orgID)");
                    Console.WriteLine("     restURL: {0}", restURL);
                    Console.WriteLine("     orgID: {0}", orgID);

                    // throw exception to start from scretch and retry.
                    //throw new Exception("Possible reason: Bad request (400), Forbidden (403) to access. Server busy. Client blacklisted.");
                }
                else
                {
                    // look response codes @ https://msdn.microsoft.com/en-us/library/azure/mt219001.aspx
                    if (httpWebResponse.StatusCode == HttpStatusCode.OK)
                    {
                        Console.WriteLine("Received Rest Call Response: HttpStatusCode.OK. Processing...");
                        Stream receiveStream = httpWebResponse.GetResponseStream();

                        // Pipes the stream to a higher level stream reader with the required encoding format.
                        StreamReader readStream    = new StreamReader(receiveStream, Encoding.UTF8);
                        string       streamContent = readStream.ReadToEnd();

                        UsagePayload usagePayload = JsonConvert.DeserializeObject <UsagePayload>(streamContent);

                        foreach (UsageAggregate ua in usagePayload.value)
                        {
                            //Handle adding cost in
                            var ur = new UsageRecord(ua);
                            try {
                                var meterInfo = rateCardInfo.Meters.Where(p => p.MeterId == ur.meterId).SingleOrDefault();
                                ur.cost = meterInfo.MeterRates["0"] * Convert.ToDecimal(ur.quantity);
                                if (ur.cost < 0.01M)
                                {
                                    ur.cost = 0;
                                }
                            } catch (Exception ex)
                            {
                                Console.WriteLine("Exception trying to apply cost info for meter: " + ur.meterId);
                            }
                            usageRecords.Add(ur);
                        }

                        ContinuationToken contToken = JsonConvert.DeserializeObject <ContinuationToken>(streamContent);
                        if (contToken.nextLink != null)
                        {
                            nextLink = contToken.nextLink;
                        }
                        else
                        {
                            nextLink = "";
                        }
                    }
                    else if (httpWebResponse.StatusCode == HttpStatusCode.Accepted)
                    {
                        Console.WriteLine("Data not ready. HttpStatusCode.Accepted. Waiting 6 min. now: {0}", DateTime.Now.ToString());
                        Thread.Sleep(1000 * 60 * 6); // wait a bit to have data get prepared by azure
                        nextLink = restURL;          // set next link to same URL for second call
                    }
                    else
                    {
                        Console.WriteLine("NEW RESPONSE TYPE. HANDLE THIS!");
                        Console.WriteLine("code:{0} desc:{1}", httpWebResponse.StatusCode, httpWebResponse.StatusDescription);
                    }
                }
            } while (nextLink != "");

            return(usageRecords);
        }
        public static List<UsageRecord> GetUsageDetails(string restURL, string orgID, RateCardPayload rateCardInfo)
        {
            string nextLink = "";
            List<UsageRecord> usageRecords = new List<UsageRecord>();

            do
            {
                HttpWebResponse httpWebResponse = null;

                if (nextLink != "")
                    httpWebResponse = AzureResourceManagerUtil.BillingRestApiCall(nextLink, orgID);
                else
                    httpWebResponse = AzureResourceManagerUtil.BillingRestApiCall(restURL, orgID);

                if (httpWebResponse == null)
                {
                    Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                    Console.WriteLine("httpWebResponse == null");
                    Console.WriteLine("     GetUsageDetails(string restURL, string orgID)");
                    Console.WriteLine("     restURL: {0}", restURL);
                    Console.WriteLine("     orgID: {0}", orgID);

                    // throw exception to start from scretch and retry.
                    //throw new Exception("Possible reason: Bad request (400), Forbidden (403) to access. Server busy. Client blacklisted.");
                }
                else
                {
                    // look response codes @ https://msdn.microsoft.com/en-us/library/azure/mt219001.aspx
                    if (httpWebResponse.StatusCode == HttpStatusCode.OK)
                    {
                        Console.WriteLine("Received Rest Call Response: HttpStatusCode.OK. Processing...");
                        Stream receiveStream = httpWebResponse.GetResponseStream();

                        // Pipes the stream to a higher level stream reader with the required encoding format.
                        StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
                        string streamContent = readStream.ReadToEnd();

                        UsagePayload usagePayload = JsonConvert.DeserializeObject<UsagePayload>(streamContent);

                        foreach (UsageAggregate ua in usagePayload.value)
                        {
                            //Handle adding cost in
                            var ur = new UsageRecord(ua);
                            try {
                                var meterInfo = rateCardInfo.Meters.Where(p => p.MeterId == ur.meterId).SingleOrDefault();
                                ur.cost = meterInfo.MeterRates["0"] * Convert.ToDecimal(ur.quantity);
                                if (ur.cost < 0.01M)
                                    ur.cost = 0;
                            } catch (Exception ex)
                            {
                                Console.WriteLine("Exception trying to apply cost info for meter: " + ur.meterId);
                            }
                            usageRecords.Add(ur);
                        }

                        ContinuationToken contToken = JsonConvert.DeserializeObject<ContinuationToken>(streamContent);
                        if (contToken.nextLink != null)
                            nextLink = contToken.nextLink;
                        else
                            nextLink = "";
                    }
                    else if (httpWebResponse.StatusCode == HttpStatusCode.Accepted)
                    {
                        Console.WriteLine("Data not ready. HttpStatusCode.Accepted. Waiting 6 min. now: {0}", DateTime.Now.ToString());
                        Thread.Sleep(1000 * 60 * 6);  // wait a bit to have data get prepared by azure
                        nextLink = restURL;  // set next link to same URL for second call
                    }
                    else
                    {
                        Console.WriteLine("NEW RESPONSE TYPE. HANDLE THIS!");
                        Console.WriteLine("code:{0} desc:{1}", httpWebResponse.StatusCode, httpWebResponse.StatusDescription);
                    }
                }
            } while (nextLink != "");

            return usageRecords;
        }
示例#19
0
        public static List <ResourceGroupAggregate> CreateResourceGroupAggregates(UsagePayload usagePayload, RateCardPayload rateCardPayload)
        {
            List <ResourceGroupAggregate> resourceGroupAggregates = new List <ResourceGroupAggregate>();

            // Get distinct resource groups
            foreach (UsageAggregate usage in usagePayload.Value)
            {
                if (usage.Properties.InstanceData.MicrosoftResources.ResourceList.ContainsKey("resourceGroups"))
                {
                    // Get resource group
                    ResourceGroupAggregate resourceGroupAggregate = resourceGroupAggregates.SingleOrDefault(x => x.ResourceGroupName.ToLower() == usage.Properties.InstanceData.MicrosoftResources.ResourceList["resourceGroups"].ToLower());

                    // Add resource group if it doesn't already exist
                    if (resourceGroupAggregate == null)
                    {
                        resourceGroupAggregate = new ResourceGroupAggregate();
                        resourceGroupAggregate.ResourceGroupName = usage.Properties.InstanceData.MicrosoftResources.ResourceList["resourceGroups"];
                        resourceGroupAggregates.Add(resourceGroupAggregate);
                        resourceGroupAggregate = resourceGroupAggregates.SingleOrDefault(x => x.ResourceGroupName == usage.Properties.InstanceData.MicrosoftResources.ResourceList["resourceGroups"]);
                    }

                    // Get resource item
                    ResourceItem resourceItem = resourceGroupAggregate.ResourceItems.SingleOrDefault(x => x.MeterName == usage.Properties.MeterName);

                    // Add resource item if it doesn't already exist
                    if (resourceItem == null)
                    {
                        resourceItem = new ResourceItem();
                        resourceItem.MeterCategory = usage.Properties.MeterCategory;
                        resourceItem.MeterName     = usage.Properties.MeterName;
                        resourceGroupAggregate.ResourceItems.Add(resourceItem);
                        resourceItem = resourceGroupAggregate.ResourceItems.SingleOrDefault(x => x.MeterName == usage.Properties.MeterName);
                    }

                    ResourceDateItem resourceDateItem = new ResourceDateItem();
                    resourceDateItem.Quantity       = usage.Properties.Quantity;
                    resourceDateItem.Cost           = rateCardPayload.Meters.Where(x => x.MeterId == usage.Properties.MeterId).FirstOrDefault().MeterRates[0] * usage.Properties.Quantity;
                    resourceDateItem.UsageStartTime = DateTime.Parse(usage.Properties.UsageStartTime);
                    resourceDateItem.UsageEndTime   = DateTime.Parse(usage.Properties.UsageEndTime);

                    resourceItem.ResourceDateItems.Add(resourceDateItem);
                }
            }

            return(resourceGroupAggregates);
        }
示例#20
0
        public static List <UsageRecord> GetUsageDetails(string restUrl, Guid orgId, RateCardPayload rateCardInfo)
        {
            string             nextLink     = "";
            List <UsageRecord> usageRecords = new List <UsageRecord>();

            do
            {
                HttpWebResponse httpWebResponse = null;

                try {
                    if (nextLink != "")
                    {
                        httpWebResponse = AzureResourceManagerUtil.BillingRestApiCall(nextLink, orgId);
                    }
                    else
                    {
                        httpWebResponse = AzureResourceManagerUtil.BillingRestApiCall(restUrl, orgId);
                    }

                    if (httpWebResponse == null)
                    {
                        Trace.TraceWarning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                        Trace.TraceWarning($"{nameof(httpWebResponse)} == null");
                        Trace.TraceWarning($"     {nameof(GetUsageDetails)}({nameof(restUrl)}, {nameof(orgId)})");
                        Trace.TraceWarning($"     {nameof(restUrl)}: {restUrl}");
                        Trace.TraceWarning($"     {nameof(orgId)}: {orgId}");

                        // throw exception to start from scretch and retry.
                        //throw new Exception("Possible reason: Bad request (400), Forbidden (403) to access. Server busy. Client blacklisted.");
                    }
                    else
                    {
                        // look response codes @ https://msdn.microsoft.com/en-us/library/azure/mt219001.aspx
                        if (httpWebResponse.StatusCode == HttpStatusCode.OK)
                        {
                            Trace.TraceInformation($"Received Rest Call Response: {nameof(HttpStatusCode.OK)}. Processing...");
                            string streamContent;

                            using (Stream receiveStream = httpWebResponse.GetResponseStream()) {
                                // Pipes the stream to a higher level stream reader with the required encoding format.
                                using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8)) {
                                    streamContent = readStream.ReadToEnd();
                                }
                            }

                            UsagePayload usagePayload = JsonConvert.DeserializeObject <UsagePayload>(streamContent);

                            foreach (UsageAggregate ua in usagePayload.Value)
                            {
                                // handle adding cost in
                                var usageRecord = new UsageRecord(ua);

                                try {
                                    var meterInfo = rateCardInfo.Meters.Where(p => p.MeterId == usageRecord.MeterId).SingleOrDefault();

                                    if (meterInfo.MeterRates.Count > 1)
                                    {
                                        Trace.TraceWarning("Multiple rates for meter: " + usageRecord.MeterId);
                                    }

                                    usageRecord.Cost = (double)meterInfo.MeterRates["0"] * usageRecord.Quantity;
                                    //if (usageRecord.cost < 0.01) usageRecord.cost = 0; // TODO: usage cost is definitelly NOT rounded like this
                                } catch (Exception ex) {
                                    Trace.TraceError("Exception trying to apply cost info for meter: " + usageRecord.MeterId);
                                }

                                usageRecords.Add(usageRecord);
                            }

                            ContinuationToken contToken = JsonConvert.DeserializeObject <ContinuationToken>(streamContent);
                            nextLink = contToken.NextLink ?? "";
                        }
                        else if (httpWebResponse.StatusCode == HttpStatusCode.Accepted)
                        {
                            Trace.TraceWarning($"Data not ready. {nameof(HttpStatusCode.Accepted)}. Waiting 6 min. now: {DateTime.UtcNow}");
                            Thread.Sleep(1000 * 60 * 6);                     // wait a bit to have data get prepared by azure
                            nextLink = restUrl;                              // set next link to same URL for second call
                        }
                        else
                        {
                            Trace.TraceWarning("NEW RESPONSE TYPE. HANDLE THIS!");
                            Trace.TraceWarning($"code:{httpWebResponse.StatusCode} desc:{httpWebResponse.StatusDescription}");
                        }
                    }
                } finally {
                    httpWebResponse?.Dispose();
                }
            } while (nextLink != "");

            return(usageRecords);
        }
示例#21
0
        public static void ProcessQueueMessage([QueueTrigger("billingdatarequests")] BillingRequest billingRequest, TextWriter logWriter = null)
        {
            if (logWriter != null)
            {
                TextWriterTraceListener traceListener = new TextWriterTraceListener(logWriter, "LogWriter");
                Trace.Listeners.Remove("LogWriter");
                Trace.Listeners.Add(traceListener);
                Trace.TraceInformation("Azure WebJob Log Writer configured");
            }

            Trace.TraceInformation($"WebJob process started. {nameof(billingRequest.SubscriptionId)}: {billingRequest.SubscriptionId}");
            int       retriesLeft   = Convert.ToInt32(RetryCountToProcessMessage);
            Exception lastException = null;

            while (retriesLeft > 0)
            {
                --retriesLeft;

                if (retriesLeft < 1)
                {
                    Trace.TraceInformation($"Finished internal retries, time:{DateTime.UtcNow}");

                    if (lastException != null)
                    {
                        throw lastException;
                    }
                    else
                    {
                        return;
                    }
                }

                Trace.TraceInformation($"Start time:{DateTime.UtcNow}, retries Left: {retriesLeft}");

                try {
                    //Fetch RateCard information First
                    string rateCardUrl = AzureResourceManagerUtil.GetRateCardRestApiCallURL(billingRequest.SubscriptionId, OfferCode, Currency, Locale, RegionInfo);
                    Trace.TraceInformation("Request cost info from RateCard service.");

                    RateCardPayload rateCardInfo = GetRateCardInfo(rateCardUrl, billingRequest.OrganizationId);

                    if (rateCardInfo == null)
                    {
                        Trace.TraceWarning("Problem receiving cost info occured - see log for details.");
                        continue;
                    }
                    else
                    {
                        Trace.TraceInformation("Received cost info: " + rateCardInfo.ToString());
                    }

                    // if granularity=hourly then report up to prev. hour,
                    // if granularity=daily then report up to prev. day. Othervise will get 400 error
                    //DateTime sdt = DateTime.UtcNow.Date.AddYears(-3);
                    //DateTime edt = DateTime.UtcNow.Date.AddDays(-1);

                    // see: https://msdn.microsoft.com/en-us/library/azure/mt219004.aspx
                    string restUrl = AzureResourceManagerUtil.GetBillingRestApiCallUrl(billingRequest.SubscriptionId, true, true, billingRequest.StartDate, billingRequest.EndDate);

                    Trace.TraceInformation("Request usage data from Billing service.");
                    var usageRecords = GetUsageDetails(restUrl, billingRequest.OrganizationId, rateCardInfo);
                    Trace.TraceInformation($"Received record count: {usageRecords.Count}");

                    if (usageRecords.Count > 0)
                    {
                        Trace.TraceInformation("Inserting usage records into SQL database.");
                        Task <int> task        = InsertIntoSqlDbAsync(usageRecords, billingRequest.SubscriptionId, billingRequest.StartDate, billingRequest.EndDate);
                        int        recordCount = task.GetAwaiter().GetResult();
                        Trace.TraceInformation($"Total {recordCount} usage record(s) inserted.");
                    }
                    else
                    {
                        Trace.TraceInformation("No usage data found.");
                    }

                    break;
                } catch (Exception e) {
                    Trace.TraceError($"Exception: {nameof(ProcessQueueMessage)} -> e.Message: " + e.Message);
                    lastException = e;
                    if (retriesLeft == 0)
                    {
                        throw;
                    }
                }

                Trace.TraceInformation($"Sleeping in {nameof(ProcessQueueMessage)} while loop for 5 min. DateTime: {DateTime.UtcNow}");
                Thread.Sleep(1000 * 60 * 5);
            }               // while

            Utils.UpdateSubscriptionStatus(billingRequest.SubscriptionId, DataGenStatus.Completed, DateTime.UtcNow);

            Trace.TraceInformation($"WebJob process completed. SubscriptionId: {billingRequest.SubscriptionId}");
        }