Пример #1
0
 /**
  * Gets events list
  *
  * @param string $mode      Chart mode
  * @param string $date      The requested date time
  * @param string $start     Start date of the current period
  * @param string $end       optional End date of the period
  * @param string $ccId      optional Cost center id
  * @param string $projectId optional Project id
  * @throws InvalidArgumentException
  */
 public function xGetTimelineEventsAction($mode, $date, $start, $end = null, $ccId = null, $projectId = null)
 {
     if (!preg_match('/^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:00$/', $date)) {
         throw new InvalidArgumentException(sprintf("Invalid date:%s. 'YYYY-MM-DD HH:00' is expected.", strip_tags($date)));
     }
     $analytics = $this->getContainer()->analytics;
     $iterator = new ChartPeriodIterator($mode, $start, $end ?: null, 'UTC');
     foreach ($iterator as $chartPoint) {
         //FIXME rewrite search a point
         if ($chartPoint->dt->format('Y-m-d H:00') === $date) {
             $startDate = $chartPoint->dt;
             if ($chartPoint->isLastPoint) {
                 $endDate = $iterator->getEnd();
             } else {
                 $iterator->next();
                 $endDate = $iterator->current()->dt;
                 $endDate->modify("-1 second");
             }
             break;
         }
     }
     if (!isset($startDate)) {
         throw new OutOfBoundsException(sprintf("Date %s is inconsistent with the interval object", $date));
     }
     $entities = $analytics->events->get($startDate, $endDate, $ccId, $projectId);
     $data = [];
     foreach ($entities as $entity) {
         $data[] = ['dtime' => $entity->dtime->format('Y-m-d H:i:s'), 'description' => $entity->description, 'type' => $entity->eventType];
     }
     $this->response->data(['data' => $data]);
 }
Пример #2
0
 /**
  * Gets events list
  *
  * @param string $mode      Chart mode
  * @param string $date      The requested date time
  * @param string $start     Start date of the current period
  * @param string $end       optional End date of the period
  * @param string $envId     optional Environment id
  * @param string $projectId optional Project id
  * @throws InvalidArgumentException
  */
 public function xGetTimelineEventsAction($mode, $date, $start, $end = null, $envId = null, $projectId = null)
 {
     if (!preg_match('/^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:00$/', $date)) {
         throw new InvalidArgumentException(sprintf("Invalid date:%s. 'YYYY-MM-DD HH:00' is expected.", strip_tags($date)));
     }
     if (!empty($envId)) {
         $env = Scalr_Environment::init()->loadById($envId);
         if ($env->clientId !== $this->user->getAccountId()) {
             throw new Scalr_Exception_InsufficientPermissions();
         }
     }
     $analytics = $this->getContainer()->analytics;
     $iterator = ChartPeriodIterator::create($mode, $start, $end ?: null, 'UTC');
     $pointPosition = $iterator->searchPoint($date);
     if ($pointPosition !== false) {
         $chartPoint = $iterator->current();
         $startDate = $chartPoint->dt;
         if ($chartPoint->isLastPoint) {
             $endDate = $chartPoint->end;
         } else {
             $iterator->next();
             $endDate = $iterator->current()->dt;
             $endDate->modify("-1 second");
         }
     }
     if (!isset($startDate)) {
         throw new OutOfBoundsException(sprintf("Date %s is inconsistent with the interval object", $date));
     }
     $entities = $analytics->events->get($startDate, $endDate, ['envId' => $envId, 'accountId' => $this->user->getAccountId(), 'projectId' => $projectId]);
     $data = [];
     foreach ($entities as $entity) {
         $data[] = ['dtime' => $entity->dtime->format('Y-m-d H:i:s'), 'description' => $entity->description, 'type' => $entity->eventType];
     }
     $this->response->data(['data' => $data]);
 }
Пример #3
0
 /**
  * Gets the list of farms
  *
  * @param string $query optional Search query
  * @return array        Retuens array of farms
  */
 private function getFarmsList($query = null)
 {
     $farms = [];
     $collection = $this->getContainer()->analytics->usage->findFarmsByKey($this->environment->id, $query);
     if ($collection->count()) {
         $iterator = ChartPeriodIterator::create('month', gmdate('Y-m-01'), null, 'UTC');
         $criteria = ['envId' => $this->environment->id];
         //It calculates usage for all provided cost centres
         $usage = $this->getContainer()->analytics->usage->getFarmData($this->environment->clientId, $criteria, $iterator->getStart(), $iterator->getEnd(), [TagEntity::TAG_ID_FARM, TagEntity::TAG_ID_FARM_ROLE, TagEntity::TAG_ID_PLATFORM]);
         //It calculates usage for previous period same days
         $prevusage = $this->getContainer()->analytics->usage->getFarmData($this->environment->clientId, $criteria, $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [TagEntity::TAG_ID_FARM]);
         foreach ($collection as $dbFarm) {
             /* @var $dbFarm \DBFarm */
             $totalCost = round(isset($usage['data'][$dbFarm->ID]) ? $usage['data'][$dbFarm->ID]['cost'] : 0, 2);
             $farms[$dbFarm->ID] = $this->getFarmData($dbFarm);
             if (isset($usage['data'][$dbFarm->ID]['data'])) {
                 $farms[$dbFarm->ID]['topSpender'] = $this->getFarmRoleTopSpender($usage['data'][$dbFarm->ID]['data']);
             } else {
                 $farms[$dbFarm->ID]['topSpender'] = null;
             }
             $prevCost = round(isset($prevusage['data'][$dbFarm->ID]) ? $prevusage['data'][$dbFarm->ID]['cost'] : 0, 2);
             $farms[$dbFarm->ID] = $this->getWrappedUsageData(['farmId' => $dbFarm->ID, 'iterator' => $iterator, 'usage' => $totalCost, 'prevusage' => $prevCost]) + $farms[$dbFarm->ID];
         }
     }
     return array_values($farms);
 }
