From a10307f901c76facb4ad2a289808ac890850635f Mon Sep 17 00:00:00 2001 From: Andrew Kostka Date: Thu, 17 Oct 2024 13:08:17 +0000 Subject: [PATCH] Update queryservice allowlist via job --- app/Console/Kernel.php | 3 + app/Jobs/UpdateQueryserviceAllowList.php | 46 +++++++ .../Jobs/UpdateQueryserviceAllowListTest.php | 117 ++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 app/Jobs/UpdateQueryserviceAllowList.php create mode 100644 tests/Jobs/UpdateQueryserviceAllowListTest.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index a79d1d73..33cfa3a0 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -14,6 +14,7 @@ use App\Jobs\SendEmptyWikiNotificationsJob; use App\Jobs\CreateQueryserviceBatchesJob; use App\Jobs\FailStalledEntityImportsJob; +use App\Jobs\UpdateQueryserviceAllowList; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -57,6 +58,8 @@ protected function schedule(Schedule $schedule): void $schedule->job(new UpdateWikiSiteStatsJob)->dailyAt('19:00'); $schedule->job(new SendEmptyWikiNotificationsJob)->dailyAt('21:00'); + + $schedule->job(new UpdateQueryserviceAllowList)->weeklyOn(Schedule::MONDAY, '01:00'); } /** diff --git a/app/Jobs/UpdateQueryserviceAllowList.php b/app/Jobs/UpdateQueryserviceAllowList.php new file mode 100644 index 00000000..961eceec --- /dev/null +++ b/app/Jobs/UpdateQueryserviceAllowList.php @@ -0,0 +1,46 @@ + "https://{$domain}/query/sparql", + Wiki::all()->pluck('domain')->toArray() + ) + ); + + $k8s->setNamespace('default'); + $configName = 'queryservice-allowlist'; + $config = $k8s->configMaps()->setFieldSelector([ + 'metadata.name' => $configName + ])->first(); + + if ($config === null) { + $this->fail( + new \RuntimeException( + "Queryservice config map '{$configName}' does not exist." + ) + ); + return; + } + + $allowListKey = 'allowlist.txt'; + $allowListStaticKey = 'allowlist-static.txt'; + + $config = $config->toArray(); + if (array_key_exists($allowListStaticKey, $config['data'])) { + $allowList .= PHP_EOL . trim($config['data'][$allowListStaticKey]); + } + $config['data'][$allowListKey] = trim($allowList); + $k8s->configMaps()->update(new ConfigMap($config)); + } +} diff --git a/tests/Jobs/UpdateQueryserviceAllowListTest.php b/tests/Jobs/UpdateQueryserviceAllowListTest.php new file mode 100644 index 00000000..ffa09aa0 --- /dev/null +++ b/tests/Jobs/UpdateQueryserviceAllowListTest.php @@ -0,0 +1,117 @@ +create(['domain' => 'somesite-5.localhost']); + Wiki::factory()->create(['domain' => 'somesite-6.localhost']); + } + + public function testMissingConfigMapFailure(): void + { + $mockJob = $this->createMock(Job::class); + $mockJob->expects($this->once()) + ->method('fail') + ->with(new \RuntimeException( + "Queryservice config map 'queryservice-allowlist' does not exist." + )); + + $job = new UpdateQueryserviceAllowList(); + $job->setJob($mockJob); + + $mock = new MockHandler([ + new Response(200, [], json_encode(['items' => []])), + new Response(200, [], json_encode(['items' => []])) + ]); + + $handlerStack = HandlerStack::create($mock); + $mockGuzzle = GuzzleClient::createWithConfig([ + 'handler' => $handlerStack, + 'verify' => '/var/run/secrets/kubernetes.io/serviceaccount/ca.crt' + ]); + + $job->handle(new Client([ + 'master' => 'https://kubernetes.default.svc', + 'token' => '/var/run/secrets/kubernetes.io/serviceaccount/token' + ], null, $mockGuzzle)); + } + + public function testSuccess(): void + { + $mockJob = $this->createMock(Job::class); + $mockJob->expects($this->never())->method('fail'); + + $job = new UpdateQueryserviceAllowList(); + $job->setJob($mockJob); + + $mock = new MockHandler([ + new Response(200, [], json_encode(['items' => [[ + 'kind' => 'ConfigMap', + 'apiVersion' => 'v1', + 'data' => [ + 'allowlist-static.txt' => implode(PHP_EOL, [ + 'https://somesite-1.localhost/query/sparql', + 'https://somesite-2.localhost/query/sparql' + ]), + 'allowlist.txt' => implode(PHP_EOL, [ + 'https://somesite-3.localhost/query/sparql', + 'https://somesite-4.localhost/query/sparql' + ]) + ] + ]]])), + new Response(200, [], json_encode(['items' => []])) + ]); + + $requests = []; + $handlerStack = HandlerStack::create($mock); + $handlerStack->push(Middleware::history($requests)); + $mockGuzzle = GuzzleClient::createWithConfig([ + 'handler' => $handlerStack, + 'verify' => '/var/run/secrets/kubernetes.io/serviceaccount/ca.crt' + ]); + + $job->handle(new Client([ + 'master' => 'https://kubernetes.default.svc', + 'token' => '/var/run/secrets/kubernetes.io/serviceaccount/token' + ], null, $mockGuzzle)); + + $this->assertCount(2, $requests); + $this->assertEquals( + [ + 'kind' => 'ConfigMap', + 'apiVersion' => 'v1', + 'data' => [ + 'allowlist-static.txt' => implode(PHP_EOL, [ + 'https://somesite-1.localhost/query/sparql', + 'https://somesite-2.localhost/query/sparql' + ]), + 'allowlist.txt' => implode(PHP_EOL, [ + 'https://somesite-5.localhost/query/sparql', + 'https://somesite-6.localhost/query/sparql', + 'https://somesite-1.localhost/query/sparql', + 'https://somesite-2.localhost/query/sparql' + ]) + ] + ], + json_decode($requests[1]['request']->getBody(), true) + ); + } +}