mirror of
https://github.com/daledavies/jump.git
synced 2026-02-24 07:10:45 +01:00
Add support for auto-discovery of sites from docker
This commit is contained in:
@@ -84,6 +84,31 @@ else
|
||||
sed -E -i 's/^(\s*)#listen \[::\]/\1listen [::]/g' /etc/nginx/nginx.conf
|
||||
fi
|
||||
|
||||
# If we have been passed something in DOCKERSOCKET then check it
|
||||
# was actually mounted and is a socket, if so then create the docker group
|
||||
# with GID matching the docker socket file, then add jumpapp user to the
|
||||
# group. This is to give jumpapp permission to make requests to the API.
|
||||
if [ -n "${DOCKERSOCKET-}" ]; then
|
||||
echo >&2 "";
|
||||
echo >&2 "- Testing docker socket file was mounted correctly."
|
||||
if [ -S "${DOCKERSOCKET}" ]; then
|
||||
DOCKERGID=$(stat -c %g ${DOCKERSOCKET})
|
||||
# Delete existing docker group if it exists.
|
||||
if grep -q "docker" /etc/group; then
|
||||
echo >&2 "-- Deleting existing docker group."
|
||||
delgroup docker
|
||||
fi
|
||||
# Create a new one with correct GID.
|
||||
echo >&2 "-- Creating docker group with correct GID."
|
||||
addgroup -S docker -g $DOCKERGID
|
||||
# Add jumpapp user to it.
|
||||
echo >&2 "-- Adding jumpapp user to docker group."
|
||||
addgroup jumpapp docker
|
||||
else
|
||||
echo >&2 "-- Docker socket file was either not mounted or is not a socket."
|
||||
fi
|
||||
fi
|
||||
|
||||
echo >&2 "";
|
||||
echo >&2 "- All done! Starting nginx/php services now."
|
||||
echo >&2 "";
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
namespace Jump;
|
||||
|
||||
use \divineomega\array_undot;
|
||||
use \Jump\Exceptions\ConfigException;
|
||||
use \Jump\Exceptions\SiteNotFoundException;
|
||||
use \Jump\Exceptions\TagNotFoundException;
|
||||
@@ -26,6 +27,7 @@ class Sites {
|
||||
private array $default;
|
||||
private string $sitesfilelocation;
|
||||
private array $loadedsites;
|
||||
public array $tags;
|
||||
|
||||
/**
|
||||
* Automatically load sites.json on instantiation.
|
||||
@@ -41,10 +43,10 @@ class Sites {
|
||||
'newtab' => false,
|
||||
];
|
||||
|
||||
// Retrieve sites from cache. Load all sites from json file if not cached or
|
||||
// the cache has expired.
|
||||
// Retrieve sites from cache. Load all sites from json file and docker if not
|
||||
// cached or the cache has expired.
|
||||
$this->loadedsites = $this->cache->load(cachename: 'sites', callback: function() {
|
||||
return $this->load_sites_from_json();
|
||||
return array_merge($this->load_sites_from_json(), $this->load_sites_from_docker());
|
||||
});
|
||||
|
||||
// Enumerate a list of unique tags from loaded sites. Again will retrieve from
|
||||
@@ -60,6 +62,80 @@ class Sites {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a list of sites from correctly labelled docker containers.
|
||||
*
|
||||
* Throws an exception if the json response from docker cannot be
|
||||
* decoded.
|
||||
*
|
||||
* @return array Array of Site objects sites identified from docker.
|
||||
* @throws ConfigException If invalid response from docker.
|
||||
*/
|
||||
private function load_sites_from_docker(): array {
|
||||
// Get either dockerproxy or dockersocket config and return early if
|
||||
// neihter have been set.
|
||||
$dockerproxy = $this->config->get('dockerproxyurl');
|
||||
$dockersocket = $this->config->get('dockersocket');
|
||||
if (!$dockerproxy && !$dockersocket) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Determine correct guzzle client and request options to use
|
||||
// for either a docker proxy or connecting directly to the socket,
|
||||
// prefer to use the proxy if both seem to have been given.
|
||||
$clientopts = ['timeout' => 2.0];
|
||||
$requestopts = [];
|
||||
if ($dockerproxy) {
|
||||
$clientopts['base_uri'] = 'http://'.rtrim($dockerproxy, '/');
|
||||
} else if (file_exists($dockersocket)) {
|
||||
$clientopts['base_uri'] = 'http://localhost';
|
||||
$requestopts = [
|
||||
'curl' => [CURLOPT_UNIX_SOCKET_PATH => '/var/run/docker.sock']
|
||||
];
|
||||
}
|
||||
|
||||
// Make a request to docker for all containers.
|
||||
try {
|
||||
$response = (new \GuzzleHttp\Client($clientopts))->request('GET', '/containers/json', $requestopts);
|
||||
} catch (\GuzzleHttp\Exception\ConnectException $e) {
|
||||
throw new ConfigException('Did not get a response from Docker API endpoint');
|
||||
}
|
||||
$containers = json_decode($response->getBody());
|
||||
if (is_null($containers)) {
|
||||
throw new ConfigException('Docker returned an invalid json response for containers');
|
||||
}
|
||||
|
||||
// Build a new array of Site() objects based on labels that have been added to
|
||||
// containers returned by docker.
|
||||
$sites = [];
|
||||
foreach ($containers as $container) {
|
||||
$labels = (array) $container->Labels;
|
||||
// We can't build a Site() without at least a name and url.
|
||||
if (!isset($labels['jump.name'], $labels['jump.url'])) {
|
||||
continue;
|
||||
}
|
||||
// Convert dot-syntax labels into a proper multidimensional array
|
||||
// and just use the top-level key "jump" as our site array.
|
||||
$site = array_undot($labels)['jump'];
|
||||
// jump.tags will have been given as a comma separated string so make this
|
||||
// into an array.
|
||||
if (isset($site['tags'])) {
|
||||
// Explode the comma separated string into an array and trim any elements.
|
||||
$site['tags'] = array_map('trim', explode(',', $site['tags']));
|
||||
}
|
||||
// Convert status array to an object and also explode list of allowed status codes to array.
|
||||
if (isset($site['status'])) {
|
||||
$site['status'] = (object) $site['status'];
|
||||
if (isset($site['status']->allowed_status_codes)) {
|
||||
$site['status']->allowed_status_codes = array_map('trim', explode(',', $site['status']->allowed_status_codes));
|
||||
}
|
||||
}
|
||||
// Finally add this to the list of sites we will return.
|
||||
$sites[] = new Site($this->config, (array) $site, $this->default);
|
||||
}
|
||||
return $sites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to load the list of sites from sites.json.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"phlak/config": "^7.0",
|
||||
"nette/http": "^3.1",
|
||||
"guzzlehttp/guzzle": "^7.0",
|
||||
"unsplash/unsplash": "3.2.1"
|
||||
"unsplash/unsplash": "3.2.1",
|
||||
"divineomega/array_undot": "^4.1"
|
||||
}
|
||||
}
|
||||
|
||||
46
jumpapp/composer.lock
generated
46
jumpapp/composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "e91bcdf01a945f46bf29aa3a1cef02f5",
|
||||
"content-hash": "8849ca2f3c80ed00c98055bf630ba1fb",
|
||||
"packages": [
|
||||
{
|
||||
"name": "arthurhoaro/favicon",
|
||||
@@ -64,6 +64,50 @@
|
||||
},
|
||||
"time": "2021-08-06T05:41:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "divineomega/array_undot",
|
||||
"version": "v4.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/DivineOmega/array_undot.git",
|
||||
"reference": "44aed525e775718e3821d670b08046fd84914d10"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/DivineOmega/array_undot/zipball/44aed525e775718e3821d670b08046fd84914d10",
|
||||
"reference": "44aed525e775718e3821d670b08046fd84914d10",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "^2.1",
|
||||
"phpunit/phpunit": "^7.0 || ^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/array_undot.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"DivineOmega\\ArrayUndot\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-3.0-only"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordan Hall",
|
||||
"email": "jordan@hall05.co.uk"
|
||||
}
|
||||
],
|
||||
"description": "array_undot (the opposite of the array_dot helper function) expands a dot notation array into a full multi-dimensional array.",
|
||||
"support": {
|
||||
"issues": "https://github.com/DivineOmega/array_undot/issues",
|
||||
"source": "https://github.com/DivineOmega/array_undot/tree/master"
|
||||
},
|
||||
"time": "2019-04-23T15:22:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "7.5.0",
|
||||
|
||||
@@ -63,5 +63,15 @@ return [
|
||||
// Ping sites to determine availability (e.g. online, offline, errors).
|
||||
'checkstatus' => getenv('CHECKSTATUS') ?: true,
|
||||
// Duration to cache status in minutes.
|
||||
'statuscache' => getenv('STATUSCACHE') ?: '5'
|
||||
'statuscache' => getenv('STATUSCACHE') ?: '5',
|
||||
|
||||
// The URL and port on which a docker socket proxy is listening, for example
|
||||
// if you have tecnativa/docker-socket-proxy named dockerproxy listening on
|
||||
// port 2375 then this would be "dockerproxy:2375".
|
||||
'dockerproxyurl' => getenv('DOCKERPROXYURL') ?: false,
|
||||
// Docker socket path. Note the host docker socket file must be mapped as
|
||||
// a volume into the container, this must match the path it has been mapped to.
|
||||
// If possible please don't use this as it can be insecure, use a docker socket
|
||||
// proxy instead (see above).
|
||||
'dockersocket' => getenv('DOCKERSOCKET') ?: false
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user