Exemplo n.º 1
0
 /**
  * Gets period data for top farms
  *
  * @param   int        $accountId       The current client id
  * @param   array      $allowedEnvs     Array of allowed environments' ids for current user
  * @param   string     $mode            The mode (week, month, quarter, year)
  * @param   string     $startDate       The start date of the period in UTC ('Y-m-d')
  * @param   string     $endDate         The end date of the period in UTC ('Y-m-d')
  * @param   int        $farmCount       Top farms count
  * @return  array      Returns cost analytics data for environment scope
  */
 public function getTopFarmsPeriodData($accountId, array $allowedEnvs, $mode, $startDate, $endDate, $farmCount = 5)
 {
     $utcTz = new DateTimeZone('UTC');
     $iterator = ChartPeriodIterator::create($mode, new DateTime($startDate, $utcTz), new DateTime($endDate, $utcTz), 'UTC');
     $start = $iterator->getStart();
     $end = $iterator->getEnd();
     //Interval which is used in the database query for grouping
     $queryInterval = preg_replace('/^1 /', '', $iterator->getInterval());
     $criteria = !empty($allowedEnvs) ? ['envId' => $allowedEnvs] : [];
     //Requests data for the specified period
     $rawUsage = $this->getFarmData($accountId, $criteria, $start, $end, [$queryInterval, TagEntity::TAG_ID_FARM], true);
     //Requests data for the previous period
     $rawPrevUsage = $this->getFarmData($accountId, $criteria, $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [$queryInterval, TagEntity::TAG_ID_FARM], true);
     //Calculates top five farms for the specified period
     $topFarms = [];
     $arr = (new AggregationCollection(['farmId'], ['cost' => 'sum']))->load($rawUsage)->getArrayCopy();
     if (!empty($arr['data']) && count($arr['data']) > $farmCount + 1) {
         uasort($arr['data'], function ($a, $b) {
             if ($a['cost'] == $b['cost']) {
                 return 0;
             }
             return $a['cost'] < $b['cost'] ? 1 : -1;
         });
         $i = 0;
         foreach ($arr['data'] as $farmId => $v) {
             $topFarms[$farmId] = $farmId;
             if (++$i >= $farmCount) {
                 break;
             }
         }
     }
     //Subtotals by farms
     $usage = new AggregationCollection(['farmId'], ['cost' => 'sum']);
     //Previous period subtotals by farms
     $prevUsage = new AggregationCollection(['farmId'], ['cost' => 'sum']);
     if (empty($topFarms)) {
         //Loads current period
         foreach ($rawUsage as $item) {
             $usage->append($item);
         }
         //Loads previous period
         foreach ($rawPrevUsage as $item) {
             $prevUsage->append($item);
         }
     } else {
         //Loads current period and aggregates top 5 farms
         foreach ($rawUsage as $item) {
             if (array_key_exists($item['farmId'], $topFarms)) {
                 $usage->append($item);
             }
         }
         //Loads previous period and aggregates top 5 farms
         foreach ($rawPrevUsage as $item) {
             if (array_key_exists($item['farmId'], $topFarms)) {
                 $prevUsage->append($item);
             }
         }
     }
     //Calculates percentage
     $usage->calculatePercentage();
     if ($iterator->getWholePreviousPeriodEnd() != $iterator->getPreviousEnd()) {
         $rawPrevUsageWhole = $this->getFarmData($accountId, ['envId' => $allowedEnvs], $iterator->getPreviousStart(), $iterator->getWholePreviousPeriodEnd(), [TagEntity::TAG_ID_FARM], true);
         //Previous whole period usage subtotals by farm
         $prevUsageWhole = (new AggregationCollection(['farmId'], ['cost' => 'sum']))->load($rawPrevUsageWhole);
     } else {
         $prevUsageWhole = $prevUsage;
     }
     //Build farms total
     $farmsTotal = [];
     $it = $usage->getIterator();
     foreach ($it as $farmId => $p) {
         $pp = isset($prevUsage['data'][$farmId]) ? $prevUsage['data'][$farmId] : null;
         $pw = isset($prevUsageWhole['data'][$farmId]) ? $prevUsageWhole['data'][$farmId] : null;
         $cl = $this->getTotalDataArray($farmId, $this->fetchFarmName($farmId), $p, $pp, $pw, [], null, true);
         $farmsTotal[] = $cl;
     }
     return $farmsTotal;
 }
