Skip to content

Commit

Permalink
Merge pull request #73 from JarvusInnovations/develop
Browse files Browse the repository at this point in the history
Release: gatekeeper v2.2.1
  • Loading branch information
themightychris authored Oct 4, 2019
2 parents 624e7b9 + fbb1aff commit e62a686
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 161 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/holo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Projections

on:
push:
tags:
- 'v2.*'


jobs:
holobranch-projections:
runs-on: ubuntu-latest
steps:
- name: 'Update holobranch: emergence/skeleton/v2'
uses: JarvusInnovations/hologit@actions/projector/v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HAB_LICENSE: accept
with:
ref: releases/v2
holobranch: emergence-skeleton
commit-to: emergence/skeleton/v2
- name: 'Update holobranch: emergence/vfs-site/v2'
uses: JarvusInnovations/hologit@actions/projector/v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HAB_LICENSE: accept
with:
ref: releases/v2
holobranch: emergence-vfs-site
commit-to: emergence/vfs-site/v2
7 changes: 7 additions & 0 deletions event-handlers/Gatekeeper/heartbeat/40_flush-metrics.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

printf('Flushing metrics...') && flush();

$flushed = Gatekeeper\Metrics\Metrics::flushMetricSamples();

printf('%u metrics flushed' . PHP_EOL, $flushed);
99 changes: 1 addition & 98 deletions event-handlers/Gatekeeper/heartbeat/50_ping-endpoints.php
Original file line number Diff line number Diff line change
@@ -1,100 +1,3 @@
<?php

namespace Gatekeeper;

use DB;
use HttpProxy;
use Gatekeeper\Alerts\TestFailed;
use Gatekeeper\Endpoints\Endpoint;
use Gatekeeper\Transactions\PingTransaction;


// find all endpoints that are overdue or near due for a ping
$endpoints = Endpoint::getAllByQuery(
'SELECT Endpoint.*'
.' FROM `%s` Endpoint'
.' WHERE'
.' Endpoint.PingFrequency IS NOT NULL AND'
.' IFNULL(('
.' SELECT Created FROM `%s` Transaction WHERE EndpointID = Endpoint.ID AND Class = "%s" ORDER BY ID DESC LIMIT 1'
.' ), 0) < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL (Endpoint.PingFrequency * 0.7) MINUTE)'
,[
Endpoint::$tableName,
PingTransaction::$tableName,
DB::escape(PingTransaction::class)
]
);


// loop through all endpoints to execute, test, and record the ping URI
foreach ($endpoints AS $Endpoint) {
printf('Testing endpoint %s...', $Endpoint->getTitle());

// execute and capture request
// TODO: use curl_multi_exec somehow?
$response = HttpProxy::relayRequest([
'autoAppend' => false,
'autoQuery' => false,
'url' => rtrim($Endpoint->InternalEndpoint, '/') . '/' . ltrim($Endpoint->PingURI, '/'),
'interface' => ApiRequestHandler::$sourceInterface,
'timeout' => 15,
'timeoutConnect' => 5,
'returnResponse' => true
]);


// evaluate success
$testPassed =
$response['info']['http_code'] == 200 &&
(
!$Endpoint->PingTestPattern ||
preg_match($Endpoint->PingTestPattern, $response['body'])
);


// record transaction
list($path, $query) = array_pad(explode('?', $Endpoint->PingURI, 2), 2, null);

$Transaction = PingTransaction::create([
'Endpoint' => $Endpoint,
'ClientIP' => ip2long($response['info']['local_ip']),
'Method' => 'GET',
'Path' => $path,
'Query' => $query,
'ResponseTime' => $response['info']['starttransfer_time'] * 1000,
'ResponseCode' => $response['info']['http_code'],
'ResponseBytes' => $response['info']['size_download'],
'TestPassed' => $testPassed
], true);


// open alert if necessary, or close any existing one
if (!$testPassed) {
TestFailed::open($Endpoint, [
'transactionId' => $Transaction->ID,
'request' => [
'uri' => $Endpoint->PingURI
],
'response' => [
'status' => $Transaction->ResponseCode,
'headers' => $response['headers'],
'body' => $response['body'],
'bytes' => $Transaction->ResponseBytes,
'time' => $Transaction->ResponseTime
]
]);
} else {
$OpenAlert = TestFailed::getByWhere([
'Class' => TestFailed::class,
'EndpointID' => $Endpoint->ID,
'Status' => 'open'
]);

if ($OpenAlert) {
$OpenAlert->Status = 'closed';
$OpenAlert->save();
}
}

printf("%s\n", $testPassed ? 'passed' : 'failed');
}
Gatekeeper\Endpoints\Pinger::pingOverdueEndpoints(true);
114 changes: 114 additions & 0 deletions php-classes/Gatekeeper/Endpoints/Pinger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

namespace Gatekeeper\Endpoints;

use Cache;
use HttpProxy;

use Gatekeeper\ApiRequestHandler;
use Gatekeeper\Alerts\TestFailed;
use Gatekeeper\Transactions\PingTransaction;


