Merge pull request #435 from cytopia/redis-ui

Bugfixes: PHP-xdebug, Redis UI and Memcached UI
This commit is contained in:
cytopia 2018-12-15 20:51:05 +01:00 committed by GitHub
commit 9efc68b62d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 237 additions and 100 deletions

View File

@ -14,7 +14,7 @@ putenv('RES_OPTIONS=retrans:1 retry:1 timeout:1 attempts:1');
$DEVILBOX_VERSION = 'v0.15';
$DEVILBOX_DATE = '2018-11-03';
$DEVILBOX_DATE = '2018-12-15';
$DEVILBOX_API_PAGE = 'devilbox-api/status.json';
//

View File

@ -25,6 +25,8 @@
<thead class="thead-inverse ">
<tr>
<th>Key</th>
<th>Size</th>
<th>TTL</th>
<th>Value</th>
</th>
</thead>
@ -32,7 +34,9 @@
<?php foreach (loadClass('Memcd')->getKeys() as $data): ?>
<tr>
<td><?php print_r($data['key']);?></td>
<td><?php print_r($data['value']);?></td>
<td><?php print_r($data['size']);?></td>
<td><?php print_r($data['ttl']);?></td>
<td><?php print_r($data['val']);?></td>
</tr>
<?php endforeach; ?>
</tbody>

View File