Пример #4
0
 /**
  * Gets a list of environments by key
  *
  * @param  string $query Search query
  * @return array  Returns array of environments
  */
 private function getEnvironmentsList($query = null)
 {
     $envs = [];
     $environments = $this->user->getEnvironments($query);
     if (count($environments) > 0) {
         $iterator = ChartPeriodIterator::create('month', gmdate('Y-m-01'), null, 'UTC');
         //It calculates usage for all provided enviroments
         $usage = $this->getContainer()->analytics->usage->getFarmData($this->user->getAccountId(), [], $iterator->getStart(), $iterator->getEnd(), [TagEntity::TAG_ID_ENVIRONMENT, TagEntity::TAG_ID_FARM]);
         //It calculates usage for previous period same days
         $prevusage = $this->getContainer()->analytics->usage->getFarmData($this->user->getAccountId(), [], $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [TagEntity::TAG_ID_ENVIRONMENT, TagEntity::TAG_ID_FARM]);
         foreach ($environments as $env) {
             if (isset($usage['data'][$env['id']]['data'])) {
                 $envs[$env['id']]['topSpender'] = $this->getFarmTopSpender($usage['data'][$env['id']]['data']);
             } else {
                 $envs[$env['id']]['topSpender'] = null;
             }
             $envs[$env['id']]['name'] = $env['name'];
             $envs[$env['id']]['envId'] = $env['id'];
             $ccId = \Scalr_Environment::init()->loadById($env['id'])->getPlatformConfigValue(\Scalr_Environment::SETTING_CC_ID);
             if (!empty($ccId)) {
                 $envs[$env['id']]['ccId'] = $ccId;
                 $envs[$env['id']]['ccName'] = CostCentreEntity::findPk($ccId)->name;
             }
             $totalCost = round(isset($usage['data'][$env['id']]) ? $usage['data'][$env['id']]['cost'] : 0, 2);
             $prevCost = round(isset($prevusage['data'][$env['id']]) ? $prevusage['data'][$env['id']]['cost'] : 0, 2);
             $envs[$env['id']] = $this->getWrappedUsageData(['iterator' => $iterator, 'usage' => $totalCost, 'prevusage' => $prevCost]) + $envs[$env['id']];
         }
     }
     return array_values($envs);
 }
Пример #5
0
 /**
  * Constructor
  *
  * @param   ChartPeriodIterator $iterator  The iterator
  */
 public function __construct(ChartPeriodIterator $iterator)
 {
     $this->mode = $iterator->getMode();
     $this->dt = $iterator->getIterationTimestamp();
     $this->interval = $iterator->getInterval();
     $this->i = $iterator->getIterationNumber();
     $this->start = $iterator->getStart();
     $this->end = $iterator->getEnd();
     $this->isLastPoint = $iterator->isLastPoint();
 }
 /**
  * @test
  * @dataProvider providerConstructor
  */
 public function testConstructor($mode, $start, $end, $fixture)
 {
     $iterator = ChartPeriodIterator::create($mode, $start, $end);
     $this->assertEquals($fixture['interval'], $iterator->getInterval());
     $this->assertEquals($fixture['startDate'], $iterator->getStart()->format('Y-m-d'), 'Start date does not match.');
     $this->assertEquals($fixture['endDate'], $iterator->getEnd()->format('Y-m-d'), 'End date does not match');
     $this->assertEquals($fixture['prevStartDate'], $iterator->getPreviousStart()->format('Y-m-d'), 'Previous period Start date does not match.');
     $this->assertEquals($fixture['prevEndDate'], $iterator->getPreviousEnd()->format('Y-m-d'), 'Previous period End date does not match.');
     foreach ($iterator as $chartPoint) {
         /* @var $chartPoint ChartPointInfo */
         $this->assertTrue(isset($fixture['keys'][$chartPoint->i]), sprintf("Fixture with number %d is not expected.", $chartPoint->i));
         $this->assertEquals($fixture['keys'][$chartPoint->i], $chartPoint->key, "Keys does not match.");
     }
 }