class Pinger
{
public static function pingOverdueEndpoints($verbose = false)
{
$endpoints = Endpoint::getAllByWhere('PingFrequency IS NOT NULL');

foreach ($endpoints as $Endpoint) {
$lastPing = Cache::fetch("endpoints/{$Endpoint->ID}/last-ping");

if (
$lastPing === false
|| $Endpoint->PingFrequency < time()-$lastPing['time'] // * 60
) {
static::pingEndpoint($Endpoint, $verbose);
}
}
}

public static function pingEndpoint(Endpoint $Endpoint, $verbose = false)
{
$verbose && printf('Testing endpoint: /%s...', $Endpoint->Path) && flush();


// execute and capture request
// TODO: use curl_multi_exec somehow?
$response = HttpProxy::relayRequest([
'autoAppend' => false,
'autoQuery' => false,
'url' => rtrim($Endpoint->InternalEndpoint, '/') . '/' . ltrim($Endpoint->PingURI, '/'),
'interface' => ApiRequestHandler::$sourceInterface,
'timeout' => 15,
'timeoutConnect' => 5,
'returnResponse' => true
]);


// evaluate success
$testPassed =
$response['info']['http_code'] == 200 &&
(
!$Endpoint->PingTestPattern ||
preg_match($Endpoint->PingTestPattern, $response['body'])
);


// record transaction
list($path, $query) = array_pad(explode('?', $Endpoint->PingURI, 2), 2, null);

$Transaction = PingTransaction::create([
'Endpoint' => $Endpoint,
'ClientIP' => ip2long($response['info']['local_ip']),
'Method' => 'GET',
'Path' => $path,
'Query' => $query,
'ResponseTime' => $response['info']['starttransfer_time'] * 1000,
'ResponseCode' => $response['info']['http_code'],
'ResponseBytes' => $response['info']['size_download'],
'TestPassed' => $testPassed
], true);


// open alert if necessary, or close any existing one
if (!$testPassed) {
TestFailed::open($Endpoint, [
'transactionId' => $Transaction->ID,
'request' => [
'uri' => $Endpoint->PingURI
],
'response' => [
'status' => $Transaction->ResponseCode,
'headers' => $response['headers'],
'body' => $response['body'],
'bytes' => $Transaction->ResponseBytes,
'time' => $Transaction->ResponseTime
]
]);
} else {
$OpenAlert = TestFailed::getByWhere([
'Class' => TestFailed::class,
'EndpointID' => $Endpoint->ID,
'Status' => 'open'
]);

if ($OpenAlert) {
$OpenAlert->Status = 'closed';
$OpenAlert->save();
}
}


$verbose && printf("%s\n", $testPassed ? 'passed' : 'failed') && flush();


// cache result and timestamp
Cache::store("endpoints/{$Endpoint->ID}/last-ping", [
'time' => time(),
'testPassed' => $testPassed
], ($Endpoint->PingFrequency+5)); // * 60

return $testPassed;
}
}
43 changes: 40 additions & 3 deletions php-classes/Gatekeeper/Metrics/Metrics.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public static function estimateAverage($averageKey, $counterKey)

$previousSampleIndex = $currentSampleIndex - 1;
$previousSampleValue = Cache::fetch("metrics/$averageKey/$previousSampleIndex");

if ($currentSampleValue === false && $previousSampleValue === false) {
return null;
} elseif ($currentSampleValue === false) {
Expand All @@ -100,7 +100,7 @@ public static function estimateAverage($averageKey, $counterKey)
} else {
$currentSampleWeight = Cache::fetch("metrics/$counterKey/$currentSampleIndex") * (1 - ($currentSampleSecondsRemaining / static::$sampleDuration));
$previusSampleWeight = Cache::fetch("metrics/$counterKey/$previousSampleIndex") * ($currentSampleSecondsRemaining / static::$sampleDuration);

return round(
(
$currentSampleValue * $currentSampleWeight
Expand All @@ -112,4 +112,41 @@ public static function estimateAverage($averageKey, $counterKey)
);
}
}
}

public static function flushMetricSamples()
{
$cacheKeyPrefix = Cache::getKeyPrefix();
$currentSampleIndex = static::getCurrentSampleIndex();

$flushed = 0;
foreach (Cache::getIterator('|^metrics/|') AS $cacheEntry) {
if (!preg_match('|^'.preg_quote($cacheKeyPrefix).'(metrics/(.*)/(\d+))$|', $cacheEntry['key'], $matches)) {
continue;
}

$cacheKey = $matches[1];
$metricKey = $matches[2];
$sampleIndex = (int)$matches[3];

// skip active and previus samples
if ($sampleIndex >= $currentSampleIndex - 1) {
continue;
}

// delete sample from cache
Cache::delete($cacheKey);

// save metric to DB
$sample = MetricSample::create([
'Timestamp' => $sampleIndex * Metrics::$sampleDuration,
'Key' => $metricKey,
'Value' => $cacheEntry['value']
], true);

// increment counter
$flushed++;
}

return $flushed;
}
}
60 changes: 0 additions & 60 deletions site-root/cron/flush-metrics.php

This file was deleted.

0 comments on commit e62a686

Please sign in to comment.