@ -1,5 +1,12 @@
<?php require '../config.php'; ?>
<?php loadClass('Helper')->authPage(); ?>
<?php
if (isset($_GET['redisdb'])) {
loadClass('Redis')->flushDB($_GET['redisdb']);
loadClass('Helper')->redirect('/db_redis.php');
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
@ -15,6 +22,27 @@
<br/>
<br/>
<?php $databases = array_keys(loadClass('Redis')->getKeys()); ?>
<?php if (count($databases)): ?>
<div class="row">
<div class="col-md-12">
<form class="form-inline">
<div class="form-group">
<label class="sr-only" for="redisdb">Redis DB</label>
<select class="form-control" name="redisdb">
<option value="" selected disabled>Select Redis DB</option>
<?php foreach ($databases as $db): ?>
<option value="<?php echo $db;?>"><?php echo $db;?></option>
<?php endforeach; ?>
</select>
</div>&nbsp;&nbsp;
<button type="submit" class="btn btn-primary">Flush database</button>
</form>
<br/>
</div>
</div>
<?php endif; ?>
<div class="row">
<div class="col-md-12">
@ -22,29 +50,43 @@
<p>Redis container is not running.</p>
<?php else: ?>
<table class="table table-striped ">
<thead class="thead-inverse ">
<tr>
<th>DB</th>
<th>Key</th>
<th>Value</th>
</th>
</thead>
<tbody>
<?php foreach (loadClass('Redis')->getKeys() as $db_name => $keys): ?>
<tr class="table-info">
<th colspan="3">
<?php echo $db_name;?>
<?php $redisKeys = loadClass('Redis')->getKeys(); ?>
<?php if (count($redisKeys)): ?>
<?php foreach ($redisKeys as $db_name => $keys): ?>
<tr class="thead-inverse ">
<th colspan="5">
Database: <?php echo $db_name; ?>&nbsp;&nbsp;&nbsp;&nbsp;
Items: <?php echo count($keys); ?>
</th>
</th>
</tr>
<?php foreach ($keys as $key=> $val): ?>
<tr>
<td></td>
<td><?php echo $key;?></td>
<td><code><?php print_r($val);?></code></td>
<tr class="table-info">
<tr>
<th>DB</th>
<th>Key</th>
<th>Expires</th>
<th>Type</th>
<th>Value</th>
</th>
</tr>
<?php endforeach; ?>
<?php foreach ($keys as $key): ?>
<tr>
<td><?php echo $db_name;?></td>
<td class="break-word" style="width:30%;"><?php echo $key['name'];?></td>
<td><?php echo $key['ttl'];?>s</td>
<td><?php echo $key['type'];?></td>
<td class="break-word">
<code>
<?php echo htmlentities($key['val']);?>
</code>
</td>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
<?php endforeach; ?>
<?php else: ?>
<p>No keys set.</p>
<?php endif; ?>
</tbody>
</table>
<?php endif; ?>

View File

@ -43,7 +43,7 @@ class Memcd extends BaseClass implements BaseInterface
if (empty($list)) {
$memcd->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$memcd->setOption(\Memcached::OPT_BINARY_PROTOCOL, false);
$memcd->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
$memcd->addServer($hostname, 11211);
}
@ -67,13 +67,15 @@ class Memcd extends BaseClass implements BaseInterface
$this->_connect_errno = 3;
return;
}
$memcd->set('devilbox-version', $GLOBALS['DEVILBOX_VERSION'].' ('.$GLOBALS['DEVILBOX_DATE'].')');
$memcd->getDelayed(array('devilbox-version'));
if (!$memcd->fetchAll()) {
$memcd->set('devilbox-version', $GLOBALS['DEVILBOX_VERSION'].' ('.$GLOBALS['DEVILBOX_DATE'].')');
}
$this->_memcached = $memcd;
} else {
$ret = 0;
loadClass('Helper')->exec('echo "stats" | nc 127.0.0.1 11211', $ret);
loadClass('Helper')->exec('printf "stats\nquit\n" | nc '.$hostname.' 11211', $ret);
if ($ret == 0) {
$this->_memcached = true;
}
@ -104,16 +106,55 @@ class Memcd extends BaseClass implements BaseInterface
public function getKeys()
{
$store = array();
// CLI seems to only sometimes get the results, so we will just loop a bit
// It's a very quick operation anyway.
$cli_retries = 100;
// Memcached >= 1.5
for ($i=0; $i<$cli_retries; $i++) {
$output = array();
exec('printf "stats cachedump 1 0\nquit\n" | nc memcd 11211 | grep -E \'^ITEM\'', $output);
foreach ($output as $line) {
$matches = array();
preg_match('/(^ITEM)\s*(.+?)\s*\[([0-9]+\s*b);\s*([0-9]+\s*s)\s*\]/', $line, $matches);
$key = $matches[2];
$store[] = array(
'key' => $key,
'val' => $this->_memcached->get($key),
'ttl' => $matches[4],
'size' => $matches[3],
);
}
// If we actually got a result, we can break here
if (count($store)) {
return $store;
}
}
// This will only work for Memcached < 1.5
if (class_exists('Memcached')) {
if ($this->_memcached) {
// Ensure we retrieve data not in binary
$this->_memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, false);
if (!($keys = $this->_memcached->getAllKeys())) {
$keys = array();
}
$this->_memcached->getDelayed($keys);
$store = $this->_memcached->fetchAll();
if (!is_array($store)) {
$store = array();
$this->_memcached->getDelayed($keys, true);
$data = $this->_memcached->fetchAll();
if (is_array($data)) {
for ($i=0; $size=count($data), $i<$size; $i++) {
$store[$i]['key'] = $data[$i]['key'];
$store[$i]['val'] = $data[$i]['value'];
$store[$i]['ttl'] = '?';
$store[$i]['size'] = strlen($data[$i]['value']);
}
}
// Revert Memcachd protocol
$this->_memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
}
}
return $store;
@ -128,14 +169,14 @@ class Memcd extends BaseClass implements BaseInterface
}
} else {
$ret = 0;
$output = loadClass('Helper')->exec('echo "stats" | nc 127.0.0.1 11211 | sed "s/^STAT[[:space:]]*//g" | grep -v "END"', $ret);
$output = loadClass('Helper')->exec('printf "stats\nquit\n" | nc memcd 11211 | sed "s/^STAT[[:space:]]*//g" | grep -v "END"', $ret);
if ($ret == 0) {
$output = explode("\n", $output);
foreach ($output as $line) {
$tmp = explode(' ', $line);
$key = isset($tmp[0]) ? $tmp[0] : '';
$val = isset($tmp[1]) ? $tmp[1] : '';
$stats['127.0.0.1'][$key] = $val;
$stats['memcd'][$key] = $val;
}
}
}
@ -167,51 +208,13 @@ class Memcd extends BaseClass implements BaseInterface
return $this->_can_connect[$hostname];
}
if (class_exists('Memcached')) {
// Silence errors and try to connect
//error_reporting(-1);
$memcd = new \Memcached();
$memcd->resetServerList();
if (!$memcd->addServer($hostname, 11211)) {
$memcd->quit();
$err = 'Failed to connect to Memcached host on '.$hostname;
$this->_can_connect[$hostname] = false;
$this->_can_connect_err[$hostname] = $err;
return false;
}
$stats = $memcd->getStats();
if (!isset($stats[$hostname.':11211'])) {
$err = 'Failed to connect to Memcached host on '.$hostname;
$this->_can_connect[$hostname] = false;
}
else if (!isset($stats[$hostname.':11211']['pid'])) {
$err = 'Failed to connect to Memcached host on '.$hostname;
$this->_can_connect[$hostname] = false;
}
else if ($stats[$hostname.':11211']['pid'] < 1) {
$err = 'Failed to connect to Memcached host on '.$hostname;
$this->_can_connect[$hostname] = false;
}
else {
$this->_can_connect[$hostname] = true;
}
$memcd->quit();
$this->_can_connect_err[$hostname] = $err;
$ret = 0;
loadClass('Helper')->exec('printf "stats\nquit\n" | nc '.$hostname.' 11211', $ret);
if ($ret == 0) {
$this->_can_connect[$hostname] = true;
} else {
$ret = 0;
loadClass('Helper')->exec('echo "stats" | nc '.$hostname.' 11211', $ret);
if ($ret == 0) {
$this->_can_connect[$hostname] = true;
} else {
$err = 'Failed to connect to Memcached host on '.$hostname;
$this->_can_connect[$hostname] = false;
}
$err = 'Failed to connect to Memcached host on '.$hostname;
$this->_can_connect[$hostname] = false;
}
return $this->_can_connect[$hostname];
@ -249,7 +252,7 @@ class Memcd extends BaseClass implements BaseInterface
}
}
} else {
$version = loadClass('Helper')->exec('echo "version" | nc 127.0.0.1 11211 | grep -oE "[0-9.-]+"', $ret);
$version = loadClass('Helper')->exec('printf "version\nquit\n" | nc memcd 11211 | grep -oE "[0-9.-]+"', $ret);
$this->_version = $version;
}
return $this->_version;