Пример #7
0
 /**
  * Gets project properties and parameters
  *
  * @param   ProjectEntity    $projectEntity          Project entity
  * @param   string           $calculate     optional Whether response should be adjusted with cost usage data
  * @return  array Returns cost centre properties and parameters
  */
 private function getProjectData(ProjectEntity $projectEntity, $calculate = false)
 {
     $ret = array('ccId' => $projectEntity->ccId, 'ccName' => $projectEntity->getCostCenter() !== null ? $projectEntity->getCostCenter()->name : null, 'projectId' => $projectEntity->projectId, 'name' => $projectEntity->name, 'billingCode' => $projectEntity->getProperty(ProjectPropertyEntity::NAME_BILLING_CODE), 'description' => $projectEntity->getProperty(ProjectPropertyEntity::NAME_DESCRIPTION), 'leadEmail' => $projectEntity->getProperty(ProjectPropertyEntity::NAME_LEAD_EMAIL), 'created' => $projectEntity->created->format('Y-m-d'), 'createdByEmail' => $projectEntity->createdByEmail, 'archived' => $projectEntity->archived, 'shared' => $projectEntity->shared, 'farmsCount' => count($projectEntity->getFarmsList()));
     if (!empty($projectEntity->accountId) && $projectEntity->shared === ProjectEntity::SHARED_WITHIN_ACCOUNT) {
         $ret['accountId'] = $projectEntity->accountId;
         $ret['accountName'] = Scalr_Account::init()->loadById($projectEntity->accountId)->name;
     } elseif (!empty($projectEntity->envId) && $projectEntity->shared === ProjectEntity::SHARED_WITHIN_ENV) {
         $ret['accountId'] = $projectEntity->accountId;
         $ret['accountName'] = Scalr_Account::init()->loadById($projectEntity->accountId)->name;
         $ret['envId'] = $projectEntity->envId;
         $ret['envName'] = Scalr_Environment::init()->loadById($projectEntity->envId)->name;
     }
     if ($calculate) {
         $iterator = ChartPeriodIterator::create('month', gmdate('Y-m-01'), null, 'UTC');
         $usage = $this->getContainer()->analytics->usage->get(['projectId' => $ret['projectId']], $iterator->getStart(), $iterator->getEnd());
         //It calculates usage for previous period same days
         $prevusage = $this->getContainer()->analytics->usage->get(['projectId' => $ret['projectId']], $iterator->getPreviousStart(), $iterator->getPreviousEnd());
         $ret = $this->getWrappedUsageData(['ccId' => $ret['ccId'], 'projectId' => $ret['projectId'], 'iterator' => $iterator, 'usage' => $usage['cost'], 'prevusage' => $prevusage['cost']]) + $ret;
     }
     return $ret;
 }
Пример #8
0
 /**
  * Gets project properties and parameters
  *
  * @param   ProjectEntity    $projectEntity          Project entity
  * @param   string           $calculate   optional Whether response should be adjusted with cost usage data
  * @return  array Returns cost centre properties and parameters
  */
 private function getProjectData(ProjectEntity $projectEntity, $calculate = false)
 {
     $ret = array('ccId' => $projectEntity->ccId, 'ccName' => $projectEntity->getCostCenter() !== null ? $projectEntity->getCostCenter()->name : null, 'projectId' => $projectEntity->projectId, 'name' => $projectEntity->name, 'billingCode' => $projectEntity->getProperty(ProjectPropertyEntity::NAME_BILLING_CODE), 'description' => $projectEntity->getProperty(ProjectPropertyEntity::NAME_DESCRIPTION), 'leadEmail' => $projectEntity->getProperty(ProjectPropertyEntity::NAME_LEAD_EMAIL), 'created' => $projectEntity->created->format('Y-m-d'), 'createdByEmail' => $projectEntity->createdByEmail, 'archived' => $projectEntity->archived, 'farmsCount' => count($projectEntity->getFarmsList()));
     if ($calculate) {
         $iterator = new ChartPeriodIterator('month', gmdate('Y-m-01'), null, 'UTC');
         $usage = $this->getContainer()->analytics->usage->get(['projectId' => $ret['projectId']], $iterator->getStart(), $iterator->getEnd());
         //It calculates usage for previous period same days
         $prevusage = $this->getContainer()->analytics->usage->get(['projectId' => $ret['projectId']], $iterator->getPreviousStart(), $iterator->getPreviousEnd());
         //Calclulates usage for previous whole period
         if ($iterator->getPreviousEnd() != $iterator->getWholePreviousPeriodEnd()) {
             $prevWholePeriodUsage = $this->getContainer()->analytics->usage->get(['projectId' => $ret['projectId']], $iterator->getPreviousStart(), $iterator->getWholePreviousPeriodEnd());
         } else {
             $prevWholePeriodUsage = $prevusage;
         }
         $ret = $this->getWrappedUsageData(['ccId' => $ret['ccId'], 'projectId' => $ret['projectId'], 'iterator' => $iterator, 'usage' => $usage['cost'], 'prevusage' => $prevusage['cost'], 'prevusagewhole' => $prevWholePeriodUsage['cost']]) + $ret;
     }
     return $ret;
 }
