Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UHF-9034: Proper internal address support #136

Merged
merged 6 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
342 changes: 297 additions & 45 deletions fixtures/environments.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions helfi_api_base.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ services:
class: Drupal\helfi_api_base\EventSubscriber\CacheTagInvalidatorSubscriber
arguments:
- '@cache_tags.invalidator'
- '@helfi_api_base.environment_resolver'
tags:
- { name: event_subscriber }

Expand Down
2 changes: 1 addition & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
colors="true"
cacheResultFile=".phpunit.cache/test-results"
executionOrder="depends,defects"
forceCoversAnnotation="true"
forceCoversAnnotation="false"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutChangesToGlobalState="true"
Expand Down
5 changes: 4 additions & 1 deletion src/Cache/CacheTagInvalidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@ public function __construct(
*
* @param array $tags
* An array of cache tags.
* @param array $instances
* The instances to flush caches from.
*
* @return $this
* The self.
*/
public function invalidateTags(array $tags) : self {
public function invalidateTags(array $tags, array $instances = []) : self {
try {
$this->pubSubManager->sendMessage([
'tags' => $tags,
'instances' => $instances,
]);
}
catch (ConnectionException) {
Expand Down
43 changes: 43 additions & 0 deletions src/Environment/Address.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types = 1);

namespace Drupal\helfi_api_base\Environment;

/**
* A value object to store address information.
*/
final class Address {

/**
* Constructs a new instance.
*
* @param string $domain
* The domain.
* @param string $protocol
* The protocol.
* @param int $port
* The port.
*/
public function __construct(
public readonly string $domain,
public readonly string $protocol = 'https',
public readonly int $port = 443,
) {
}

/**
* Gets the address.
*
* @return string
* The address.
*/
public function getAddress() : string {
$port = '';
if (!in_array($this->port, [80, 443])) {
$port = sprintf(':%d', $this->port);
}
return sprintf('%s://%s%s', $this->protocol, $this->domain, $port);
}

}
71 changes: 19 additions & 52 deletions src/Environment/Environment.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ final class Environment {
/**
* Constructs a new instance.
*
* @param string $domain
* The domain.
* @param \Drupal\helfi_api_base\Environment\Address $address
* The address.
* @param \Drupal\helfi_api_base\Environment\Address $internalAddress
* The internal address.
* @param array $paths
* The paths.
* @param string $protocol
* The protocol.
* @param string $id
* Environment resolver identifier for the project.
* @param \Drupal\helfi_api_base\Environment\EnvironmentEnum $environment
Expand All @@ -26,9 +26,9 @@ final class Environment {
* The environment specific metadata.
*/
public function __construct(
private readonly string $domain,
private readonly Address $address,
private readonly Address $internalAddress,
private readonly array $paths,
private readonly string $protocol,
private readonly string $id,
private readonly EnvironmentEnum $environment,
private readonly ?EnvironmentMetadata $metadata,
Expand All @@ -45,42 +45,6 @@ public function getId() : string {
return $this->id;
}

/**
* Gets the domain.
*
* @return string
* The domain.
*/
public function getDomain() : string {
return $this->domain;
}

/**
* Gets the protocol.
*
* @return string
* The protocol.
*/
public function getProtocol() : string {
return $this->protocol;
}

/**
* Gets the original URL for given language.
*
* @param string $language
* The language.
*
* @return string
* The URL.
*/
private function doGetUrl(string $language) : string {
return vsprintf('%s/%s', [
$this->getBaseUrl(),
ltrim($this->getPath($language), '/'),
]);
}

/**
* Gets the full URL for given language.
*
Expand All @@ -91,11 +55,7 @@ private function doGetUrl(string $language) : string {
* The URL.
*/
public function getUrl(string $language) : string {
$url = $this->doGetUrl($language);
// Local uses an internal address by default to allow containers to
// communicate via API requests. Convert URL back to a proper link that
// works with browsers.
return str_replace(['http://', ':8080'], ['https://', ''], $url);
return sprintf('%s/%s', $this->address->getAddress(), ltrim($this->getPath($language), '/'));
}

/**
Expand All @@ -108,7 +68,7 @@ public function getUrl(string $language) : string {
* The canonical URL.
*/
public function getInternalAddress(string $language) : string {
return $this->doGetUrl($language);
return sprintf('%s/%s', $this->internalAddress->getAddress(), ltrim($this->getPath($language), '/'));
}

/**
Expand All @@ -118,10 +78,17 @@ public function getInternalAddress(string $language) : string {
* The base url.
*/
public function getBaseUrl() : string {
return vsprintf('%s://%s', [
$this->getProtocol(),
$this->getDomain(),
]);
return $this->address->getAddress();
}

/**
* Gets the internal base url.
*
* @return string
* The base url.
*/
public function getInternalBaseUrl() : string {
return $this->internalAddress->getAddress();
}

/**
Expand Down
9 changes: 5 additions & 4 deletions src/Environment/EnvironmentResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,14 @@ private function populateEnvironments(string $pathOrJson) : void {
$project = new Project($id, ProjectMetadata::createFromArray($meta));

foreach ($environments as $environment => $settings) {
if (!isset($settings['domain'], $settings['path'])) {
throw new \InvalidArgumentException('Project missing domain or paths setting.');
if (!isset($settings['address'], $settings['internal_address'], $settings['path'])) {
throw new \InvalidArgumentException('Project missing "address", "internal_address" or "paths" setting.');
}

$project->addEnvironment($environment, new Environment(
$settings['domain'],
new Address(...$settings['address']),
new Address(...$settings['internal_address']),
$settings['path'],
$settings['protocol'] ?? 'https',
$id,
EnvironmentEnum::tryFrom($environment),
EnvironmentMetadata::createFromArray($settings['meta'] ?? [])
Expand Down
33 changes: 33 additions & 0 deletions src/EventSubscriber/CacheTagInvalidatorSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\helfi_api_base\Azure\PubSub\PubSubMessage;
use Drupal\helfi_api_base\Environment\EnvironmentResolverInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
Expand All @@ -18,12 +19,39 @@ final class CacheTagInvalidatorSubscriber implements EventSubscriberInterface {
*
* @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cacheTagsInvalidator
* The cache tag invalidator subscriber.
* @param \Drupal\helfi_api_base\Environment\EnvironmentResolverInterface $environmentResolver
* The environment resolver.
*/
public function __construct(
private readonly CacheTagsInvalidatorInterface $cacheTagsInvalidator,
private readonly EnvironmentResolverInterface $environmentResolver,
) {
}

/**
* Checks if the given instance is valid.
*
* @param array $instances
* The instances.
*
* @return bool
* TRUE if valid instance.
*/
private function isValidInstance(array $instances = []) : bool {
if (!$instances) {
return TRUE;
}

try {
$project = $this->environmentResolver->getActiveProject();

return in_array($project->getName(), $instances);
}
catch (\InvalidArgumentException) {
}
return TRUE;
}

/**
* Responds to PubSub message events.
*
Expand All @@ -34,6 +62,11 @@ public function onReceive(PubSubMessage $message) : void {
if (!isset($message->data['data']['tags'])) {
return;
}
$instances = $message->data['data']['instances'] ?? [];

if (!$this->isValidInstance($instances)) {
return;
}
$this->cacheTagsInvalidator->invalidateTags($message->data['data']['tags']);
// Cache invalidator service keeps already invalidated cache tags in a
// static cache and prevents the invalidation of the same tag multiple
Expand Down
38 changes: 33 additions & 5 deletions tests/fixtures/environments.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,30 @@
"sv": "/sv/boende",
"en": "/en/housing"
},
"protocol": "http",
"domain": "helfi-asuminen.docker.so:8080"
"address": {
"protocol": "https",
"domain": "helfi-asuminen.docker.so"
},
"internal_address": {
"protocol": "http",
"domain": "helfi-asuminen.docker.so",
"port": 8080
}
},
"prod": {
"path": {
"fi": "/fi/asuminen",
"sv": "/sv/boende",
"en": "/en/housing"
},
"domain": "www.hel.fi",
"address": {
"protocol": "https",
"domain": "www.hel.fi"
},
"internal_address": {
"protocol": "https",
"domain": "nginx-asuminen-prod.apps.platta.hel.fi"
},
"meta": {}
},
"stage": {
Expand All @@ -29,7 +43,14 @@
"sv": "/sv/staging-boende",
"en": "/en/staging-housing"
},
"domain": "www.hel.fi",
"address": {
"protocol": "https",
"domain": "www.hel.fi"
},
"internal_address": {
"protocol": "https",
"domain": "nginx-asuminen-staging.apps.platta.hel.fi"
},
"meta": {
"openshift_console_link": "https://example.com"
}
Expand All @@ -40,7 +61,14 @@
"sv": "/sv/test-boende",
"en": "/en/test-housing"
},
"domain": "helfi-asuminen-test.docker.so",
"address": {
"protocol": "https",
"domain": "www.hel.fi"
},
"internal_address": {
"protocol": "https",
"domain": "nginx-asuminen-test.apps.arodevtest.hel.fi"
},
"meta": {
"openshift_console_link": "https://example.com"
}
Expand Down
Loading
Loading