View File

@ -91,10 +91,9 @@ class Mongo extends BaseClass implements BaseInterface
*/
private function command($command)
{
$cmd = new \MongoDB\Driver\Command($command);
if ($this->_mongo) {
try {
$cmd = new \MongoDB\Driver\Command($command);
$cursor = $this->_mongo->executeCommand('admin', $cmd);
return $cursor->toArray();
} catch(\MongoDB\Driver\Exception $e) {

View File

@ -70,6 +70,17 @@ class Redis extends BaseClass implements BaseInterface
* Select functions
*
*********************************************************************************/
public function flushDB($db)
{
if ($this->_redis) {
if ( !$this->_redis->select($db) ) {
return FALSE;
}
return $this->_redis->flushDb();
} else {
return FALSE;
}
}
public function getInfo()
{
@ -101,7 +112,35 @@ class Redis extends BaseClass implements BaseInterface
$this->_redis->select($db);
$keys = $this->_redis->keys('*');
foreach ($keys as $key) {
$store[$db][$key] = $this->_redis->get($key);
switch($this->_redis->type($key)) {
case \Redis::REDIS_STRING:
$dtype = 'string';
break;
case \Redis::REDIS_SET:
$dtype = 'set';
break;
case \Redis::REDIS_LIST:
$dtype = 'list';
break;
case \Redis::REDIS_ZSET:
$dtype = 'zset';
break;
case \Redis::REDIS_HASH:
$dtype = 'hash';
break;
case \Redis::REDIS_NOT_FOUND:
$dtype = 'other';
break;
default:
$dtype = 'unknown';
}
$store[$db][] = array(
'name' => $key,
'val' => $this->_redis->get($key),
'type' => $dtype,
'ttl' => $this->_redis->ttl($key)
);
}
}
}

View File

@ -17,9 +17,11 @@ printf "[TEST] dvlbox-ok"
TEST_OK="$( curl -sS localhost/index.php | grep -c 'dvlbox-ok' || true )"
if [ "${TEST_OK}" != "${NUM_OK}" ]; then
# 2nd Try
sleep 1
TEST_OK="$( curl -sS localhost/index.php | grep -c 'dvlbox-ok' || true )"
if [ "${TEST_OK}" != "${NUM_OK}" ]; then
# 3rd Try
sleep 1
TEST_OK="$( curl -sS localhost/index.php | grep -c 'dvlbox-ok' || true )"
if [ "${TEST_OK}" != "${NUM_OK}" ]; then
printf "\r[FAIL] dvlbox-ok\n"
@ -45,9 +47,11 @@ printf "[TEST] dvlbox-err"
TEST_ERR="$( curl -sS localhost/index.php | grep -c 'dvlbox-err' || true )"
if [ "${TEST_ERR}" != "${NUM_ERR}" ]; then
# 2nd Try
sleep 1
TEST_ERR="$( curl -sS localhost/index.php | grep -c 'dvlbox-err' || true )"
if [ "${TEST_ERR}" != "${NUM_ERR}" ]; then
# 3rd Try
sleep 1
TEST_ERR="$( curl -sS localhost/index.php | grep -c 'dvlbox-err' || true )"
if [ "${TEST_ERR}" != "${NUM_ERR}" ]; then
printf "\r[FAIL] dvlbox-err\n"

26
.tests/intra-tests/memcached.sh Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
printf "[TEST] devilbox-version key in Memcached"
# 1st Try
if ! curl -sS localhost/db_memcd.php | grep -q 'devilbox-version'; then
sleep 1
if ! curl -sS localhost/db_memcd.php | grep -q 'devilbox-version'; then
sleep 1
if ! curl -sS localhost/db_memcd.php | grep -q 'devilbox-version'; then
printf "\r[FAIL] devilbox-version key in Memcached\n"
curl -sS localhost/db_memcd.php || true
exit 1
else
printf "\r[OK] devilbox-version key in Memcached (3 rounds)\n"
fi
else
printf "\r[OK] devilbox-version key in Memcached (2 rounds)\n"
fi
else
printf "\r[OK] devilbox-version key in Memcached (1 round)\n"
fi

26
.tests/intra-tests/redis.sh Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
printf "[TEST] devilbox-version key in Redis"
# 1st Try
if ! curl -sS localhost/db_redis.php | grep -q 'devilbox-version'; then
sleep 1
if ! curl -sS localhost/db_redis.php | grep -q 'devilbox-version'; then
sleep 1
if ! curl -sS localhost/db_redis.php | grep -q 'devilbox-version'; then
printf "\r[FAIL] devilbox-version key in Redis\n"
curl -sS localhost/db_redis.php || true
exit 1
else
printf "\r[OK] devilbox-version key in Redis (3 rounds)\n"
fi
else
printf "\r[OK] devilbox-version key in Redis (2 rounds)\n"
fi
else
printf "\r[OK] devilbox-version key in Redis (1 round)\n"
fi

View File

@ -124,19 +124,22 @@ env:
### Installation
###
install:
# Update Debian/Ubuntu package index
- if [ "${S1}" != "DOCUMENTATION" ]; then
until sudo apt-get update -qq; do sleep 1; done
fi
# Install dependencies for documentation
- if [ "${S1}" = "DOCUMENTATION" ]; then
max=100; i=0; while [ $i -lt $max ]; do if pip install sphinx; then break; else i=$((i+1)); fi done;
max=100; i=0; while [ $i -lt $max ]; do if pip install sphinx-autobuild; then break; else i=$((i+1)); fi done;
max=100; i=0; while [ $i -lt $max ]; do if pip install recommonmark; then break; else i=$((i+1)); fi done;
max=100; i=0; while [ $i -lt $max ]; do if pip install sphinx_rtd_theme; then break; else i=$((i+1)); fi done;
until pip install sphinx; do sleep 1; done;
until pip install sphinx-autobuild; do sleep 1; done;
until pip install recommonmark; do sleep 1; done;
until pip install sphinx_rtd_theme; do sleep 1; done;
fi
# Determine latest Docker version in apt
- set -e;
DOCKER_APT="";
- DOCKER_APT="";
if [ "${S1}" = "DOCKER" ]; then
max=100; i=0; while [ $i -lt $max ]; do if sudo apt-get update -qq; then break; else i=$((i+1)); fi; done;
DOCKER_APT="$( curl -sS https://raw.githubusercontent.com/cytopia/tools/master/docker-apt-versions | sh -s "${V1}" )";
fi;
if [ -n "${DOCKER_APT}" ]; then
@ -145,8 +148,7 @@ install:
echo "${DOCKER_APT}";
# Determine latest Docker Compose version
- set -e;
if [ "${S2}" = "COMPOSE" ]; then
- if [ "${S2}" = "COMPOSE" ]; then
COMPOSE_VERSION="$( curl -sS https://raw.githubusercontent.com/cytopia/tools/master/docker-compose-versions | sh -s "${V2}" )";
else
COMPOSE_VERSION="$( curl -sS https://raw.githubusercontent.com/cytopia/tools/master/docker-compose-versions | sh -s 1 )";
@ -154,17 +156,9 @@ install:
echo "${COMPOSE_VERSION}";
# Install Docker and Docker Compose
- set -e;
if [ "${S1}" != "DOCUMENTATION" ]; then
max=100; i=0; while [ $i -lt $max ]; do
if sudo apt-get update -qq; then break; else i=$((i+1)); fi;
done;
max=100; i=0; while [ $i -lt $max ]; do
if sudo apt-get -y -qq -o Dpkg::Options::="--force-confnew" install docker-ce${DOCKER_APT}; then break; else i=$((i+1)); fi;
done;
max=100; i=0; while [ $i -lt $max ]; do
if curl -L --retry 100 --retry-max-time 0 https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose; then break; else i=$((i+1)); fi;
done;
- if [ "${S1}" != "DOCUMENTATION" ]; then
until sudo apt-get -y -qq -o Dpkg::Options::="--force-confnew" install docker-ce${DOCKER_APT}; do sleep 1; done;
until curl -L -sS --retry 100 --retry-max-time 0 https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose; do sleep 1; done;
chmod +x docker-compose;
sudo mv -f docker-compose /usr/local/bin;
fi

View File

@ -95,7 +95,7 @@ services:
# PHP / HHVM
# ------------------------------------------------------------
php:
image: devilbox/php-fpm:${PHP_SERVER:-7.2}-work-0.52
image: devilbox/php-fpm:${PHP_SERVER:-7.2}-work-0.54
##
## All .env variables