Пример #9
0
 /**
  * Constructor
  *
  * @param   ChartPeriodIterator $iterator  The iterator
  * @throws  \InvalidArgumentException
  */
 public function __construct(ChartPeriodIterator $iterator)
 {
     $this->mode = $iterator->getMode();
     $this->dt = $iterator->getIterationTimestamp();
     $this->interval = $iterator->getInterval();
     $this->i = $iterator->getIterationNumber();
     $prevStart = $iterator->getPreviousStart();
     $previousPeriodDt = clone $this->dt;
     $previousPeriodDt->sub($iterator->getPreviousPeriodInterval());
     $this->start = $iterator->getStart();
     $this->end = $iterator->getEnd();
     $this->isLastPoint = $iterator->isLastPoint();
     if ($this->mode == 'year' || $this->mode == 'custom' && $this->interval == '1 month') {
         $this->show = $this->label = $this->dt->format('M');
         $this->key = $this->dt->format('Y-m');
         $this->previousPeriodKey = $previousPeriodDt->format('Y-m');
     } elseif ($this->mode == 'quarter' || $this->mode == 'custom' && $this->interval == '1 week') {
         $ddt = clone $this->dt;
         $ddt->modify('next saturday');
         if ($ddt > $this->end) {
             $ddt = $this->end;
         }
         $this->label = $this->dt->format('M j') . ' - ' . $ddt->format('M j');
         $this->key = \Scalr_Util_DateTime::yearweek($this->dt->format('Y-m-d'));
         $this->previousPeriodKey = \Scalr_Util_DateTime::yearweek($previousPeriodDt->format('Y-m-d'));
         $this->show = $this->i % 3 == 0 ? $this->dt->format('M j') : ($this->isLastPoint && $this->i % 3 > 1 ? $ddt->format('M j') : '');
     } elseif ($this->mode == 'week') {
         $this->label = $this->dt->format('l, M j');
         $this->show = $this->dt->format('M j');
         $this->key = $this->dt->format('Y-m-d');
         $this->previousPeriodKey = $previousPeriodDt->format('Y-m-d');
     } elseif ($this->mode == 'month' || $this->mode == 'custom' && $this->interval == '1 day') {
         $this->label = $this->dt->format('M j');
         $this->key = $this->dt->format('Y-m-d');
         $this->previousPeriodKey = $previousPeriodDt->format('Y-m-d');
         $this->show = $this->i % 4 == 0 || $this->isLastPoint && $this->i % 4 > 2 ? $this->dt->format('M j') : '';
     } elseif ($this->mode == 'custom') {
         switch ($this->interval) {
             case '1 hour':
                 $h = $this->dt->format('H');
                 $this->label = $this->dt->format('l, M j, g A');
                 $this->show = $h == 0 ? $this->dt->format('M j') : ($h % 3 == 0 ? $this->dt->format('g a') : '');
                 $this->key = $this->dt->format("Y-m-d H:00:00");
                 $this->previousPeriodKey = $previousPeriodDt->format('Y-m-d H:00:00');
                 break;
             case '1 quarter':
                 //Quarter breakdown is not supported yet
                 $quarters = new Quarters(SettingEntity::getQuarters());
                 $currentPeriod = $quarters->getPeriodForDate($this->start);
                 $prevPeriod = $quarters->getPeriodForDate($prevStart);
                 $this->show = $this->label = $currentPeriod->year . ' Q' . $currentPeriod->quarter;
                 $this->key = $currentPeriod->year . '-' . $currentPeriod->quarter;
                 $this->previousPeriodKey = $prevPeriod->year . '-' . $prevPeriod->quarter;
                 break;
             case '1 year':
                 $this->show = $this->label = $this->dt->format('Y');
                 $this->key = $this->label;
                 $this->previousPeriodKey = $previousPeriodDt->format('Y');
                 break;
             default:
                 throw new \InvalidArgumentException(sprintf('Unsupported interval for custom mode %s.', $this->interval));
                 break;
         }
     } else {
         throw new \InvalidArgumentException(sprintf('Invalid mode %s', strip_tags($this->mode)));
     }
 }
Пример #10
0
 /**
  * Gets a list of projects by key
  *
  * @param string $query Search query
  * @return array Returns array of projects
  */
 private function getProjectsList($query = null)
 {
     $projects = [];
     $collection = $this->getContainer()->analytics->projects->getAccountProjects($this->user->getAccountId(), $query);
     if ($collection->count()) {
         $iterator = ChartPeriodIterator::create('month', gmdate('Y-m-01'), null, 'UTC');
         //It calculates usage for all provided cost centres
         $usage = $this->getContainer()->analytics->usage->getFarmData($this->user->getAccountId(), [], $iterator->getStart(), $iterator->getEnd(), [TagEntity::TAG_ID_PROJECT]);
         //It calculates usage for previous period same days
         $prevusage = $this->getContainer()->analytics->usage->getFarmData($this->user->getAccountId(), [], $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [TagEntity::TAG_ID_PROJECT]);
         foreach ($collection as $projectEntity) {
             /* @var $projectEntity \Scalr\Stats\CostAnalytics\Entity\ProjectEntity */
             $totalCost = round(isset($usage['data'][$projectEntity->projectId]) ? $usage['data'][$projectEntity->projectId]['cost'] : 0, 2);
             //Archived projects are excluded only when there aren't any usage for this month and
             //query filter key has not been provided.
             if (($query === null || $query === '') && $projectEntity->archived && $totalCost < 0.01) {
                 continue;
             }
             $projects[$projectEntity->projectId] = $this->getProjectData($projectEntity);
             $prevCost = round(isset($prevusage['data'][$projectEntity->projectId]) ? $prevusage['data'][$projectEntity->projectId]['cost'] : 0, 2);
             $projects[$projectEntity->projectId] = $this->getWrappedUsageData(['projectId' => $projectEntity->projectId, 'iterator' => $iterator, 'usage' => $totalCost, 'prevusage' => $prevCost]) + $projects[$projectEntity->projectId];
         }
     }
     return array_values($projects);
 }
