Skip to content

Commit a0c0b68

Browse files
committed
Fix Nayra REST host resolution
1 parent 6c89eae commit a0c0b68

2 files changed

Lines changed: 261 additions & 7 deletions

File tree

ProcessMaker/Models/ScriptDockerNayraTrait.php

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,7 @@ public function handleNayraDocker(string $code, array $data, array $config, $tim
4545
'timeout' => $timeout,
4646
];
4747
$body = json_encode($params);
48-
$servers = self::getNayraAddresses();
49-
if (!$servers) {
50-
$this->bringUpNayra();
51-
}
52-
$baseUrl = $this->getNayraInstanceUrl();
48+
$baseUrl = $this->resolveNayraBaseUrl();
5349
$url = $baseUrl . '/run_script';
5450
$this->ensureNayraServerIsRunning($baseUrl);
5551

@@ -80,10 +76,27 @@ public function handleNayraDocker(string $code, array $data, array $config, $tim
8076

8177
private function getNayraInstanceUrl()
8278
{
79+
if (config('app.nayra_rest_api_host')) {
80+
return config('app.nayra_rest_api_host');
81+
}
82+
8383
$servers = self::getNayraAddresses();
8484
return $this->schema . '://' . $servers[0] . ':' . $this->getNayraPort();
8585
}
8686

87+
private function resolveNayraBaseUrl()
88+
{
89+
if (config('app.nayra_rest_api_host')) {
90+
return config('app.nayra_rest_api_host');
91+
}
92+
93+
if (!self::getNayraAddresses()) {
94+
$this->bringUpNayra();
95+
}
96+
97+
return $this->getNayraInstanceUrl();
98+
}
99+
87100
private function getDockerLogs($instanceName)
88101
{
89102
$docker = Docker::command();
@@ -105,9 +118,15 @@ private function getDockerLogs($instanceName)
105118
private function ensureNayraServerIsRunning(string $url)
106119
{
107120
$header = @get_headers($url);
108-
if (!$header) {
109-
$this->bringUpNayra(true);
121+
if ($header) {
122+
return;
123+
}
124+
125+
if (config('app.nayra_rest_api_host')) {
126+
throw new ScriptException('Could not connect to the configured Nayra REST API host: ' . $url);
110127
}
128+
129+
$this->bringUpNayra(true);
111130
}
112131

113132
/**
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
<?php
2+
3+
namespace ProcessMaker\Models;
4+
5+
use ProcessMaker\Exception\ScriptException;
6+
use Tests\TestCase;
7+
8+
class ScriptDockerNayraTraitFunctionState
9+
{
10+
public static bool $enabled = false;
11+
12+
public static array $headers = [];
13+
14+
public static array $requestedHeaders = [];
15+
16+
public static ?string $curlUrl = null;
17+
18+
public static array $curlOptions = [];
19+
20+
public static string $curlResult = '{"status":"ok"}';
21+
22+
public static int $curlHttpStatus = 200;
23+
24+
public static bool $curlClosed = false;
25+
26+
public static function reset(): void
27+
{
28+
self::$enabled = false;
29+
self::$headers = [];
30+
self::$requestedHeaders = [];
31+
self::$curlUrl = null;
32+
self::$curlOptions = [];
33+
self::$curlResult = '{"status":"ok"}';
34+
self::$curlHttpStatus = 200;
35+
self::$curlClosed = false;
36+
}
37+
}
38+
39+
if (!function_exists(__NAMESPACE__ . '\get_headers')) {
40+
function get_headers($url, $associative = false, $context = null)
41+
{
42+
if (!ScriptDockerNayraTraitFunctionState::$enabled) {
43+
return \get_headers($url, $associative, $context);
44+
}
45+
46+
ScriptDockerNayraTraitFunctionState::$requestedHeaders[] = $url;
47+
48+
return ScriptDockerNayraTraitFunctionState::$headers[$url] ?? false;
49+
}
50+
}
51+
52+
if (!function_exists(__NAMESPACE__ . '\curl_init')) {
53+
function curl_init($url = null)
54+
{
55+
if (!ScriptDockerNayraTraitFunctionState::$enabled) {
56+
return \curl_init($url);
57+
}
58+
59+
ScriptDockerNayraTraitFunctionState::$curlUrl = $url;
60+
61+
return (object) ['url' => $url];
62+
}
63+
}
64+
65+
if (!function_exists(__NAMESPACE__ . '\curl_setopt')) {
66+
function curl_setopt($handle, $option, $value)
67+
{
68+
if (!ScriptDockerNayraTraitFunctionState::$enabled) {
69+
return \curl_setopt($handle, $option, $value);
70+
}
71+
72+
ScriptDockerNayraTraitFunctionState::$curlOptions[$option] = $value;
73+
74+
return true;
75+
}
76+
}
77+
78+
if (!function_exists(__NAMESPACE__ . '\curl_exec')) {
79+
function curl_exec($handle)
80+
{
81+
if (!ScriptDockerNayraTraitFunctionState::$enabled) {
82+
return \curl_exec($handle);
83+
}
84+
85+
return ScriptDockerNayraTraitFunctionState::$curlResult;
86+
}
87+
}
88+
89+
if (!function_exists(__NAMESPACE__ . '\curl_getinfo')) {
90+
function curl_getinfo($handle, $option = null)
91+
{
92+
if (!ScriptDockerNayraTraitFunctionState::$enabled) {
93+
return \curl_getinfo($handle, $option);
94+
}
95+
96+
if ($option === CURLINFO_HTTP_CODE) {
97+
return ScriptDockerNayraTraitFunctionState::$curlHttpStatus;
98+
}
99+
100+
return ['http_code' => ScriptDockerNayraTraitFunctionState::$curlHttpStatus];
101+
}
102+
}
103+
104+
if (!function_exists(__NAMESPACE__ . '\curl_close')) {
105+
function curl_close($handle)
106+
{
107+
if (!ScriptDockerNayraTraitFunctionState::$enabled) {
108+
return \curl_close($handle);
109+
}
110+
111+
ScriptDockerNayraTraitFunctionState::$curlClosed = true;
112+
}
113+
}
114+
115+
class ScriptDockerNayraTraitTestHarness
116+
{
117+
use ScriptDockerNayraTrait {
118+
getNayraInstanceUrl as public exposedGetNayraInstanceUrl;
119+
resolveNayraBaseUrl as public exposedResolveNayraBaseUrl;
120+
}
121+
122+
public int $bringUpNayraCalls = 0;
123+
124+
public array $bringUpNayraRestartValues = [];
125+
126+
public function bringUpNayra($restart = false)
127+
{
128+
$this->bringUpNayraCalls++;
129+
$this->bringUpNayraRestartValues[] = $restart;
130+
131+
if (!$restart) {
132+
self::setNayraAddresses(['172.18.0.9']);
133+
}
134+
}
135+
}
136+
137+
class ScriptDockerNayraTraitTest extends TestCase
138+
{
139+
protected function setUp(): void
140+
{
141+
parent::setUp();
142+
143+
ScriptDockerNayraTraitFunctionState::reset();
144+
ScriptDockerNayraTraitTestHarness::clearNayraAddresses();
145+
146+
config([
147+
'app.nayra_rest_api_host' => '',
148+
'app.nayra_port' => 8081,
149+
]);
150+
}
151+
152+
protected function tearDown(): void
153+
{
154+
ScriptDockerNayraTraitFunctionState::reset();
155+
ScriptDockerNayraTraitTestHarness::clearNayraAddresses();
156+
157+
parent::tearDown();
158+
}
159+
160+
public function testHandleNayraDockerUsesConfiguredRestApiHostWithoutStartingDocker()
161+
{
162+
config(['app.nayra_rest_api_host' => 'http://127.0.0.1:8081']);
163+
ScriptDockerNayraTraitFunctionState::$enabled = true;
164+
ScriptDockerNayraTraitFunctionState::$headers = [
165+
'http://127.0.0.1:8081' => ['HTTP/1.1 200 OK'],
166+
];
167+
168+
$runner = new ScriptDockerNayraTraitTestHarness();
169+
$result = $runner->handleNayraDocker('<?php return [];', ['foo' => 'bar'], [], 30, ['API_TOKEN=test-token']);
170+
171+
$this->assertSame('{"status":"ok"}', $result);
172+
$this->assertSame('http://127.0.0.1:8081/run_script', ScriptDockerNayraTraitFunctionState::$curlUrl);
173+
$this->assertSame(['http://127.0.0.1:8081'], ScriptDockerNayraTraitFunctionState::$requestedHeaders);
174+
$this->assertSame(0, $runner->bringUpNayraCalls);
175+
}
176+
177+
public function testConfiguredRestApiHostTakesPriorityOverCachedDockerAddress()
178+
{
179+
config(['app.nayra_rest_api_host' => 'http://127.0.0.1:8081']);
180+
ScriptDockerNayraTraitTestHarness::setNayraAddresses(['172.18.0.5']);
181+
ScriptDockerNayraTraitFunctionState::$enabled = true;
182+
ScriptDockerNayraTraitFunctionState::$headers = [
183+
'http://127.0.0.1:8081' => ['HTTP/1.1 200 OK'],
184+
];
185+
186+
$runner = new ScriptDockerNayraTraitTestHarness();
187+
$runner->handleNayraDocker('<?php return [];', [], [], 30, []);
188+
189+
$this->assertSame('http://127.0.0.1:8081/run_script', ScriptDockerNayraTraitFunctionState::$curlUrl);
190+
$this->assertSame(0, $runner->bringUpNayraCalls);
191+
}
192+
193+
public function testNayraBaseUrlFallsBackToCachedDockerAddressWithoutRestApiHost()
194+
{
195+
ScriptDockerNayraTraitTestHarness::setNayraAddresses(['172.18.0.5']);
196+
197+
$runner = new ScriptDockerNayraTraitTestHarness();
198+
199+
$this->assertSame('http://172.18.0.5:8081', $runner->exposedResolveNayraBaseUrl());
200+
$this->assertSame(0, $runner->bringUpNayraCalls);
201+
}
202+
203+
public function testNayraBaseUrlStartsDockerBeforeResolvingUrlWhenNoRestApiHostOrCachedAddressExists()
204+
{
205+
$runner = new ScriptDockerNayraTraitTestHarness();
206+
207+
$this->assertSame('http://172.18.0.9:8081', $runner->exposedResolveNayraBaseUrl());
208+
$this->assertSame(1, $runner->bringUpNayraCalls);
209+
$this->assertSame([false], $runner->bringUpNayraRestartValues);
210+
}
211+
212+
public function testConfiguredRestApiHostConnectionFailureDoesNotStartTenantDockerContainer()
213+
{
214+
config(['app.nayra_rest_api_host' => 'http://127.0.0.1:8081']);
215+
ScriptDockerNayraTraitFunctionState::$enabled = true;
216+
ScriptDockerNayraTraitFunctionState::$headers = [
217+
'http://127.0.0.1:8081' => false,
218+
];
219+
220+
$runner = new ScriptDockerNayraTraitTestHarness();
221+
222+
try {
223+
$runner->handleNayraDocker('<?php return [];', [], [], 30, []);
224+
$this->fail('Expected a ScriptException when the configured Nayra REST API host is unavailable.');
225+
} catch (ScriptException $exception) {
226+
$this->assertStringContainsString(
227+
'Could not connect to the configured Nayra REST API host: http://127.0.0.1:8081',
228+
$exception->getMessage()
229+
);
230+
}
231+
232+
$this->assertSame(0, $runner->bringUpNayraCalls);
233+
$this->assertNull(ScriptDockerNayraTraitFunctionState::$curlUrl);
234+
}
235+
}

0 commit comments

Comments
 (0)