Upstreaming changes from downstream project
This commit is contained in:
parent
d62725db5f
commit
9d437e266f
7 changed files with 304 additions and 109 deletions
7
bouncer/.gitignore
vendored
7
bouncer/.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
|||
/docker-compose.override.yml
|
||||
/vendor
|
||||
/.php-cs-fixer.cache
|
||||
.idea
|
||||
docker-compose.override.yml
|
||||
vendor
|
||||
.php-cs-fixer.cache
|
||||
|
|
@ -49,11 +49,13 @@ COPY composer.* /app/
|
|||
COPY public /app/public
|
||||
RUN composer install && \
|
||||
chmod +x /app/bouncer && \
|
||||
mkdir -p /var/log/bouncer
|
||||
mkdir -p /var/log/bouncer && \
|
||||
rm /etc/nginx/sites-enabled/default && \
|
||||
cp /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default
|
||||
|
||||
FROM benzine/php:nginx-8.0 as test-app-a
|
||||
FROM benzine/php:nginx-8.1 as test-app-a
|
||||
COPY ./test/public-web-a /app/public
|
||||
|
||||
FROM benzine/php:nginx-8.0 as test-app-b
|
||||
FROM benzine/php:nginx-8.1 as test-app-b
|
||||
COPY ./test/public-web-b /app/public
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ server {
|
|||
{% if useTemporaryCert %}
|
||||
ssl_certificate /certs/example.crt;
|
||||
ssl_certificate_key /certs/example.key;
|
||||
{% elseif useGlobalCert %}
|
||||
ssl_certificate /certs/global.crt;
|
||||
ssl_certificate_key /certs/global.key;
|
||||
{% else %}
|
||||
ssl_certificate /etc/letsencrypt/live/{{ name }}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/{{ name }}/privkey.pem;
|
||||
|
|
|
|||
48
bouncer/Readme.md
Normal file
48
bouncer/Readme.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# Automatic Swarm Nginx Loadbalancer
|
||||
|
||||
## Environment variables
|
||||
This container has its own environment variables, AS WELL AS scanning for some environment variables associated with your services.
|
||||
These should not be confused.
|
||||
|
||||
### Load balancer Configuration
|
||||
#### Main configuration
|
||||
| Key | Default | Options | Behaviour |
|
||||
|----------------------------------------|---------|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| DOCKER_HOST | false | | Define a http endpoint representing your docker socket. If this is null, it connects to /var/lib/docker.sock |
|
||||
| GLOBAL_CERT | false | Contents of an ssl certificate | If you want to provide a single cert for all endpoints, perhaps with a catch-all that may be later overriden, you can provide the whole contents of a certificates file here. |
|
||||
| GLOBAL_CERT_KEY | false | Contents of an ssl certificates private key | The private key related to GLOBAL CERT. These must be provided in tandem. |
|
||||
| BOUNCER_FORCED_UPDATE_INTERVAL_SECONDS | false | positive numbers | To force the bouncer to update on a schedule even if no changes are detected, measured in seconds |
|
||||
|
||||
#### For using with lets encrypt
|
||||
| Key | Default | Options | Behaviour |
|
||||
|---------------------------|-----------|---------------------------|--------------------------------------------------------------------------------------|
|
||||
| BOUNCER_LETSENCRYPT_MODE | 'staging' | 'staging' or 'production' | Determine if this is going to connect to a production or staging Lets Encrypt server |
|
||||
| BOUNCER_LETSENCRYPT_EMAIL | | 'bob@example.com' | Email address to associate with lets encrypt |
|
||||
|
||||
#### For using S3 for generated cert synchronisation with Lets Encrypt
|
||||
| Key | Default | Options | Behaviour |
|
||||
|------------------------------------|---------|-----------------|---------------------------------------------------------------------------------------|
|
||||
| BOUNCER_S3_BUCKET | false | | enable S3 behaviour to store lets-encrypt generated certs |
|
||||
| BOUNCER_S3_ENDPOINT | false | | define s3 endpoint to override default AWS s3 implementation, for example, with minio |
|
||||
| BOUNCER_S3_KEY_ID | false | | S3 API Key ID | |
|
||||
| BOUNCER_s3_KEY_SECRET | false | | S3 API Key Secret |
|
||||
| BOUNCER_S3_REGION | false | | S3 API Region |
|
||||
| BOUNCER_S3_USE_PATH_STYLE_ENDPOINT | false | `true or false` | Needed for minio |
|
||||
| BOUNCER_S3_PREFIX | false | | Prefix file path in s3 bucket |
|
||||
|
||||
### Served Instance Configuration
|
||||
|
||||
These environment variables need to be applied to the CONSUMING SERVICE and not the loadbalancer container itself.
|
||||
|
||||
| Key | Example | Behaviour |
|
||||
|--------------------------------|-------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| BOUNCER_DOMAIN | "a.example.com" | The domain that should be directed to this container |
|
||||
| BOUNCER_LETSENCRYPT | Values are "yes" or "true", anything else is false | To enable, or disable Lets Encrypt service for this hostname |
|
||||
| BOUNCER_TARGET_PORT | 9000 | Explicitly define the port you want to hit the service on, in case of ambiguity |
|
||||
| BOUNCER_ALLOW_NON_SSL | Defaults to enabled. Values are "yes" or "true", anything else is false | Should HTTP only traffic be allowed to hit this service? If disabled, http traffic is forwarded towards https |
|
||||
| BOUNCER_ALLOW_WEBSOCKETS | Defaults to enabled. Values are "yes" or "true", anything else is false | Enable websocket behaviour |
|
||||
| BOUNCER_ALLOW_LARGE_PAYLOADS | Defaults to disabled. | Allows overriding the default nginx payload size. Related to BOUNCER_MAX_PAYLOADS_MEGABYTES |
|
||||
| BOUNCER_MAX_PAYLOADS_MEGABYTES | numbers | Size of max payload to allow, in megabytes. Requires BOUNCER_ALLOW_LARGE_PAYLOADS to be enabled |
|
||||
|
||||
## Security considerations
|
||||
If you're putting this behind access control to the docker socket, it will need access to the /swarm /services and /containers endpoints of the docker api.
|
||||
205
bouncer/bouncer
205
bouncer/bouncer
|
|
@ -21,16 +21,22 @@ class BouncerTarget
|
|||
{
|
||||
private string $id;
|
||||
private array $domains;
|
||||
private string $ip;
|
||||
private int $port = 80;
|
||||
private string $endpointHostnameOrIp;
|
||||
private ?int $port = null;
|
||||
private bool $letsEncrypt = false;
|
||||
private string $targetPath;
|
||||
private bool $allowNonSSL = true;
|
||||
private bool $useTemporaryCert = true;
|
||||
private bool $useGlobalCert = false;
|
||||
private bool $allowWebsocketSupport = true;
|
||||
private bool $allowLargePayloads = false;
|
||||
private int $maxPayloadSizeMegabytes = 256;
|
||||
|
||||
public function __construct(
|
||||
private Logger $logger
|
||||
) {
|
||||
}
|
||||
|
||||
public function __toArray()
|
||||
{
|
||||
return [
|
||||
|
|
@ -40,6 +46,7 @@ class BouncerTarget
|
|||
'letsEncrypt' => $this->isLetsEncrypt(),
|
||||
'targetPath' => $this->getTargetPath(),
|
||||
'useTemporaryCert' => $this->isUseTemporaryCert(),
|
||||
'useGlobalCert' => $this->isUseGlobalCert(),
|
||||
'allowNonSSL' => $this->isAllowNonSSL(),
|
||||
'allowWebsocketSupport' => $this->isAllowWebsocketSupport(),
|
||||
'allowLargePayloads' => $this->isAllowLargePayloads(),
|
||||
|
|
@ -59,6 +66,21 @@ class BouncerTarget
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function isUseGlobalCert(): bool
|
||||
{
|
||||
return $this->useGlobalCert;
|
||||
}
|
||||
|
||||
public function setUseGlobalCert(bool $useGlobalCert): BouncerTarget
|
||||
{
|
||||
$this->useGlobalCert = $useGlobalCert;
|
||||
|
||||
// Global cert overrides temporary certs.
|
||||
$this->setUseTemporaryCert(false);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isAllowWebsocketSupport(): bool
|
||||
{
|
||||
return $this->allowWebsocketSupport;
|
||||
|
|
@ -149,23 +171,28 @@ class BouncerTarget
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getIp(): string
|
||||
public function getEndpointHostnameOrIp(): string
|
||||
{
|
||||
return $this->ip;
|
||||
return $this->endpointHostnameOrIp;
|
||||
}
|
||||
|
||||
public function setIp(string $ip): BouncerTarget
|
||||
public function setEndpointHostnameOrIp(string $endpointHostnameOrIp): BouncerTarget
|
||||
{
|
||||
$this->ip = $ip;
|
||||
$this->endpointHostnameOrIp = $endpointHostnameOrIp;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPort(): int
|
||||
public function getPort(): ?int
|
||||
{
|
||||
return $this->port;
|
||||
}
|
||||
|
||||
public function isPortSet(): bool
|
||||
{
|
||||
return $this->port !== null;
|
||||
}
|
||||
|
||||
public function setPort(int $port): BouncerTarget
|
||||
{
|
||||
$this->port = $port;
|
||||
|
|
@ -189,6 +216,28 @@ class BouncerTarget
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isEndpointValid(): bool
|
||||
{
|
||||
// Is it just an IP?
|
||||
if (filter_var($this->getEndpointHostnameOrIp(), FILTER_VALIDATE_IP)) {
|
||||
// $this->logger->debug(sprintf('%s isEndpointValid: %s is a normal IP', Emoji::magnifyingGlassTiltedRight(), $this->getEndpointHostnameOrIp()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is it a Hostname that resolves?
|
||||
$resolved = gethostbyname($this->getEndpointHostnameOrIp());
|
||||
if (filter_var($resolved, FILTER_VALIDATE_IP)) {
|
||||
// $this->logger->debug(sprintf('%s isEndpointValid: %s is a hostname that resolves to a normal IP %s', Emoji::magnifyingGlassTiltedRight(), $this->getEndpointHostnameOrIp(), $resolved));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// $this->logger->debug(sprintf('%s isEndpointValid: %s is a hostname does not resolve', Emoji::magnifyingGlassTiltedRight(), $this->getEndpointHostnameOrIp()));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class Bouncer
|
||||
|
|
@ -200,10 +249,14 @@ class Bouncer
|
|||
private Filesystem $configFilesystem;
|
||||
private Filesystem $certificateStoreLocal;
|
||||
private ?Filesystem $certificateStoreRemote = null;
|
||||
private Filesystem $providedCertificateStore;
|
||||
private Logger $logger;
|
||||
private string $instanceStateHash = '';
|
||||
private array $fileHashes;
|
||||
private bool $swarmMode = false;
|
||||
private bool $useGlobalCert = false;
|
||||
private int $forcedUpdateIntervalSeconds = 600;
|
||||
private ?int $lastUpdateEpoch = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
|
@ -216,14 +269,13 @@ class Bouncer
|
|||
$stdout->setFormatter(new ColoredLineFormatter(null, "%level_name%: %message% \n"));
|
||||
$this->logger->pushHandler($stdout);
|
||||
|
||||
$this->client = new Guzzle(
|
||||
[
|
||||
'base_uri' => 'http://localhost',
|
||||
'curl' => [
|
||||
CURLOPT_UNIX_SOCKET_PATH => '/var/run/docker.sock',
|
||||
],
|
||||
]
|
||||
);
|
||||
if (isset($this->environment['DOCKER_HOST'])) {
|
||||
$this->logger->info(sprintf('%s Connecting to %s', Emoji::electricPlug(), $this->environment['DOCKER_HOST']));
|
||||
$this->client = new Guzzle(['base_uri' => $this->environment['DOCKER_HOST']]);
|
||||
} else {
|
||||
$this->logger->info(sprintf('%s Connecting to /var/run/docker.sock', Emoji::electricPlug()));
|
||||
$this->client = new Guzzle(['base_uri' => 'http://localhost', 'curl' => [CURLOPT_UNIX_SOCKET_PATH => '/var/run/docker.sock']]);
|
||||
}
|
||||
|
||||
$this->loader = new FilesystemLoader([
|
||||
__DIR__,
|
||||
|
|
@ -236,6 +288,9 @@ class Bouncer
|
|||
// Set up Local certificate store
|
||||
$this->certificateStoreLocal = new Filesystem(new LocalFilesystemAdapter('/etc/letsencrypt'));
|
||||
|
||||
// Set up Local certificate store for certificates provided to us
|
||||
$this->providedCertificateStore = new Filesystem(new LocalFilesystemAdapter('/certs'));
|
||||
|
||||
// Set up Remote certificate store, if configured
|
||||
if (isset($this->environment['BOUNCER_S3_BUCKET'])) {
|
||||
$this->certificateStoreRemote = new Filesystem(
|
||||
|
|
@ -255,6 +310,20 @@ class Bouncer
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Allow defined global cert if set
|
||||
if (isset($this->environment['GLOBAL_CERT'], $this->environment['GLOBAL_CERT_KEY'])) {
|
||||
$this->setUseGlobalCert(true);
|
||||
$this->providedCertificateStore->write('global.crt', str_replace('\\n', "\n", trim($this->environment['GLOBAL_CERT'], '"')));
|
||||
$this->providedCertificateStore->write('global.key', str_replace('\\n', "\n", trim($this->environment['GLOBAL_CERT_KEY'], '"')));
|
||||
$this->logger->info(sprintf("%s GLOBAL_CERT was set, so we're going to use a defined certificate!", Emoji::globeShowingEuropeAfrica()));
|
||||
}
|
||||
|
||||
// Determine forced update interval.
|
||||
if (isset($this->environment['BOUNCER_FORCED_UPDATE_INTERVAL_SECONDS']) && is_numeric($this->environment['BOUNCER_FORCED_UPDATE_INTERVAL_SECONDS'])) {
|
||||
$this->setForcedUpdateIntervalSeconds($this->environment['BOUNCER_FORCED_UPDATE_INTERVAL_SECONDS']);
|
||||
}
|
||||
$this->logger->info(sprintf('%s Forced update interval is every %d seconds', Emoji::watch(), $this->getForcedUpdateIntervalSeconds()));
|
||||
}
|
||||
|
||||
public function isSwarmMode(): bool
|
||||
|
|
@ -269,6 +338,30 @@ class Bouncer
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function isUseGlobalCert(): bool
|
||||
{
|
||||
return $this->useGlobalCert;
|
||||
}
|
||||
|
||||
public function setUseGlobalCert(bool $useGlobalCert): Bouncer
|
||||
{
|
||||
$this->useGlobalCert = $useGlobalCert;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getForcedUpdateIntervalSeconds(): int
|
||||
{
|
||||
return $this->forcedUpdateIntervalSeconds;
|
||||
}
|
||||
|
||||
public function setForcedUpdateIntervalSeconds(int $forcedUpdateIntervalSeconds): Bouncer
|
||||
{
|
||||
$this->forcedUpdateIntervalSeconds = $forcedUpdateIntervalSeconds;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*
|
||||
|
|
@ -288,29 +381,40 @@ class Bouncer
|
|||
[$envKey, $envVal] = explode('=', $environmentItem, 2);
|
||||
$envs[$envKey] = $envVal;
|
||||
} else {
|
||||
$envs[$envKey] = true;
|
||||
$envs[$environmentItem] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($envs['BOUNCER_DOMAIN'])) {
|
||||
$bouncerTarget = (new BouncerTarget())
|
||||
$bouncerTarget = (new BouncerTarget($this->logger))
|
||||
->setId($inspect['Id'])
|
||||
;
|
||||
$bouncerTarget = $this->parseContainerEnvironmentVariables($envs, $bouncerTarget);
|
||||
|
||||
if (isset($inspect['NetworkSettings']['IPAddress']) && !empty($inspect['NetworkSettings']['IPAddress'])) {
|
||||
// As per docker service
|
||||
$bouncerTarget->setIp($inspect['NetworkSettings']['IPAddress']);
|
||||
$bouncerTarget->setEndpointHostnameOrIp($inspect['NetworkSettings']['IPAddress']);
|
||||
} else {
|
||||
// As per docker compose
|
||||
$networks = array_values($inspect['NetworkSettings']['Networks']);
|
||||
$bouncerTarget->setIp($networks[0]['IPAddress']);
|
||||
$bouncerTarget->setEndpointHostnameOrIp($networks[0]['IPAddress']);
|
||||
}
|
||||
// $this->logger->debug(sprintf('Decided that %s has the ip %s', $bouncerTarget->getName(), $bouncerTarget->getIp()));
|
||||
|
||||
$bouncerTarget->setTargetPath(sprintf('http://%s:%d/', $bouncerTarget->getIp(), $bouncerTarget->getPort()));
|
||||
$bouncerTarget->setTargetPath(sprintf('http://%s:%d/', $bouncerTarget->getEndpointHostnameOrIp(), $bouncerTarget->getPort() >= 0 ? $bouncerTarget->getPort() : 80));
|
||||
|
||||
$bouncerTargets[] = $bouncerTarget;
|
||||
$bouncerTarget->setUseGlobalCert($this->isUseGlobalCert());
|
||||
|
||||
$valid = $bouncerTarget->isEndpointValid();
|
||||
// $this->logger->debug(sprintf(
|
||||
// '%s Decided that %s has the endpoint %s and it %s.',
|
||||
// Emoji::magnifyingGlassTiltedLeft(),
|
||||
// $bouncerTarget->getName(),
|
||||
// $bouncerTarget->getEndpointHostnameOrIp(),
|
||||
// $valid ? 'is valid' : 'is not valid'
|
||||
// ));
|
||||
if ($valid) {
|
||||
$bouncerTargets[] = $bouncerTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -340,19 +444,39 @@ class Bouncer
|
|||
$envs[$eKey] = $eVal;
|
||||
}
|
||||
if (isset($envs['BOUNCER_DOMAIN'])) {
|
||||
$bouncerTarget = (new BouncerTarget())
|
||||
$bouncerTarget = (new BouncerTarget($this->logger))
|
||||
->setId($service['ID'])
|
||||
;
|
||||
|
||||
$bouncerTarget = $this->parseContainerEnvironmentVariables($envs, $bouncerTarget);
|
||||
|
||||
$bouncerTarget->setIp('172.17.0.1');
|
||||
$bouncerTarget->setPort($service['Endpoint']['Ports'][0]['PublishedPort']);
|
||||
$bouncerTarget->setTargetPath(sprintf('http://%s:%d/', $bouncerTarget->getIp(), $bouncerTarget->getPort()));
|
||||
if ($bouncerTarget->isPortSet()) {
|
||||
$bouncerTarget->setEndpointHostnameOrIp($service['Spec']['Name']);
|
||||
// $this->logger->info(sprintf('Ports for %s has been explicitly set to %s:%d.', $bouncerTarget->getName(), $bouncerTarget->getEndpointHostnameOrIp(), $bouncerTarget->getPort()));
|
||||
} elseif (isset($service['Endpoint']['Ports'])) {
|
||||
$bouncerTarget->setEndpointHostnameOrIp('172.17.0.1');
|
||||
$bouncerTarget->setPort($service['Endpoint']['Ports'][0]['PublishedPort']);
|
||||
} else {
|
||||
$this->logger->warning(sprintf('Ports block missing for %s.', $bouncerTarget->getName()));
|
||||
|
||||
continue;
|
||||
}
|
||||
$bouncerTarget->setTargetPath(sprintf('http://%s:%d/', $bouncerTarget->getEndpointHostnameOrIp(), $bouncerTarget->getPort()));
|
||||
|
||||
$bouncerTarget->setUseGlobalCert($this->isUseGlobalCert());
|
||||
|
||||
// $this->logger->debug(sprintf('Decided that %s has the target path %s', $bouncerTarget->getName(), $bouncerTarget->getTargetPath()));
|
||||
|
||||
$bouncerTargets[] = $bouncerTarget;
|
||||
$valid = $bouncerTarget->isEndpointValid();
|
||||
// $this->logger->debug(sprintf(
|
||||
// '%s Decided that %s has the endpoint %s and it %s.',
|
||||
// Emoji::magnifyingGlassTiltedLeft(),
|
||||
// $bouncerTarget->getName(),
|
||||
// $bouncerTarget->getEndpointHostnameOrIp(),
|
||||
// $valid ? 'is valid' : 'is not valid'
|
||||
// ));
|
||||
if ($valid) {
|
||||
$bouncerTargets[] = $bouncerTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -431,6 +555,9 @@ class Bouncer
|
|||
*/
|
||||
private function stateHasChanged(): bool
|
||||
{
|
||||
if ($this->lastUpdateEpoch === null || $this->lastUpdateEpoch <= time() - $this->forcedUpdateIntervalSeconds) {
|
||||
return true;
|
||||
}
|
||||
$newInstanceStates = [];
|
||||
|
||||
// Standard Containers
|
||||
|
|
@ -486,6 +613,8 @@ class Bouncer
|
|||
$this->logger->info(sprintf('%s Swarm mode is %s.', Emoji::CHARACTER_HONEYBEE, $this->isSwarmMode() ? 'enabled' : 'disabled'));
|
||||
$targets = $this->isSwarmMode() ? $this->findContainersSwarmMode() : $this->findContainersContainerMode();
|
||||
|
||||
$this->wipeNginxConfig();
|
||||
|
||||
$this->logger->info(sprintf('%s Found %d services with BOUNCER_DOMAIN set', Emoji::CHARACTER_MAGNIFYING_GLASS_TILTED_LEFT, count($targets)));
|
||||
foreach ($targets as $target) {
|
||||
$this->generateNginxConfig($target);
|
||||
|
|
@ -502,6 +631,7 @@ class Bouncer
|
|||
while ($this->stateHasChanged() === false) {
|
||||
sleep(5);
|
||||
}
|
||||
$this->lastUpdateEpoch = time();
|
||||
$this->logger->info(sprintf('%s Host Container state has changed', Emoji::CHARACTER_WARNING));
|
||||
}
|
||||
|
||||
|
|
@ -567,10 +697,8 @@ class Bouncer
|
|||
|
||||
private function generateNginxConfig(BouncerTarget $target): self
|
||||
{
|
||||
$this->configFilesystem->write(
|
||||
$target->getName(),
|
||||
$this->twig->render('NginxTemplate.twig', $target->__toArray())
|
||||
);
|
||||
$configData = $this->twig->render('NginxTemplate.twig', $target->__toArray());
|
||||
$this->configFilesystem->write($target->getName(), $configData);
|
||||
$this->logger->info(sprintf('%s Created Nginx config for http://%s', Emoji::CHARACTER_PENCIL, $target->getName()));
|
||||
|
||||
return $this;
|
||||
|
|
@ -644,6 +772,19 @@ class Bouncer
|
|||
$this->logger->info(sprintf('%s Restarting nginx', Emoji::CHARACTER_TIMER_CLOCK));
|
||||
$shell->run($command);
|
||||
}
|
||||
|
||||
private function wipeNginxConfig(): void
|
||||
{
|
||||
$this->logger->debug('Purging existing config files ...');
|
||||
foreach ($this->configFilesystem->listContents('') as $file) {
|
||||
/** @var FileAttributes $file */
|
||||
if ($file->isFile() && $file->path() != 'default' && $file->path() != 'default-ssl') {
|
||||
$this->configFilesystem->delete($file->path());
|
||||
// $this->logger->debug(sprintf(' > %s', $file->path()));
|
||||
}
|
||||
}
|
||||
// $this->logger->debug('Purge complete!');
|
||||
}
|
||||
}
|
||||
|
||||
(new Bouncer())->run();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "benzine/bouncer",
|
||||
"description": "Nginx Configuration Management",
|
||||
"description": "Automated Docker-swarm aware Nginx configuration management",
|
||||
"type": "project",
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"license": "GPL-3.0-or-later",
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"php": "^8.1",
|
||||
"ext-json": "*",
|
||||
"ext-curl": "*",
|
||||
"kint-php/kint": "^3.3",
|
||||
|
|
|
|||
138
bouncer/composer.lock
generated
138
bouncer/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": "bb6894396a4d90d304b95586f326ea71",
|
||||
"content-hash": "afde4d97f684020724ec24b67577d3ae",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adambrett/shell-wrapper",
|
||||
|
|
@ -108,16 +108,16 @@
|
|||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.224.0",
|
||||
"version": "3.228.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "bc5eb18414ef703c5f39a5a009a437c74c228306"
|
||||
"reference": "4dad57c95c7ff1dfcea29a7877ce64720b3318c3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/bc5eb18414ef703c5f39a5a009a437c74c228306",
|
||||
"reference": "bc5eb18414ef703c5f39a5a009a437c74c228306",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/4dad57c95c7ff1dfcea29a7877ce64720b3318c3",
|
||||
"reference": "4dad57c95c7ff1dfcea29a7877ce64720b3318c3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -125,9 +125,9 @@
|
|||
"ext-json": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-simplexml": "*",
|
||||
"guzzlehttp/guzzle": "^5.3.3 || ^6.2.1 || ^7.0",
|
||||
"guzzlehttp/guzzle": "^6.5.8 || ^7.4.5",
|
||||
"guzzlehttp/promises": "^1.4.0",
|
||||
"guzzlehttp/psr7": "^1.7.0 || ^2.1.1",
|
||||
"guzzlehttp/psr7": "^1.8.5 || ^2.3",
|
||||
"mtdowling/jmespath.php": "^2.6",
|
||||
"php": ">=5.5"
|
||||
},
|
||||
|
|
@ -193,9 +193,9 @@
|
|||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.224.0"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.228.3"
|
||||
},
|
||||
"time": "2022-05-27T20:23:28+00:00"
|
||||
"time": "2022-06-24T20:24:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bramus/ansi-php",
|
||||
|
|
@ -883,16 +883,16 @@
|
|||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "2.6.0",
|
||||
"version": "2.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/monolog.git",
|
||||
"reference": "247918972acd74356b0a91dfaa5adcaec069b6c0"
|
||||
"reference": "5579edf28aee1190a798bfa5be8bc16c563bd524"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/247918972acd74356b0a91dfaa5adcaec069b6c0",
|
||||
"reference": "247918972acd74356b0a91dfaa5adcaec069b6c0",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/5579edf28aee1190a798bfa5be8bc16c563bd524",
|
||||
"reference": "5579edf28aee1190a798bfa5be8bc16c563bd524",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -971,7 +971,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Seldaek/monolog/issues",
|
||||
"source": "https://github.com/Seldaek/monolog/tree/2.6.0"
|
||||
"source": "https://github.com/Seldaek/monolog/tree/2.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -983,7 +983,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-10T09:36:00+00:00"
|
||||
"time": "2022-06-09T08:59:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mtdowling/jmespath.php",
|
||||
|
|
@ -1435,16 +1435,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.25.0",
|
||||
"version": "v1.26.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "30885182c981ab175d4d034db0f6f469898070ab"
|
||||
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
|
||||
"reference": "30885182c981ab175d4d034db0f6f469898070ab",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
|
||||
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1459,7 +1459,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.23-dev"
|
||||
"dev-main": "1.26-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
|
|
@ -1497,7 +1497,7 @@
|
|||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -1513,20 +1513,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-10-20T20:35:02+00:00"
|
||||
"time": "2022-05-24T11:49:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.25.0",
|
||||
"version": "v1.26.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825"
|
||||
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825",
|
||||
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
|
||||
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1541,7 +1541,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.23-dev"
|
||||
"dev-main": "1.26-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
|
|
@ -1580,7 +1580,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -1596,7 +1596,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-11-30T18:21:41+00:00"
|
||||
"time": "2022-05-24T11:49:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
|
|
@ -2337,16 +2337,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v6.1.0",
|
||||
"version": "v6.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "c9646197ef43b0e2ff44af61e7f0571526fd4170"
|
||||
"reference": "7a86c1c42fbcb69b59768504c7bca1d3767760b7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/c9646197ef43b0e2ff44af61e7f0571526fd4170",
|
||||
"reference": "c9646197ef43b0e2ff44af61e7f0571526fd4170",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/7a86c1c42fbcb69b59768504c7bca1d3767760b7",
|
||||
"reference": "7a86c1c42fbcb69b59768504c7bca1d3767760b7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2413,7 +2413,7 @@
|
|||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v6.1.0"
|
||||
"source": "https://github.com/symfony/console/tree/v6.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -2429,7 +2429,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-27T06:34:22+00:00"
|
||||
"time": "2022-06-26T13:01:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
|
|
@ -2789,16 +2789,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.25.0",
|
||||
"version": "v1.26.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
"reference": "81b86b50cf841a64252b439e738e97f4a34e2783"
|
||||
"reference": "433d05519ce6990bf3530fba6957499d327395c2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783",
|
||||
"reference": "81b86b50cf841a64252b439e738e97f4a34e2783",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2",
|
||||
"reference": "433d05519ce6990bf3530fba6957499d327395c2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2810,7 +2810,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.23-dev"
|
||||
"dev-main": "1.26-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
|
|
@ -2850,7 +2850,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -2866,20 +2866,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-11-23T21:10:46+00:00"
|
||||
"time": "2022-05-24T11:49:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.25.0",
|
||||
"version": "v1.26.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8"
|
||||
"reference": "219aa369ceff116e673852dce47c3a41794c14bd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8",
|
||||
"reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
|
||||
"reference": "219aa369ceff116e673852dce47c3a41794c14bd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2891,7 +2891,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.23-dev"
|
||||
"dev-main": "1.26-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
|
|
@ -2934,7 +2934,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -2950,20 +2950,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-02-19T12:13:01+00:00"
|
||||
"time": "2022-05-24T11:49:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.25.0",
|
||||
"version": "v1.26.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c"
|
||||
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c",
|
||||
"reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
|
||||
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2972,7 +2972,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.23-dev"
|
||||
"dev-main": "1.26-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
|
|
@ -3017,7 +3017,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0"
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -3033,20 +3033,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-03-04T08:16:47+00:00"
|
||||
"time": "2022-05-10T07:21:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.25.0",
|
||||
"version": "v1.26.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
"reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f"
|
||||
"reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
|
||||
"reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1",
|
||||
"reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -3055,7 +3055,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.23-dev"
|
||||
"dev-main": "1.26-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
|
|
@ -3096,7 +3096,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0"
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -3112,7 +3112,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-09-13T13:58:11+00:00"
|
||||
"time": "2022-05-24T11:49:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
|
|
@ -3324,16 +3324,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v6.1.0",
|
||||
"version": "v6.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529"
|
||||
"reference": "1903f2879875280c5af944625e8246d81c2f0604"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/d3edc75baf9f1d4f94879764dda2e1ac33499529",
|
||||
"reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/1903f2879875280c5af944625e8246d81c2f0604",
|
||||
"reference": "1903f2879875280c5af944625e8246d81c2f0604",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -3389,7 +3389,7 @@
|
|||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v6.1.0"
|
||||
"source": "https://github.com/symfony/string/tree/v6.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -3405,7 +3405,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-04-22T08:18:23+00:00"
|
||||
"time": "2022-06-26T16:35:04+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
|
|
|||
Loading…
Reference in a new issue