Пример #11
0
 /**
  * Gets total data array
  *
  * @param   string              $id                  The identifier of the subject
  * @param   string              $name                The name of the subject
  * @param   array               $currentPeriod
  * @param   array               $previousPeriod
  * @param   array               $previousWholePeriod
  * @param   array               $detailed            Details by each point on chart
  * @param   ChartPeriodIterator $iterator            optional Iterator is needed when it returns long form of array
  * @param   bool                $bshort              optional Whether it should return short form of array
  * @return  array               Returns data array
  */
 public function getTotalDataArray($id, $name, $currentPeriod, $previousPeriod, $previousWholePeriod, $detailed, ChartPeriodIterator $iterator = null, $bshort = false)
 {
     $cl = ['id' => $id, 'name' => $name, 'cost' => isset($currentPeriod['cost']) ? round($currentPeriod['cost'], 2) : 0, 'costPct' => isset($currentPeriod['cost_percentage']) ? $currentPeriod['cost_percentage'] : 0, 'prevCost' => isset($previousPeriod['cost']) ? round($previousPeriod['cost'], 2) : 0, 'prevCostPct' => isset($previousPeriod['cost_percentage']) ? $previousPeriod['cost_percentage'] : 0];
     $cl['growth'] = $cl['cost'] - $cl['prevCost'];
     // growth
     $cl['growthPct'] = $cl['prevCost'] == 0 ? null : round(abs($cl['growth'] / $cl['prevCost'] * 100), 0);
     //growth percentage
     //short form of the data array
     if ($bshort) {
         return $cl;
     }
     // forecasted spend for period
     $cl['forecastCost'] = self::calculateForecast($cl['cost'], $iterator->getStart(), $iterator->getEnd(), $previousWholePeriod['cost'], ($cl['growth'] > 0 ? 1 : -1) * $cl['growthPct']);
     $mediandata = [];
     if (!empty($detailed[$id]['data'])) {
         $dt = $iterator->getStart();
         //FIXME rewrite searching a point
         foreach ($detailed[$id]['data'] as $i => $v) {
             if ($dt > $iterator->today) {
                 break;
             }
             $mediandata[] = !isset($v['cost']) ? 0 : $v['cost'];
             if ($iterator->getInterval() == '1 week') {
                 $dt->modify('next sunday');
             } else {
                 $dt->add($iterator->getIterationInterval());
             }
         }
     }
     $cl['median'] = empty($detailed[$id]['data']) ? 0 : round((double) Scalr_Util_Arrays::median($mediandata), 2);
     $cl['averageCost'] = count($mediandata) ? round(array_sum($mediandata) / count($mediandata), 2) : 0;
     // percentage difference between current and previous period
     $cl['curPrevPctGrowth'] = $cl['costPct'] - $cl['prevCostPct'];
     return $cl;
 }
