mirror of
https://github.com/stylersnico/librenms.git
synced 2026-07-28 00:24:21 +02:00
Added query method for Http adapter
This commit is contained in:
@@ -43,6 +43,51 @@ Actually we using Guzzle as HTTP client
|
||||
$influx->mark("tcp.test", ["mark" => "element"]);
|
||||
```
|
||||
|
||||
## Query InfluxDB
|
||||
|
||||
You can query the time series database using the query method.
|
||||
|
||||
```php
|
||||
$influx->query("select * from mine");
|
||||
$influx->query("select * from mine", "s"); // with time_precision
|
||||
```
|
||||
|
||||
You can query the database only if the adapter is queryable (implements `QueryableInterface`),
|
||||
actually `GuzzleAdapter`.
|
||||
|
||||
The adapter returns the json decoded body of the InfluxDB response, something like:
|
||||
|
||||
```
|
||||
array(1) {
|
||||
[0] =>
|
||||
class stdClass#1 (3) {
|
||||
public $name =>
|
||||
string(8) "tcp.test"
|
||||
public $columns =>
|
||||
array(3) {
|
||||
[0] =>
|
||||
string(4) "time"
|
||||
[1] =>
|
||||
string(15) "sequence_number"
|
||||
[2] =>
|
||||
string(4) "mark"
|
||||
}
|
||||
public $points =>
|
||||
array(1) {
|
||||
[0] =>
|
||||
array(3) {
|
||||
[0] =>
|
||||
int(1410545635590)
|
||||
[1] =>
|
||||
int(2390001)
|
||||
[2] =>
|
||||
string(7) "element"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Prepare lib dependencies
|
||||
|
||||
Use your DiC or Service Locator in order to provide a configured client
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
],
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"InfluxDB": ["./src/", "./tests"]
|
||||
"InfluxDB\\": ["./src/", "./tests"]
|
||||
}
|
||||
},
|
||||
"suggests": {
|
||||
|
||||
@@ -11,7 +11,9 @@ class GuzzleAdapterSpec extends ObjectBehavior
|
||||
{
|
||||
function let(Client $client, Options $options)
|
||||
{
|
||||
$options->getTcpEndpoint()->willReturn("localhost");
|
||||
$options->getHttpSeriesEndpoint()->willReturn("localhost");
|
||||
$options->getUsername()->willReturn("one");
|
||||
$options->getPassword()->willReturn("two");
|
||||
$this->beConstructedWith($client, $options);
|
||||
}
|
||||
|
||||
@@ -22,8 +24,23 @@ class GuzzleAdapterSpec extends ObjectBehavior
|
||||
|
||||
function it_should_send_data_via_post(Client $client, Options $options)
|
||||
{
|
||||
$client->post("localhost", ['body' => json_encode(['pippo'])])->shouldBeCalledTimes(1);
|
||||
$client->post("localhost", [
|
||||
'auth' => ["one", "two"],
|
||||
'body' => json_encode(['pippo'])
|
||||
])->shouldBeCalledTimes(1);
|
||||
|
||||
$this->send(["pippo"]);
|
||||
}
|
||||
|
||||
function it_should_query_data(Client $client, Options $options)
|
||||
{
|
||||
$client->get("select * from tcp.test", [])->willReturn([]);
|
||||
$this->query("select * from tcp.test")->shouldReturn([]);
|
||||
}
|
||||
|
||||
function it_should_query_data_with_time_precision(Client $client, Options $options)
|
||||
{
|
||||
$client->get("select * from tcp.test", ["time_precision" => "s"])->willReturn([]);
|
||||
$this->query("select * from tcp.test", "s")->shouldReturn([]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace spec\InfluxDB;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Prophecy\Argument;
|
||||
use InfluxDB\Adapter\GuzzleAdapter;
|
||||
use InfluxDB\Adapter\UdpAdapter;
|
||||
|
||||
class ClientSpec extends ObjectBehavior
|
||||
{
|
||||
@@ -31,4 +33,35 @@ class ClientSpec extends ObjectBehavior
|
||||
"title" => "Autogrill"
|
||||
]);
|
||||
}
|
||||
|
||||
function it_should_query_on_querable_adapter(GuzzleAdapter $adapter)
|
||||
{
|
||||
$this->setAdapter($adapter);
|
||||
$adapter->query("select * from tcp.test", false)->willReturn([]);
|
||||
|
||||
$this->query("select * from tcp.test")->shouldReturn([]);
|
||||
}
|
||||
|
||||
function it_should_query_with_time_precision(GuzzleAdapter $adapter)
|
||||
{
|
||||
$this->setAdapter($adapter);
|
||||
$adapter->query("select * from tcp.test", "s")->willReturn([]);
|
||||
|
||||
$this->query("select * from tcp.test", "s")->shouldReturn([]);
|
||||
}
|
||||
|
||||
function it_should_query_but_skip_invalid_time_precision(GuzzleAdapter $adapter)
|
||||
{
|
||||
$this->setAdapter($adapter);
|
||||
$adapter->query("select * from tcp.test", false)->willReturn([]);
|
||||
|
||||
$this->query("select * from tcp.test", "r")->shouldReturn([]);
|
||||
}
|
||||
|
||||
function it_should_thrown_an_exception_on_unquerable_adapter(UdpAdapter $adapter)
|
||||
{
|
||||
$this->setAdapter($adapter);
|
||||
|
||||
$this->shouldThrow("\\BadMethodCallException")->duringQuery("select * from tcp.test");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ class OptionsSpec extends ObjectBehavior
|
||||
function it_should_create_a_valid_tcp_endpoint()
|
||||
{
|
||||
$this->setDatabase("mine");
|
||||
$this->getTcpEndpoint()
|
||||
->shouldReturn("http://localhost:8086/db/mine/series?u=root&p=root");
|
||||
$this->getHttpSeriesEndpoint()
|
||||
->shouldReturn("http://localhost:8086/db/mine/series");
|
||||
}
|
||||
|
||||
function it_should_allows_option_override_for_tcp_endpoint()
|
||||
@@ -26,15 +26,15 @@ class OptionsSpec extends ObjectBehavior
|
||||
$this->setUsername("walter");
|
||||
$this->setPassword("walter");
|
||||
$this->setDatabase("me");
|
||||
$this->getTcpEndpoint()
|
||||
->shouldReturn("http://influx.1.prod.tld:19385/db/me/series?u=walter&p=walter");
|
||||
$this->getHttpSeriesEndpoint()
|
||||
->shouldReturn("http://influx.1.prod.tld:19385/db/me/series");
|
||||
}
|
||||
|
||||
function it_should_allows_https_for_tcp_endpoint()
|
||||
{
|
||||
$this->setProtocol("https");
|
||||
$this->setDatabase("me");
|
||||
$this->getTcpEndpoint()
|
||||
->shouldReturn("https://localhost:8086/db/me/series?u=root&p=root");
|
||||
$this->getHttpSeriesEndpoint()
|
||||
->shouldReturn("https://localhost:8086/db/me/series");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace InfluxDB\Adapter;
|
||||
use GuzzleHttp\Client;
|
||||
use InfluxDB\Options;
|
||||
|
||||
class GuzzleAdapter implements AdapterInterface
|
||||
class GuzzleAdapter implements AdapterInterface, QueryableInterface
|
||||
{
|
||||
private $httpClient;
|
||||
private $options;
|
||||
@@ -20,10 +20,27 @@ class GuzzleAdapter implements AdapterInterface
|
||||
public function send($message)
|
||||
{
|
||||
$httpMessage = [
|
||||
"auth" => [$this->options->getUsername(), $this->options->getPassword()],
|
||||
"body" => json_encode($message)
|
||||
];
|
||||
$endpoint = $this->options->getTcpEndpoint();
|
||||
$endpoint = $this->options->getHttpSeriesEndpoint();
|
||||
|
||||
$this->httpClient->post($endpoint, $httpMessage);
|
||||
return $this->httpClient->post($endpoint, $httpMessage);
|
||||
}
|
||||
|
||||
public function query($query, $timePrecision = false)
|
||||
{
|
||||
$options = [
|
||||
"auth" => [$this->options->getUsername(), $this->options->getPassword()],
|
||||
'query' => [
|
||||
"q" => $query,
|
||||
]
|
||||
];
|
||||
if ($timePrecision) {
|
||||
$options["query"]["time_precision"] = $timePrecision;
|
||||
}
|
||||
|
||||
$endpoint = $this->options->getHttpSeriesEndpoint();
|
||||
return $this->httpClient->get($endpoint, $options)->json();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace InfluxDb\Adapter;
|
||||
|
||||
interface QueryableInterface
|
||||
{
|
||||
public function query($query, $timePrecision = false);
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace InfluxDB;
|
||||
|
||||
use InfluxDb\Adapter\QueryableInterface;
|
||||
|
||||
class Client
|
||||
{
|
||||
private $adapter;
|
||||
@@ -36,4 +38,29 @@ class Client
|
||||
|
||||
return $this->getAdapter()->send([$data]);
|
||||
}
|
||||
|
||||
public function query($query, $timePrecision = false)
|
||||
{
|
||||
if (!($this->getAdapter() instanceOf QueryableInterface)) {
|
||||
throw new \BadMethodCallException("You can query the database only if the adapter supports it!");
|
||||
}
|
||||
|
||||
$timePrecision = $this->clearTimePrecision($timePrecision);
|
||||
|
||||
return $this->getAdapter()->query($query, $timePrecision);
|
||||
}
|
||||
|
||||
private function clearTimePrecision($timePrecision)
|
||||
{
|
||||
switch ($timePrecision) {
|
||||
case 's':
|
||||
case 'u':
|
||||
case 'ms':
|
||||
break;
|
||||
default:
|
||||
$timePrecision = false;
|
||||
}
|
||||
|
||||
return $timePrecision;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,16 +87,14 @@ class Options
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTcpEndpoint()
|
||||
public function getHttpSeriesEndpoint()
|
||||
{
|
||||
return sprintf(
|
||||
"%s://%s:%d/db/%s/series?u=%s&p=%s",
|
||||
"%s://%s:%d/db/%s/series",
|
||||
$this->getProtocol(),
|
||||
$this->getHost(),
|
||||
$this->getPort(),
|
||||
$this->getDatabase(),
|
||||
$this->getUsername(),
|
||||
$this->getPassword()
|
||||
$this->getDatabase()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||
public function setUp()
|
||||
{
|
||||
$options = include __DIR__ . '/../bootstrap.php';
|
||||
$this->options = $options;
|
||||
|
||||
$this->object = new Client();
|
||||
|
||||
$client = new Crodas(
|
||||
$options["tcp"]["host"],
|
||||
@@ -34,11 +31,8 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||
$client->createDatabase($options["tcp"]["database"]);
|
||||
|
||||
$this->anotherClient = $client;
|
||||
}
|
||||
|
||||
public function testGuzzleHttpApiWorksCorrectly()
|
||||
{
|
||||
$tcpOptions = $this->options["tcp"];
|
||||
$tcpOptions = $options["tcp"];
|
||||
|
||||
$options = new Options();
|
||||
$options->setHost($tcpOptions["host"]);
|
||||
@@ -47,17 +41,56 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||
$options->setPassword($tcpOptions["password"]);
|
||||
$options->setDatabase($tcpOptions["database"]);
|
||||
|
||||
$this->options = $options;
|
||||
|
||||
$guzzleHttp = new GuzzleHttpClient();
|
||||
$adapter = new InfluxHttpAdapter($guzzleHttp, $options);
|
||||
|
||||
$influx = new Client();
|
||||
$influx->setAdapter($adapter);
|
||||
$this->object = $influx;
|
||||
}
|
||||
|
||||
$influx->mark("tcp.test", ["mark" => "element"]);
|
||||
public function testGuzzleHttpApiWorksCorrectly()
|
||||
{
|
||||
$this->object->mark("tcp.test", ["mark" => "element"]);
|
||||
|
||||
$cursor = $this->anotherClient->getDatabase($tcpOptions["database"])
|
||||
$cursor = $this->anotherClient->getDatabase($this->options->getDatabase())
|
||||
->query("select * from tcp.test");
|
||||
$this->assertCount(1, $cursor);
|
||||
$this->assertEquals("element", $cursor[0]->mark);
|
||||
}
|
||||
|
||||
public function testGuzzleHttpQueryApiWorksCorrectly()
|
||||
{
|
||||
$this->object->mark("tcp.test", ["mark" => "element"]);
|
||||
|
||||
$body = $this->object->query("select * from tcp.test");
|
||||
|
||||
$this->assertCount(1, $body);
|
||||
$this->assertEquals("tcp.test", $body[0]["name"]);
|
||||
$this->assertEquals("element", $body[0]["points"][0][2]);
|
||||
}
|
||||
|
||||
public function testGuzzleHttpQueryApiWithMultipleData()
|
||||
{
|
||||
$this->object->mark("tcp.test", ["mark" => "element"]);
|
||||
$this->object->mark("tcp.test", ["mark" => "element2"]);
|
||||
$this->object->mark("tcp.test", ["mark" => "element3"]);
|
||||
|
||||
$body = $this->object->query("select mark from tcp.test", "s");
|
||||
|
||||
$this->assertCount(3, $body[0]["points"]);
|
||||
$this->assertEquals("tcp.test", $body[0]["name"]);
|
||||
}
|
||||
|
||||
public function testGuzzleHttpQueryApiWithTimePrecision()
|
||||
{
|
||||
$this->object->mark("tcp.test", ["mark" => "element"]);
|
||||
|
||||
$body = $this->object->query("select mark from tcp.test", "s");
|
||||
|
||||
$this->assertCount(1, $body[0]["points"]);
|
||||
$this->assertEquals("tcp.test", $body[0]["name"]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user