From 1453eacf6d33e8ecd1bed899a0d25a065eb61686 Mon Sep 17 00:00:00 2001 From: Phil Tyler Date: Wed, 13 Nov 2024 16:32:47 -0800 Subject: [PATCH] reload core during schema update (#191) --------- Co-authored-by: Brian Weaver Co-authored-by: Kevin Porras Co-authored-by: Tom Stovall --- .envrc.dist | 1 + .gitignore | 2 + CODEOWNERS | 1 + RoboFile.php | 37 +++++++++ catalog-info.yml | 12 +++ drush.services.yml | 5 ++ phpunit.xml | 1 + search_api_pantheon.services.yml | 3 + src/Commands/Diagnose.php | 3 + src/Commands/Reload.php | 68 +++++++++++++++ .../SolrConnector/PantheonSolrConnector.php | 1 + src/Services/Endpoint.php | 29 +++++++ src/Services/PantheonGuzzle.php | 10 ++- src/Services/Reload.php | 82 +++++++++++++++++++ src/Services/SchemaPoster.php | 24 ++++++ tests/Unit/EndpointServiceTest.php | 10 +++ tests/Unit/GuzzleClassTest.php | 2 + 17 files changed, 289 insertions(+), 2 deletions(-) create mode 100644 CODEOWNERS create mode 100644 catalog-info.yml create mode 100644 src/Commands/Reload.php create mode 100644 src/Services/Reload.php diff --git a/.envrc.dist b/.envrc.dist index b18f4442..a0031c90 100644 --- a/.envrc.dist +++ b/.envrc.dist @@ -9,3 +9,4 @@ export PANTHEON_INDEX_PORT=8983 export PANTHEON_INDEX_PATH=/solr export PANTHEON_INDEX_CORE=${SOLR_CORE} export PANTHEON_INDEX_SCHEME=http +export PANTHEON_INDEX_RELOAD_PATH=${SOLR_RELOAD_PATH} diff --git a/.gitignore b/.gitignore index 5b0d6ba4..6baa65bf 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ .idea .DS_Store docs/Badge.confluence + +.envrc diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..632c6150 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @pantheon-systems/site-experience diff --git a/RoboFile.php b/RoboFile.php index bc25bcf2..1fc32bba 100644 --- a/RoboFile.php +++ b/RoboFile.php @@ -117,6 +117,10 @@ public function testFull(int $drupal_version = 9, string $site_name = NULL) { // Test creating Solr index. $this->testSolrIndexCreate($site_name, 'dev'); + // Test running the reload + $this->testPantheonSolrReload($site_name, 'dev'); + $this->testSolrReload($site_name, 'dev'); + // Test select query. $this->testSolrSelect($site_name, 'dev'); @@ -573,6 +577,7 @@ public function testModuleEnable(string $site_name, string $env = 'dev') { '--yes', 'search_api_pantheon', 'search_api_pantheon_admin', + 'search_api_solr_admin' ) ->run(); $this->taskExec(static::$TERMINUS_EXE) @@ -802,9 +807,41 @@ public function testSolrIndexCreate(string $site_name, string $env = 'dev') { if (!$result->wasSuccessful()) { exit(1); } + } + public function testPantheonSolrReload(string $site_name, string $env = 'dev') { + $result = $this->taskExec( static::$TERMINUS_EXE ) + ->args( + 'drush', + "$site_name.$env", + '--', + 'search-api-pantheon:reloadSchema', + ) + ->run(); + if (!$result->wasSuccessful()) { + exit(1); + } } + public function testSolrReload(string $site_name, string $env = 'dev') { + $result = $this->taskExec( static::$TERMINUS_EXE ) + ->args( + 'drush', + "$site_name.$env", + '--', + 'search-api-solr:reload', + 'pantheon_solr8' + ) + ->run(); + if (!$result->wasSuccessful()) { + exit(1); + } + } + + + + + /** * Use search-api-pantheon:select command to ensure both Drupal index and the actual Solr index have the same amount of items. * diff --git a/catalog-info.yml b/catalog-info.yml new file mode 100644 index 00000000..b1795c74 --- /dev/null +++ b/catalog-info.yml @@ -0,0 +1,12 @@ +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: search_api_pantheon + description: Auto-generated catalog info for pantheon-systems/search_api_pantheon + annotations: + backstage.io/techdocs-ref: dir:docs/ +spec: + type: library + lifecycle: mature + owner: site diff --git a/drush.services.yml b/drush.services.yml index 57fe20ed..2be3d265 100644 --- a/drush.services.yml +++ b/drush.services.yml @@ -19,3 +19,8 @@ services: arguments: [ "@logger.factory", "@search_api_pantheon.pantheon_guzzle", "@search_api_pantheon.endpoint", "@search_api_pantheon.solarium_client" ] tags: - { name: drush.command } + search_api_pantheon.drush_reload: + class: \Drupal\search_api_pantheon\Commands\Reload + arguments: [ "@logger.factory", "@search_api_pantheon.pantheon_guzzle", "@search_api_pantheon.schema_poster" ] + tags: + - { name: drush.command } diff --git a/phpunit.xml b/phpunit.xml index 5184585e..b0e49b9c 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -11,6 +11,7 @@ + diff --git a/search_api_pantheon.services.yml b/search_api_pantheon.services.yml index f20aa923..8c5a19f1 100755 --- a/search_api_pantheon.services.yml +++ b/search_api_pantheon.services.yml @@ -15,3 +15,6 @@ services: class: Drupal\search_api_pantheon\EventSubscriber\SearchApiPantheonSolrConfigFilesAlter tags: - { name: event_subscriber } + search_api_pantheon.reload: + class: Drupal\search_api_pantheon\Services\Reload + arguments: ['@logger.factory', '@search_api_pantheon.pantheon_guzzle'] diff --git a/src/Commands/Diagnose.php b/src/Commands/Diagnose.php index 066f24fa..1ec37214 100644 --- a/src/Commands/Diagnose.php +++ b/src/Commands/Diagnose.php @@ -119,6 +119,9 @@ public function diagnose() { $this->logger->notice('Index PATH Value: {var}', [ 'var' => $this->endpoint->getPath(), ]); + $this->logger->notice('Index RELOAD_PATH Value: {var}', [ + 'var' => $this->endpoint->getReloadPath(), + ]); $this->logger->notice('Testing bare Connection...'); $response = $this->pingSolrHost(); $this->logger->notice('Ping Received Response? {var}', [ diff --git a/src/Commands/Reload.php b/src/Commands/Reload.php new file mode 100644 index 00000000..9b42b482 --- /dev/null +++ b/src/Commands/Reload.php @@ -0,0 +1,68 @@ +logger = $loggerChannelFactory->get('SearchAPIPantheon Drush'); + $this->pantheonGuzzle = $pantheonGuzzle; + $this->schemaPoster = $schemaPoster; + } + + /** + * Search_api_pantheon:reloadSchema. + * + * @usage search-api-pantheon:reloadSchema + * Reload the latest schema + * + * @command search-api-pantheon:reloadSchema + */ + public function reloadSchema() { + try { + $this->schemaPoster->reloadServer(); + } + catch (\Exception $e) { + $this->logger->error((string) $e); + } + } + +} diff --git a/src/Plugin/SolrConnector/PantheonSolrConnector.php b/src/Plugin/SolrConnector/PantheonSolrConnector.php index c2ce5ea2..f2a4740c 100644 --- a/src/Plugin/SolrConnector/PantheonSolrConnector.php +++ b/src/Plugin/SolrConnector/PantheonSolrConnector.php @@ -129,6 +129,7 @@ public static function getPlatformConfig() { 'path' => getenv('PANTHEON_INDEX_PATH'), 'core' => getenv('PANTHEON_INDEX_CORE'), 'schema' => getenv('PANTHEON_INDEX_SCHEMA'), + 'reload_path' => getenv('PANTHEON_INDEX_RELOAD_PATH'), ]; } diff --git a/src/Services/Endpoint.php b/src/Services/Endpoint.php index 7b9cf98f..7a5f93a8 100644 --- a/src/Services/Endpoint.php +++ b/src/Services/Endpoint.php @@ -198,6 +198,35 @@ public function getSchemaUploadUri(): string { ); } + /** + * Get URL in pantheon environment to POST reload requests. + * + * @return string + * URL of envrionment. + */ + public function getReloadUri(): string { + return vsprintf( + '%s://%s:%d/%s%s', + [ + $this->getScheme(), + $this->getHost(), + $this->getPort(), + $this->getPath(), + $this->getReloadPath(), + ] + ); + } + + /** + * Get the path for Schema Reloads. + * + * @return string + * The path for schema reloads + */ + public function getReloadPath(): string { + return $this->options['reload_path']; + } + /** * Get the path for Schema Uploads. * diff --git a/src/Services/PantheonGuzzle.php b/src/Services/PantheonGuzzle.php index 89ff0cf0..55e9b256 100644 --- a/src/Services/PantheonGuzzle.php +++ b/src/Services/PantheonGuzzle.php @@ -73,8 +73,14 @@ public function __construct(Endpoint $endpoint, LoggerChannelFactoryInterface $l $config['cert'] = $cert; } parent::__construct($config); - $this->endpoint = $endpoint; - $this->logger = $logger_factory->get('PantheonGuzzle'); + if (!$endpoint instanceof Endpoint) { + throw new \InvalidArgumentException('Endpoint must be an instance of Endpoint'); + } + $this->setEndpoint($endpoint); + if ($logger_factory instanceof LoggerChannelFactoryInterface) { + $this->setLogger($logger_factory->get('PantheonGuzzle')); + } + $this->setLogger($logger_factory->get('PantheonGuzzle')); } /** diff --git a/src/Services/Reload.php b/src/Services/Reload.php new file mode 100644 index 00000000..4de21a26 --- /dev/null +++ b/src/Services/Reload.php @@ -0,0 +1,82 @@ +setLogger($logger_factory->get('reload_service')); + $this->client = $client; + } + + /** + * Reload the server after schema upload. + * + * @throws \Drupal\search_api_pantheon\Exceptions\PantheonSearchApiException + */ + public function reloadServer(): bool { + // Schema upload URL. + $uri = new Uri( + $this->getClient() + ->getEndpoint() + ->getReloadUri() + ); + + $this->logger->debug('Reload url: ' . (string) $uri); + + // Send the request. + $request = new Request( + 'POST', + $uri, + [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ] + ); + $response = $this->getClient()->sendRequest($request); + + $status_code = $response->getStatusCode(); + $reload_logger_content = [ + 'status_code' => $status_code, + 'reason' => $response->getReasonPhrase(), + ]; + if ($status_code >= 200 && $status_code < 300) { + $this->logger->info('Server reloaded: {status_code} {reason}', $reload_logger_content); + return TRUE; + } + $this->logger->error('Server not reloaded: {status_code} {reason}', $reload_logger_content); + return FALSE; + } + + public function getClient(): PantheonGuzzle { + return $this->client; + } + +} diff --git a/src/Services/SchemaPoster.php b/src/Services/SchemaPoster.php index fac2c2f6..c8c45d22 100644 --- a/src/Services/SchemaPoster.php +++ b/src/Services/SchemaPoster.php @@ -58,6 +58,8 @@ class SchemaPoster implements LoggerAwareInterface { */ protected $moduleExtensionList; + protected LoggerChannelFactoryInterface $loggerFactory; + /** * Class Constructor. */ @@ -68,6 +70,7 @@ public function __construct( ModuleExtensionList $module_extension_list ) { $this->logger = $logger_factory->get('PantheonSearch'); + $this->loggerFactory = $logger_factory; $this->client = $client; $this->entityTypeManager = $entity_type_manager; $this->moduleExtensionList = $module_extension_list; @@ -105,9 +108,30 @@ public function postSchema(string $server_id, $files = []): array { throw new \Exception('Cannot post schema to environment url.'); } + $status_code = $response->getStatusCode(); + $this->logger->info('Status code: ' . $status_code); + if ($status_code >= 200 && $status_code < 300) { + // @TODO Maybe we need to capture exception here?? + // Call reload on the server. + $this->reloadServer(); + } + $this->logger->info('After server reload?'); + return $this->processResponse($response); } + /** + * Reload the server after schema upload. + * + * @throws \Drupal\search_api_pantheon\Exceptions\PantheonSearchApiException + * + * @return bool + */ + public function reloadServer(): bool { + $reload = new Reload($this->loggerFactory, $this->client); + return $reload->reloadServer(); + } + /** * Process response and return message to be shown to user. * diff --git a/tests/Unit/EndpointServiceTest.php b/tests/Unit/EndpointServiceTest.php index a37d8dd2..8792fda1 100644 --- a/tests/Unit/EndpointServiceTest.php +++ b/tests/Unit/EndpointServiceTest.php @@ -28,6 +28,7 @@ public function testURIGeneration() { 'schema' => '/schema-path', 'collection' => NULL, 'leader' => FALSE, + 'reload_path' => "/reload-path", ]); $this->assertEquals('/core-name', $ep->getCore()); @@ -43,6 +44,15 @@ public function testURIGeneration() { 'one://two:1234/server-path/schema-path', $ep->getSchemaUploadUri() ); + $this->assertEquals( + 'one://two:1234/server-path/reload-path', + $ep->getReloadUri() + ); + } + + public function testReloadPath() { + $ep = new Endpoint(["reload_path" => "/reload"]); + $this->assertEquals("/reload", $ep->getReloadPath()); } } diff --git a/tests/Unit/GuzzleClassTest.php b/tests/Unit/GuzzleClassTest.php index d873e0d8..1e08b746 100644 --- a/tests/Unit/GuzzleClassTest.php +++ b/tests/Unit/GuzzleClassTest.php @@ -19,6 +19,8 @@ */ class GuzzleClassTest extends TestCase { + protected $loggerFactory; + /** * {@inheritdoc} */