Пример #12
0
 /**
  * Get period data for one point on chart
  *
  *
  *
  * @param   int         $accountId    Identifier of the Account
  * @param   string      $projectId    optional Identifier of the Project
  * @param   int         $envId        optional Identifier of the Environment
  * @param   int|array   $farmId       optional Identifier of the Farm, or the list of the farms which should be excluded
  * @param   int         $farmRoleId   optional Identifier of the Farm Role Id
  * @param   string      $mode         The mode (chart)
  * @param   string      $date         The UTC date within period ('Y-m-d H:00')
  * @param   string      $start        The start date of the period in UTC ('Y-m-d')
  * @param   string      $end          The end date of the period in UTC ('Y-m-d')
  * @return  array
  */
 public function getFarmPointData($accountId, $projectId = null, $envId = null, $farmId = null, $farmRoleId = null, $mode, $date, $start, $end)
 {
     $criteria = [];
     if ($envId) {
         $criteria['envId'] = $envId;
     }
     if ($farmId) {
         $criteria['farmId'] = $farmId;
     }
     if ($farmRoleId) {
         $criteria['farmRoleId'] = $farmRoleId;
     }
     if ($projectId) {
         $criteria['projectId'] = $projectId;
     }
     $chartPoint = null;
     if (!empty($date)) {
         $iterator = ChartPeriodIterator::create($mode, $start, $end ?: null, 'UTC');
         //Interval which is used in the database query for grouping
         $queryInterval = preg_replace('/^1 /', '', $iterator->getInterval());
         //Finds the key for current label
         foreach ($iterator as $chartPoint) {
             /* @var $chartPoint \Scalr\Stats\CostAnalytics\ChartPointInfo */
             if ($chartPoint->dt->format('Y-m-d H:00') == $date) {
                 break;
             }
         }
     } else {
         $queryInterval = $mode == 'day' ? 'hour' : 'day';
     }
     if ($chartPoint === null) {
         $intervalStart = new DateTime($start . " 00:00:00", new DateTimeZone('UTC'));
         $intervalEnd = new DateTime($end . " 23:59:59", new DateTimeZone('UTC'));
     } else {
         $intervalStart = $chartPoint->dt;
         if ($chartPoint->isLastPoint) {
             $intervalEnd = new DateTime($end . " 23:59:59", new DateTimeZone('UTC'));
         } else {
             $iterator->next();
             $intervalEnd = $iterator->current()->dt->modify('-1 second');
         }
     }
     if ($queryInterval == 'hour') {
         $criteria['hourly'] = true;
     }
     //Requests data for the specified period
     $usg = (new AggregationCollection(['distributionType', 'usageType' => ['name', 'displayName'], 'usageItem' => ['envId', 'platform', 'cloudLocation', 'id']], ['cost' => 'sum', 'minUsage' => 'min', 'maxUsage' => 'max', 'usageHours' => 'sum', 'workingHours' => 'sum']))->load($this->getFarmData($accountId, $criteria, $intervalStart, $intervalEnd, ['distributionType', 'usageType', 'usageItem'], true))->calculatePercentage();
     $distrTypes = [];
     if (!empty($usg['data'])) {
         foreach ($usg['data'] as $distrType => $distrUsage) {
             $usageTypesData = [];
             $distrTypesDataPoint = $this->getDetailedPointDataArray($distrType, $distrType, $distrUsage, null, null);
             foreach ($distrUsage['data'] as $usageType => $uv) {
                 $usageTypeDataPoint = ['id' => $usageType, 'name' => $uv['name'], 'displayName' => $uv['displayName'], 'measure' => $this->getMeasure($uv['name'])];
                 if (!empty($uv['data'])) {
                     $usageItemsData = [];
                     foreach ($uv['data'] as $usageItem => $iv) {
                         if ($uv['name'] == UsageTypeEntity::NAME_COMPUTE_BOX_USAGE) {
                             $usageItemName = $this->getInstanceTypeName($usageItem, $iv['envId'], $iv['platform'], $iv['cloudLocation']);
                         } else {
                             $usageItemName = $usageItem;
                         }
                         $usageItemDataPoint = $this->getDetailedPointDataArray($iv['id'], $usageItemName, $iv, null, null);
                         $usageItemDataPoint['costPct'] = !empty($usg['cost']) ? round($usageItemDataPoint['cost'] / $usg['cost'] * 100) : 0;
                         $usageItemDataPoint['min'] = $iv['minUsage'];
                         $usageItemDataPoint['max'] = $iv['maxUsage'];
                         $usageItemDataPoint['avg'] = !empty($iv['workingHours']) ? round($iv['usageHours'] / $iv['workingHours']) : 0;
                         $usageItemDataPoint['hours'] = $iv['usageHours'];
                         $usageItemDataPoint['displayHours'] = $this->getDisplayHours($iv['usageHours']);
                         $usageItemsData[] = $usageItemDataPoint;
                     }
                     $usageTypeDataPoint['usageItems'] = $usageItemsData;
                 }
                 $usageTypesData[] = $usageTypeDataPoint;
             }
             $distrTypesDataPoint['usageTypes'] = $usageTypesData;
             $distrTypes[] = $distrTypesDataPoint;
         }
     }
     return $distrTypes;
 }
Пример #13
0
 /**
  * Returns iterator for current quarter
  *
  * @return Iterator\ChartQuarterlyIterator
  */
 public function getCurrentQuarterIterator()
 {
     $quarters = new Quarters(SettingEntity::getQuarters());
     $currentQuarter = $quarters->getQuarterForDate(new \DateTime('now', new \DateTimeZone('UTC')));
     $currentYear = (new \DateTime('now', new \DateTimeZone('UTC')))->format('Y');
     if ($currentQuarter === 1) {
         $quarter = 4;
         $year = $currentYear - 1;
     } else {
         $quarter = $currentQuarter - 1;
         $year = $currentYear;
     }
     $date = $quarters->getPeriodForQuarter($quarter, $year);
     $iterator = ChartPeriodIterator::create('quarter', $date->start, $date->end, 'UTC');
     return $iterator;
 }