Exemplo n.º 2
0
 /**
  * Gets analytics data for the specified project and period
  *
  * @param   string   $projectId The identifier of the Project (UUID)
  * @param   string   $mode      Mode (week, month, quarter, year, custom)
  * @param   string   $startDate Start date in UTC (Y-m-d)
  * @param   string   $endDate   End date in UTC (Y-m-d)
  * @return  array    Returns analytics data for the specified project and period
  */
 public function getProjectPeriodData($projectId, $mode, $startDate, $endDate)
 {
     $analytics = $this->getContainer()->analytics;
     /* @var $projectEntity ProjectEntity */
     $projectEntity = ProjectEntity::findPk($projectId);
     $ccId = $projectEntity->ccId;
     $utcTz = new DateTimeZone('UTC');
     $currentDate = new DateTime('now', $utcTz);
     $iterator = new ChartPeriodIterator($mode, new DateTime($startDate, $utcTz), new DateTime($endDate, $utcTz), 'UTC');
     $start = $iterator->getStart();
     $end = $iterator->getEnd();
     $timelineEvents = $analytics->events->count($iterator->getInterval(), $iterator->getStart(), $iterator->getEnd(), null, $projectId);
     //Interval which is used in the database query for grouping
     $queryInterval = preg_replace('/^1 /', '', $iterator->getInterval());
     //Requests data for the specified period
     $rawUsage = $this->get(['projectId' => $projectId], $start, $end, [$queryInterval, TagEntity::TAG_ID_PLATFORM, TagEntity::TAG_ID_FARM], true);
     //Requests data for the previous period
     $rawPrevUsage = $this->get(['projectId' => $projectId], $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [$queryInterval, TagEntity::TAG_ID_PLATFORM, TagEntity::TAG_ID_FARM], true);
     $max = 5;
     //Calculates top five farms for the specified period
     $top5farms = [];
     $this->otherFarmsQuantity = 0;
     $arr = (new AggregationCollection(['farmId'], ['cost' => 'sum']))->load($rawUsage)->getArrayCopy();
     if (!empty($arr['data']) && count($arr['data']) > $max + 1) {
         $this->otherFarmsQuantity = count($arr['data']) - $max;
         uasort($arr['data'], function ($a, $b) {
             if ($a['cost'] == $b['cost']) {
                 return 0;
             }
             return $a['cost'] < $b['cost'] ? 1 : -1;
         });
         $i = 0;
         foreach ($arr['data'] as $farmId => $v) {
             $top5farms[$farmId] = $farmId;
             if (++$i >= 5) {
                 break;
             }
         }
     }
     $usgByPlatformDetailed = (new AggregationCollection(['period', 'platform'], ['cost' => 'sum']))->load($rawUsage)->calculatePercentage();
     $usgByPlatformPrevDetailed = (new AggregationCollection(['period', 'platform'], ['cost' => 'sum']))->load($rawPrevUsage)->calculatePercentage();
     if (empty($top5farms)) {
         $usgByFarmDetailed = (new AggregationCollection(['period', 'farmId', 'platform'], ['cost' => 'sum']))->load($rawUsage)->calculatePercentage();
         $usgByFarmPrevDetailed = (new AggregationCollection(['period', 'farmId', 'platform'], ['cost' => 'sum']))->load($rawPrevUsage)->calculatePercentage();
     } else {
         $usgByFarmDetailed = new AggregationCollection(['period', 'farmId', 'platform'], ['cost' => 'sum']);
         foreach ($rawUsage as $d) {
             if (!array_key_exists($d['farmId'], $top5farms)) {
                 $d['farmId'] = self::EVERYTHING_ELSE;
             }
             $usgByFarmDetailed->append($d);
         }
         $usgByFarmDetailed->calculatePercentage();
         $usgByFarmPrevDetailed = new AggregationCollection(['period', 'farmId', 'platform'], ['cost' => 'sum']);
         foreach ($rawPrevUsage as $d) {
             if (!array_key_exists($d['farmId'], $top5farms)) {
                 $d['farmId'] = self::EVERYTHING_ELSE;
             }
             $usgByFarmPrevDetailed->append($d);
         }
         $usgByFarmPrevDetailed->calculatePercentage();
     }
     $cloudsData = [];
     $farmsData = [];
     $timeline = [];
     $prevPointKey = null;
     foreach ($iterator as $chartPoint) {
         /* @var $chartPoint \Scalr\Stats\CostAnalytics\ChartPointInfo */
         $i = $chartPoint->i;
         $timeline[] = ['datetime' => $chartPoint->dt->format('Y-m-d H:00'), 'label' => $chartPoint->label, 'onchart' => $chartPoint->show, 'cost' => round(isset($usgByPlatformDetailed['data'][$chartPoint->key]['cost']) ? $usgByPlatformDetailed['data'][$chartPoint->key]['cost'] : 0, 2), 'events' => isset($timelineEvents[$chartPoint->key]) ? $timelineEvents[$chartPoint->key] : null];
         //Period - Platform - Farms subtotals
         if (!isset($usgByPlatformDetailed['data'][$chartPoint->key]['data'])) {
             foreach ($cloudsData as $platform => $v) {
                 if (!$iterator->isFuture()) {
                     //Previous period details
                     if (isset($usgByPlatformPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$platform])) {
                         $pp = $usgByPlatformPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$platform];
                     } else {
                         $pp = null;
                     }
                     //Previous point details
                     if (isset($usgByPlatformDetailed['data'][$prevPointKey]['data'][$platform])) {
                         $ppt = $usgByPlatformDetailed['data'][$prevPointKey]['data'][$platform];
                     } else {
                         $ppt = null;
                     }
                     $r = $this->getPointDataArray(null, $pp, $ppt);
                     //Projects data is empty
                     $r['farms'] = [];
                     $cloudsData[$platform]['data'][] = $r;
                 } else {
                     $cloudsData[$platform]['data'][] = null;
                 }
             }
         } else {
             foreach ($usgByPlatformDetailed['data'][$chartPoint->key]['data'] as $platform => $v) {
                 //Previous period details
                 if (isset($usgByPlatformPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$platform])) {
                     $pp = $usgByPlatformPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$platform];
                 } else {
                     $pp = null;
                 }
                 //Previous point details
                 if (isset($usgByPlatformDetailed['data'][$prevPointKey]['data'][$platform])) {
                     $ppt = $usgByPlatformDetailed['data'][$prevPointKey]['data'][$platform];
                 } else {
                     $ppt = null;
                 }
                 if (!isset($cloudsData[$platform]) && $i > 0) {
                     $cloudsData[$platform]['name'] = $platform;
                     //initializes platfrorm legend for the not filled period
                     $cloudsData[$platform]['data'] = array_fill(0, $i, null);
                 }
                 if (!$iterator->isFuture()) {
                     $r = $this->getPointDataArray($v, $pp, $ppt);
                     // Farms data is accessible by clicking on a point
                     $r['farms'] = [];
                     $cloudsData[$platform]['name'] = $platform;
                     $cloudsData[$platform]['data'][] = $r;
                 } else {
                     $cloudsData[$platform]['data'][] = null;
                 }
             }
         }
         //Period - Farm - Platform subtotal
         if (!isset($usgByFarmDetailed['data'][$chartPoint->key]['data'])) {
             foreach ($farmsData as $farmId => $v) {
                 if (!$iterator->isFuture()) {
                     //Previous period details
                     if (isset($usgByFarmPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmId])) {
                         $pp = $usgByFarmPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmId];
                     } else {
                         $pp = null;
                     }
                     //Previous point details
                     if (isset($usgByFarmDetailed['data'][$prevPointKey]['data'][$farmId])) {
                         $ppt = $usgByFarmDetailed['data'][$prevPointKey]['data'][$farmId];
                     } else {
                         $ppt = null;
                     }
                     $r = $this->getPointDataArray(null, $pp, $ppt);
                     //Projects data is empty
                     $r['clouds'] = [];
                     $farmsData[$farmId]['data'][] = $r;
                 } else {
                     $farmsData[$farmId]['data'][] = null;
                 }
             }
         } else {
             foreach ($usgByFarmDetailed['data'][$chartPoint->key]['data'] as $farmId => $v) {
                 //Previous period details
                 if (isset($usgByFarmPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmId])) {
                     $pp = $usgByFarmPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmId];
                 } else {
                     $pp = null;
                 }
                 //Previous point details
                 if (isset($usgByFarmDetailed['data'][$prevPointKey]['data'][$farmId])) {
                     $ppt = $usgByFarmDetailed['data'][$prevPointKey]['data'][$farmId];
                 } else {
                     $ppt = null;
                 }
                 if (!isset($farmsData[$farmId]) && $i > 0) {
                     $farmsData[$farmId]['name'] = $this->fetchFarmName($farmId);
                     //initializes project legend for the not filled period
                     $farmsData[$farmId]['data'] = array_fill(0, $i, null);
                 }
                 if (!$iterator->isFuture()) {
                     $r = $this->getPointDataArray($v, $pp, $ppt);
                     // platform data
                     $cloudPlatformData = [];
                     if (!empty($v['data'])) {
                         foreach ($v['data'] as $platform => $pv) {
                             $cloudPlatformData[] = $this->getDetailedPointDataArray($platform, $platform, $pv, isset($pp['data'][$platform]) ? $pp['data'][$platform] : null, isset($ppt['data'][$platform]) ? $ppt['data'][$platform] : null);
                         }
                     }
                     $r['clouds'] = $cloudPlatformData;
                     $farmsData[$farmId]['name'] = $this->fetchFarmName($farmId);
                     $farmsData[$farmId]['data'][] = $r;
                 } else {
                     $farmsData[$farmId]['data'][] = null;
                 }
             }
         }
         $prevPointKey = $chartPoint->key;
     }
     //complete arrays for cloud data and project data
     $cntpoints = count($timeline);
     foreach ($cloudsData as $platform => $v) {
         if (($j = count($v['data'])) < $cntpoints) {
             while ($j < $cntpoints) {
                 $cloudsData[$platform]['data'][] = null;
                 $j++;
             }
         }
     }
     foreach ($farmsData as $farmId => $v) {
         if (($j = count($v['data'])) < $cntpoints) {
             while ($j < $cntpoints) {
                 $farmsData[$farmId]['data'][] = null;
                 $j++;
             }
         }
     }
     //Subtotals by platforms
     $usage = new AggregationCollection(['platform', 'farmId'], ['cost' => 'sum']);
     //Subtotals by farms
     $usage2 = new AggregationCollection(['farmId' => ['envId'], 'platform'], ['cost' => 'sum']);
     //Previous period subtotals by platforms
     $prevUsage = new AggregationCollection(['platform', 'farmId'], ['cost' => 'sum']);
     //Previous period subtotals by farms
     $prevUsage2 = new AggregationCollection(['farmId', 'platform'], ['cost' => 'sum']);
     if (empty($top5farms)) {
         //Loads current period
         foreach ($rawUsage as $item) {
             $usage->append($item);
             $usage2->append($item);
         }
         //Loads previous period
         foreach ($rawPrevUsage as $item) {
             $prevUsage->append($item);
             $prevUsage2->append($item);
         }
     } else {
         //Loads current period and aggregates top 5 farms
         foreach ($rawUsage as $item) {
             if (!array_key_exists($item['farmId'], $top5farms)) {
                 $item['farmId'] = self::EVERYTHING_ELSE;
             }
             $usage->append($item);
             $usage2->append($item);
         }
         //Loads previous period and aggregates top 5 farms
         foreach ($rawPrevUsage as $item) {
             if (!array_key_exists($item['farmId'], $top5farms)) {
                 $item['farmId'] = self::EVERYTHING_ELSE;
             }
             $prevUsage->append($item);
             $prevUsage2->append($item);
         }
     }
     //Calculates percentage
     $usage->calculatePercentage();
     $usage2->calculatePercentage();
     $prevUsage->calculatePercentage();
     $prevUsage2->calculatePercentage();
     if ($iterator->getWholePreviousPeriodEnd() != $iterator->getPreviousEnd()) {
         $rawPrevUsageWhole = $this->get(['projectId' => $projectId], $iterator->getPreviousStart(), $iterator->getWholePreviousPeriodEnd(), [TagEntity::TAG_ID_PLATFORM, TagEntity::TAG_ID_FARM], true);
         //Previous whole period usage subtotals by platform
         $prevUsageWhole = (new AggregationCollection(['platform'], ['cost' => 'sum']))->load($rawPrevUsageWhole);
         //Previous whole period usage subtotals by farm
         $prevUsageWhole2 = (new AggregationCollection(['farmId'], ['cost' => 'sum']))->load($rawPrevUsageWhole);
     } else {
         $prevUsageWhole = $prevUsage;
         $prevUsageWhole2 = $prevUsage2;
     }
     //Build cloud platforms total
     $cloudsTotal = [];
     $it = $usage->getIterator();
     foreach ($it as $platform => $p) {
         $pp = isset($prevUsage['data'][$platform]) ? $prevUsage['data'][$platform] : null;
         $pw = isset($prevUsageWhole['data'][$platform]) ? $prevUsageWhole['data'][$platform] : null;
         $cl = $this->getTotalDataArray($platform, $platform, $p, $pp, $pw, $cloudsData, $iterator);
         if ($it->hasChildren()) {
             $clFarms = [];
             foreach ($it->getChildren() as $farmId => $c) {
                 $cp = isset($prevUsage['data'][$platform]['data'][$farmId]) ? $prevUsage['data'][$platform]['data'][$farmId] : null;
                 $clFarms[] = $this->getTotalDataArray($farmId, $this->fetchFarmName($farmId), $c, $cp, null, $farmsData, $iterator, true);
             }
             $cl['farms'] = $clFarms;
         } else {
             $cl['farms'] = [];
         }
         $cloudsTotal[] = $cl;
     }
     //Build projects total
     $farmsTotal = [];
     $it = $usage2->getIterator();
     foreach ($it as $farmId => $p) {
         $pp = isset($prevUsage2['data'][$farmId]) ? $prevUsage2['data'][$farmId] : null;
         $pw = isset($prevUsageWhole2['data'][$farmId]) ? $prevUsageWhole2['data'][$farmId] : null;
         $cl = $this->getTotalDataArray($farmId, $this->fetchFarmName($farmId), $p, $pp, $pw, $farmsData, $iterator);
         if ($farmId && $farmId != self::EVERYTHING_ELSE && !empty($p['envId'])) {
             $cl['environment'] = ['id' => (int) $p['envId'], 'name' => AccountTagEntity::fetchName($p['envId'], TagEntity::TAG_ID_ENVIRONMENT)];
         }
         if ($it->hasChildren()) {
             $clPlatforms = [];
             foreach ($it->getChildren() as $platform => $c) {
                 $cp = isset($prevUsage2['data'][$farmId]['data'][$platform]) ? $prevUsage2['data'][$farmId]['data'][$platform] : null;
                 $clPlatforms[] = $this->getTotalDataArray($platform, $platform, $c, $cp, null, $cloudsData, $iterator, true);
             }
             $cl['clouds'] = $clPlatforms;
         } else {
             $cl['clouds'] = [];
         }
         $farmsTotal[] = $cl;
     }
     $data = ['reportVersion' => '0.1.0', 'totals' => ['cost' => round($usage['cost'], 2), 'prevCost' => round($prevUsage['cost'], 2), 'growth' => round($usage['cost'] - $prevUsage['cost'], 2), 'growthPct' => $prevUsage['cost'] == 0 ? null : round(abs(($usage['cost'] - $prevUsage['cost']) / $prevUsage['cost'] * 100), 0), 'clouds' => $cloudsTotal, 'farms' => $farmsTotal, 'trends' => $this->calculateSpendingTrends(['projectId' => $projectId], $timeline, $queryInterval, $iterator->getEnd()), 'forecastCost' => null], 'timeline' => $timeline, 'clouds' => $cloudsData, 'farms' => $farmsData, 'interval' => $queryInterval, 'startDate' => $iterator->getStart()->format('Y-m-d'), 'endDate' => $iterator->getEnd()->format('Y-m-d'), 'previousStartDate' => $iterator->getPreviousStart()->format('Y-m-d'), 'previousEndDate' => $iterator->getPreviousEnd()->format('Y-m-d')];
     if ($iterator->getTodayDate() < $iterator->getEnd()) {
         //Today is in the selected period
         $data['totals']['forecastCost'] = self::calculateForecast($data['totals']['cost'], $start, $end, $prevUsageWhole['cost'], ($data['totals']['growth'] >= 0 ? 1 : -1) * $data['totals']['growthPct'], isset($data['totals']['trends']['rollingAverageDaily']) ? $data['totals']['trends']['rollingAverageDaily'] : null);
     }
     $budgetRequest = ['projectId' => $projectId, 'usage' => $data['totals']['cost']];
     if ($mode != 'custom') {
         //We need to get budget for the appropriate quarter
         $budgetRequest['period'] = $iterator->getQuarterPeriod();
     }
     $budget = $this->getBudgetUsedPercentage($budgetRequest);
     $this->calculateBudgetEstimateOverspend($budget);
     $data['totals']['budget'] = $budget;
     return $data;
 }