Пример #14
0
 /**
  * Gets detailed top 5 usage by farms for specified project on date
  *
  * @param   string|null $projectId    The identifier of the project
  * @param   string      $platform     The cloud platform
  * @param   string      $mode         The mode
  * @param   string      $date         The UTC date within period ('Y-m-d H:00')
  * @param   string      $start        The start date of the period in UTC ('Y-m-d')
  * @param   string      $end          The end date of the period in UTC ('Y-m-d')
  * @param   string      $ccId         optional The identifier of the cost center (It is used only when project is null)
  * @return  array       Returns detailed top 5 usage by farms for specified project on date
  * @throws  AnalyticsException
  * @throws  OutOfBoundsException
  */
 public function getProjectFarmsTopUsageOnDate($projectId, $platform, $mode, $date, $start, $end, $ccId = null)
 {
     $projectId = empty($projectId) ? null : $projectId;
     $iterator = new ChartPeriodIterator($mode, $start, $end ?: null, 'UTC');
     //Interval which is used in the database query for grouping
     $queryInterval = preg_replace('/^1 /', '', $iterator->getInterval());
     if ($projectId !== null) {
         $project = ProjectEntity::findPk($projectId);
         if ($project === null) {
             if (empty($ccId)) {
                 throw new AnalyticsException(sprintf("Project %s does not exist. Please provide ccId.", $projectId));
             }
         } else {
             $ccId = $project->ccId;
         }
     }
     //Requests data for the specified period
     $rawUsage = $this->get(['projectId' => $projectId], $iterator->getStart(), $iterator->getEnd(), [$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);
     //We do not need to calculate the percentage here
     $usg = (new AggregationCollection(['period', 'platform', 'farmId' => ['envId']], ['cost' => 'sum']))->load($rawUsage);
     $prevUsg = (new AggregationCollection(['period', 'platform', 'farmId'], ['cost' => 'sum']))->load($rawPrevUsage)->calculatePercentage();
     //Previous chart point
     $prevcp = null;
     //Finds the key for current label
     foreach ($iterator as $chartPoint) {
         //FIXME rewrite search a point
         if ($chartPoint->dt->format('Y-m-d H:00') !== $date) {
             $prevcp = $chartPoint;
             continue;
         }
         $cp = $chartPoint;
         break;
     }
     if (!isset($cp)) {
         throw new OutOfRangeException(sprintf('Requested date (%s) is out of the range. Last point date is %s', $date, isset($prevcp->dt) ? $prevcp->dt->format('Y-m-d H:00') : 'undefined'));
     }
     $result = [];
     //Maximum number of the farms without grouping
     $max = 5;
     $sEverything = self::EVERYTHING_ELSE;
     if (!empty($usg['data'][$cp->key]['data'][$platform]['data'])) {
         $usgFarms = new AggregationCollection(['farmId' => ['envId']], ['cost' => 'sum']);
         $ptr = $usg['data'][$cp->key]['data'][$platform]['data'];
         uasort($ptr, function ($a, $b) {
             if ($a['cost'] == $b['cost']) {
                 return 0;
             }
             return $a['cost'] > $b['cost'] ? -1 : 1;
         });
         //Aggregates farms if its number more then max + 1
         if (count($ptr) > $max + 1) {
             $this->otherFarmsQuantity = count($ptr) - $max;
             $new = [];
             $i = 0;
             foreach ($ptr as $farmId => $v) {
                 $v['cost_percentage'] = round($usg['data'][$cp->key]['data'][$platform]['cost'] == 0 ? 0 : $v['cost'] * 100 / $usg['data'][$cp->key]['data'][$platform]['cost'], 0);
                 if ($i < $max) {
                     $new[$farmId] = $v;
                 } elseif (!isset($new[self::EVERYTHING_ELSE])) {
                     $v['id'] = self::EVERYTHING_ELSE;
                     $new[self::EVERYTHING_ELSE] = $v;
                 } else {
                     $new[self::EVERYTHING_ELSE]['cost'] += $v['cost'];
                 }
                 $i++;
             }
             $new[self::EVERYTHING_ELSE]['cost_percentage'] = round($usg['data'][$cp->key]['data'][$platform]['cost'] == 0 ? 0 : $new[self::EVERYTHING_ELSE]['cost'] * 100 / $usg['data'][$cp->key]['data'][$platform]['cost'], 0);
             $usgFarms->setArray(['data' => $new]);
         } else {
             $usgFarms->setArray($usg['data'][$cp->key]['data'][$platform])->calculatePercentage();
         }
         //Forms result data array
         foreach ($usgFarms->getIterator() as $farmId => $pv) {
             $record = $this->getDetailedPointDataArray($farmId, $this->fetchFarmName($farmId), $pv, isset($prevUsg['data'][$cp->previousPeriodKey]['data'][$platform]['data'][$farmId]) ? $prevUsg['data'][$cp->previousPeriodKey]['data'][$platform]['data'][$farmId] : null, isset($usg['data'][$cp->key]['data'][$platform]['data'][$farmId]) ? $usg['data'][$cp->key]['data'][$platform]['data'][$farmId] : null);
             if ($farmId && $farmId != self::EVERYTHING_ELSE && !empty($pv['envId'])) {
                 $record['environment'] = ['id' => (int) $pv['envId'], 'name' => AccountTagEntity::fetchName($pv['envId'], TagEntity::TAG_ID_ENVIRONMENT)];
             }
             $result[] = $record;
         }
     }
     return ['data' => $result];
 }
Пример #15
0
 /**
  * Gets a list of projects by key
  *
  * @param string $query Search query
  * @return array Returns array of projects
  */
 private function getProjectsList($query = null)
 {
     $projects = [];
     $collection = $this->getContainer()->analytics->projects->findByKey($query, ['accountId' => $this->user->getAccountId()], true);
     //Select identifiers of all projects assigned to farms from the account
     $assignedProjects = [];
     $rs = $this->db->Execute("\n            SELECT DISTINCT fs.value\n            FROM farms f\n            JOIN farm_settings fs ON f.id = fs.farmid\n            WHERE fs.name = ?\n            AND f.clientid = ?\n        ", [Entity\FarmSetting::PROJECT_ID, $this->user->getAccountId()]);
     while ($rec = $rs->fetchRow()) {
         $assignedProjects[$rec['value']] = true;
     }
     //Adjusts missing projects.
     //This is going to be very rare event.
     foreach ($collection as $projectEntity) {
         if (isset($assignedProjects[$projectEntity->projectId])) {
             unset($assignedProjects[$projectEntity->projectId]);
         }
     }
     foreach ($assignedProjects as $projectId => $v) {
         $project = ProjectEntity::findPk($projectId);
         /* @var $project ProjectEntity */
         $projectBillingCode = $project->getProperty(ProjectPropertyEntity::NAME_BILLING_CODE);
         if (empty($query) || (stripos($project->name, $query) !== false || stripos($projectBillingCode, $query) !== false)) {
             $collection->append($project);
         }
     }
     if ($collection->count()) {
         $iterator = ChartPeriodIterator::create('month', gmdate('Y-m-01'), null, 'UTC');
         //It calculates usage for all provided cost centres
         $usage = $this->getContainer()->analytics->usage->getFarmData($this->user->getAccountId(), [], $iterator->getStart(), $iterator->getEnd(), [TagEntity::TAG_ID_PROJECT]);
         //It calculates usage for previous period same days
         $prevusage = $this->getContainer()->analytics->usage->getFarmData($this->user->getAccountId(), [], $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [TagEntity::TAG_ID_PROJECT]);
         foreach ($collection as $projectEntity) {
             /* @var $projectEntity \Scalr\Stats\CostAnalytics\Entity\ProjectEntity */
             $totalCost = round(isset($usage['data'][$projectEntity->projectId]) ? $usage['data'][$projectEntity->projectId]['cost'] : 0, 2);
             //Archived projects are excluded only when there aren't any usage for this month and
             //query filter key has not been provided.
             if (($query === null || $query === '') && $projectEntity->archived && $totalCost < 0.01) {
                 continue;
             }
             $projects[$projectEntity->projectId] = $this->getProjectData($projectEntity);
             $prevCost = round(isset($prevusage['data'][$projectEntity->projectId]) ? $prevusage['data'][$projectEntity->projectId]['cost'] : 0, 2);
             $projects[$projectEntity->projectId] = $this->getWrappedUsageData(['projectId' => $projectEntity->projectId, 'iterator' => $iterator, 'usage' => $totalCost, 'prevusage' => $prevCost]) + $projects[$projectEntity->projectId];
         }
     }
     return array_values($projects);
 }
Пример #16
0
 /**
  * Gets cost centre properties and parameters
  *
  * @param   CostCentreEntity $cc          Cost centre entity
  * @param   string           $calculate   optional Whether response should be adjusted with cost usage data
  * @return  array Returns cost centre properties and parameters
  */
 private function getCostCenterData(CostCentreEntity $cc, $calculate = false)
 {
     $ret = array('ccId' => $cc->ccId, 'name' => $cc->name, 'billingCode' => $cc->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE), 'description' => $cc->getProperty(CostCentrePropertyEntity::NAME_DESCRIPTION), 'leadEmail' => $cc->getProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL), 'locked' => $cc->getProperty(CostCentrePropertyEntity::NAME_LOCKED) ? 1 : 0, 'created' => $cc->created->format('Y-m-d'), 'createdByEmail' => $cc->createdByEmail, 'archived' => $cc->archived, 'envCount' => count($cc->getEnvironmentsList()), 'projectsCount' => count($cc->getProjects()));
     if ($calculate) {
         $iterator = ChartPeriodIterator::create('month', gmdate('Y-m-01'), null, 'UTC');
         $usage = $this->getContainer()->analytics->usage->get(['ccId' => $cc->ccId], $iterator->getStart(), $iterator->getEnd());
         //It calculates usage for previous period same days
         $prevusage = $this->getContainer()->analytics->usage->get(['ccId' => $cc->ccId], $iterator->getPreviousStart(), $iterator->getPreviousEnd());
         $ret = $this->getWrappedUsageData(['ccId' => $cc->ccId, 'iterator' => $iterator, 'usage' => $usage['cost'], 'prevusage' => $prevusage['cost']]) + $ret;
     }
     return $ret;
 }
Пример #17
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;
 }