Skip to content

Commit 58ae4a0

Browse files
committed
Merge branch 'master' of github.com:spryker/docker-sdk into feature/frw-11487/master-rmq-42-rollout
2 parents f38f0c6 + a43b6b8 commit 58ae4a0

12 files changed

Lines changed: 335 additions & 18 deletions

File tree

.github/workflows/trivy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- name: Checkout code
1313
uses: actions/checkout@v3
1414
- name: Scan for secrets in the repository
15-
uses: aquasecurity/trivy-action@0.28.0
15+
uses: aquasecurity/trivy-action@0.35.0
1616
with:
1717
scan-type: 'fs' # File system scan
1818
trivy-config: .trivy/trivy.yaml # Path to the Trivy config file

bin/sdk/compose.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,9 @@ function Compose::restart() {
195195
function Compose::stop() {
196196
Console::verbose "${INFO}Stopping all containers${NC}"
197197
Compose::command stop
198-
Compose::command stop mutagen
198+
if Service::isServiceExist mutagen; then
199+
Compose::command stop mutagen
200+
fi
199201
Registry::Flow::runAfterStop
200202
}
201203

bin/sdk/mount/mutagen.sh

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,16 +287,43 @@ function Mount::Mutagen::createSyncSession() {
287287
}
288288

289289
# This is necessary due to https://github.com/mutagen-io/mutagen/issues/225
290+
function Mount::Mutagen::waitForSessionReady() {
291+
local sessionName="${1:-${SPRYKER_SYNC_SESSION_NAME}}"
292+
local maxWaitSeconds="${2:-300}"
293+
local intervalSeconds=3
294+
local elapsed=0
295+
local status
296+
297+
Console::verbose "${INFO}Waiting for mutagen sync session to finish initial scan...${NC}"
298+
299+
while [ "${elapsed}" -lt "${maxWaitSeconds}" ]; do
300+
status=$(mutagen sync list "${sessionName}" 2>/dev/null | grep 'Status:' | sed 's/.*Status: //' || echo '')
301+
302+
if echo "${status}" | grep -qi "Watching for changes\|Synchronized"; then
303+
Console::verbose "${INFO}Mutagen sync session ready (${status})${NC}"
304+
return 0
305+
fi
306+
307+
Console::verbose "${INFO}Mutagen status: ${status} (${elapsed}s elapsed)${NC}"
308+
sleep "${intervalSeconds}"
309+
elapsed=$((elapsed + intervalSeconds))
310+
done
311+
312+
Console::warn "Mutagen session did not reach ready state within ${maxWaitSeconds}s (last status: ${status}). Proceeding anyway."
313+
return 0
314+
}
315+
290316
function Mount::Mutagen::afterCliReady() {
291317
if ! Mount::Mutagen::createSyncSession; then
292318
Console::warn "Mutagen sync session creation failed or timed out. Boot will continue."
293319
Console::warn "You can manually create the session later or retry after fixing Mutagen issues."
294320
return 0
295321
fi
296-
322+
297323
if Mount::Mutagen::sessionExists; then
324+
Mount::Mutagen::waitForSessionReady
298325
Console::verbose "${INFO}Flushing file syncronization${NC}"
299-
Mount::Mutagen::runWithTimeout 10 mutagen sync flush "${SPRYKER_SYNC_SESSION_NAME}" 2>/dev/null || true
326+
Mount::Mutagen::runWithTimeout 60 mutagen sync flush "${SPRYKER_SYNC_SESSION_NAME}" 2>/dev/null || true
300327
fi
301328
}
302329

context/dashboard/package-lock.json

Lines changed: 14 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
HOST="${HOST:-localhost}"
5+
PORT="${PORT:-8080}"
6+
7+
# === marker & token produced by Groovy ===
8+
BOOTSTRAP_DIR="/root/.jenkins/secrets/bootstrap"
9+
MARKER_FILE="${BOOTSTRAP_DIR}/.token_ready"
10+
SPRYKER_SCHEDULER_USER="${SPRYKER_SCHEDULER_USER:-}" # optional; will auto-detect if empty
11+
TOKEN_FILE="${BOOTSTRAP_DIR}/${SPRYKER_SCHEDULER_USER:-}.token"
12+
13+
# Will be filled after reading token
14+
AUTH_CURL=()
15+
TOKEN_VALUE=""
16+
17+
# --- helpers (auth-aware once AUTH_CURL is set) ---
18+
getCrumb() {
19+
# Returns 'Jenkins-Crumb:<crumb>' or empty if endpoint not enabled
20+
curl -sf "http://${HOST}:${PORT}/crumbIssuer/api/json" \
21+
"${AUTH_CURL[@]}" 2>/dev/null \
22+
| jq -r '"Jenkins-Crumb:"+.crumb' 2>/dev/null || true
23+
}
24+
25+
suspendJenkins() {
26+
local crumb
27+
crumb="$(getCrumb || true)"
28+
curl -sfLI -X POST "http://${HOST}:${PORT}/quietDown" \
29+
"${AUTH_CURL[@]}" \
30+
${crumb:+-H "$crumb"} \
31+
|| true
32+
}
33+
34+
countRunningJobs() {
35+
# returns a number (defaults to 0 on error)
36+
curl -sf "http://${HOST}:${PORT}/computer/api/json" \
37+
"${AUTH_CURL[@]}" 2>/dev/null \
38+
| jq -r '.busyExecutors' 2>/dev/null || echo 0
39+
}
40+
41+
waitForFinishOfActiveJobs() {
42+
suspendJenkins
43+
local count
44+
count="$(countRunningJobs || echo 0)"
45+
while [ "${count}" -gt 0 ]; do
46+
echo "Active jobs count: ${count}"
47+
sleep 1
48+
count="$(countRunningJobs || echo 0)"
49+
done
50+
echo "No running jobs. Exiting..."
51+
}
52+
53+
waitForJenkinsToStart() {
54+
local code=000
55+
local url="http://${HOST}:${PORT}/login" # safe endpoint under SSO
56+
57+
echo "Waiting for Jenkins HTTP on ${url} (accept 200/3xx/401/403)..."
58+
until code="$(curl -sS -o /dev/null -w '%{http_code}' -I "$url" || echo 000)"; \
59+
[[ "$code" == "200" || "$code" == "401" || "$code" == "403" || \
60+
"$code" == "301" || "$code" == "302" || "$code" == "303" || \
61+
"$code" == "307" || "$code" == "308" ]]; do
62+
sleep 1
63+
done
64+
echo "Jenkins responded with HTTP ${code} — proceeding."
65+
}
66+
67+
waitForGroovyBootstrap() {
68+
echo "Waiting for Groovy bootstrap marker: ${MARKER_FILE}"
69+
local waited=0
70+
local timeout="${WAIT_TIMEOUT:-300}" # seconds; set 0 to disable
71+
until [ -f "${MARKER_FILE}" ]; do
72+
sleep 1
73+
waited=$((waited+1))
74+
if [ "${timeout}" -gt 0 ] && [ "${waited}" -ge "${timeout}" ]; then
75+
echo "ERROR: Timed out waiting for ${MARKER_FILE}"
76+
exit 1
77+
fi
78+
done
79+
echo "Groovy bootstrap complete."
80+
81+
# Discover token file if username wasn't set
82+
if [ -z "${SPRYKER_SCHEDULER_USER}" ]; then
83+
TOKEN_FILE="$(find "${BOOTSTRAP_DIR}" -maxdepth 1 -type f -name '*.token' | head -n1 || true)"
84+
if [ -z "${TOKEN_FILE}" ]; then
85+
echo "ERROR: No token file found in ${BOOTSTRAP_DIR}"
86+
exit 1
87+
fi
88+
SPRYKER_SCHEDULER_USER="$(basename "${TOKEN_FILE}")"
89+
SPRYKER_SCHEDULER_USER="${SPRYKER_SCHEDULER_USER%.token}"
90+
fi
91+
}
92+
93+
readToken() {
94+
if [ ! -f "${TOKEN_FILE}" ]; then
95+
echo "ERROR: Token file not found: ${TOKEN_FILE}"
96+
exit 1
97+
fi
98+
TOKEN_VALUE="$(awk -F'=' '/^tokenValue=/{print $2; exit}' "${TOKEN_FILE}")"
99+
if [ -z "${TOKEN_VALUE:-}" ]; then
100+
echo "ERROR: tokenValue not present in ${TOKEN_FILE}"
101+
exit 1
102+
fi
103+
echo "Token for user ${SPRYKER_SCHEDULER_USER} loaded from ${TOKEN_FILE}"
104+
105+
# Prepare auth array for curl
106+
local auth_b64
107+
auth_b64="$(printf '%s' "${SPRYKER_SCHEDULER_USER}:${TOKEN_VALUE}" | base64)"
108+
AUTH_CURL=(-H "Authorization: Basic ${auth_b64}")
109+
}
110+
111+
# === main bootstrap ===
112+
mkdir -p ~/.jenkins/updates
113+
rm -rf ~/.jenkins/plugins || echo 'plugins did not exist anyway'
114+
mkdir -p ~/.jenkins/plugins
115+
test -f ~/.jenkins/jenkins.model.JenkinsLocationConfiguration.xml || envsubst < /opt/jenkins.model.JenkinsLocationConfiguration.xml > ~/.jenkins/jenkins.model.JenkinsLocationConfiguration.xml
116+
117+
# On shutdown: drain queue then stop Jenkins
118+
trap 'waitForFinishOfActiveJobs; kill ${pid}; exit 0;' SIGTERM
119+
120+
# Seed plugins from ref
121+
cp -r /usr/share/jenkins/ref/plugins/* /root/.jenkins/plugins/ || true
122+
123+
# Init bootstrap script
124+
HOME_DIR="${JENKINS_HOME:-/root/.jenkins}"
125+
INIT_REF="/usr/share/jenkins/ref/init.groovy.d"
126+
INIT_HOME="${HOME_DIR}/init.groovy.d"
127+
128+
mkdir -p "${INIT_HOME}"
129+
if [ -d "${INIT_REF}" ]; then
130+
# copy only if there are .groovy files; avoid failing when none exist
131+
if find "${INIT_REF}" -maxdepth 1 -type f -name '*.groovy' | read _; then
132+
find "${INIT_REF}" -maxdepth 1 -type f -name '*.groovy' -print -exec cp -f {} "${INIT_HOME}/" \;
133+
fi
134+
fi
135+
echo "Init scripts in HOME (${INIT_HOME}):"
136+
ls -l "${INIT_HOME}" || true
137+
138+
# Start Jenkins (Groovy init runs now and creates the token)
139+
java ${JAVA_OPTS:-} -Djenkins.install.runSetupWizard=false -jar /usr/share/jenkins/jenkins.war ${JENKINS_OPTS:-} & pid=$!
140+
141+
# First wait: HTTP up (no auth yet)
142+
waitForJenkinsToStart
143+
echo "HTTP port ${PORT} on ${HOST} all started up.."
144+
145+
# Wait for Groovy to finish and write the marker + token
146+
waitForGroovyBootstrap
147+
readToken
148+
149+
# Keep PID 1 alive
150+
wait "${pid}"

docs/07-deploy-file/02-deploy.file.reference.v1.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ services:
628628
scheduler:
629629
engine: jenkins
630630
version: 2.176
631+
number-of-executors: 4
631632
endpoints:
632633
scheduler.spryker.local:
633634
@@ -836,6 +837,67 @@ docker:
836837
Now you can access the applications from the `{ IP address 1 }` and `{ IP address 2 }` IP addresses.
837838

838839

840+
### Per-store and per-region maintenance pages
841+
842+
By default, all endpoints of an application share the same maintenance page located at `public/{application}/maintenance/index.html` (e.g., `public/Yves/maintenance/index.html`).
843+
844+
You can customize the maintenance page per store or per region by placing an `index.html` file in a subdirectory named after the store or region code:
845+
846+
```
847+
public/Yves/maintenance/
848+
├── index.html # Default maintenance page (fallback)
849+
├── EU/
850+
│ └── index.html # Maintenance page for EU region
851+
├── US/
852+
│ └── index.html # Maintenance page for US region
853+
├── DE/
854+
│ └── index.html # Maintenance page for DE store (legacy store mode)
855+
└── AT/
856+
└── index.html # Maintenance page for AT store (legacy store mode)
857+
```
858+
859+
The same structure applies to all applications (`Backoffice`, `MerchantPortal`, `Zed`, etc.).
860+
861+
Nginx resolves the maintenance page using the following fallback order:
862+
863+
**Dynamic store mode** (region-based endpoints):
864+
1. `maintenance/{region}/index.html` — region-specific page
865+
2. `maintenance/index.html` — default page
866+
867+
**Legacy store mode** (store-based endpoints):
868+
1. `maintenance/{store}/index.html` — store-specific page
869+
2. `maintenance/{region}/index.html` — region-specific page
870+
3. `maintenance/index.html` — default page
871+
872+
If no store-specific or region-specific page exists, the default `maintenance/index.html` is served. The default maintenance page is required and must always be present.
873+
874+
#### Testing maintenance pages locally
875+
876+
To verify a maintenance page locally without changing the deploy file, follow these steps:
877+
878+
1. Boot the environment with your deploy file:
879+
```bash
880+
docker/sdk boot {deploy file name}
881+
```
882+
883+
2. Open the generated `docker/deployment/default/docker-compose.yml` and add the `SPRYKER_MAINTENANCE_MODE_ENABLED` environment variable to the `frontend` service:
884+
```yaml
885+
services:
886+
frontend:
887+
image: ...
888+
environment:
889+
SPRYKER_MAINTENANCE_MODE_ENABLED: 1
890+
```
891+
892+
3. Start the environment:
893+
```bash
894+
docker/sdk up
895+
```
896+
897+
4. Open Yves in a browser — the maintenance page should be displayed.
898+
899+
> **Note:** `docker/deployment/default/docker-compose.yml` is a generated file and will be overwritten the next time `docker/sdk boot` is run. This approach is intended for temporary local testing only. Do not commit this change.
900+
839901

840902
### docker: logs:
841903
* `docker: logs: path:` defines the path to the directory with Docker logs. This variable is optional. If not specified, the default value applies: `path: '/var/log/spryker`.
@@ -1083,6 +1145,7 @@ A scheduler *Service* used to run application-specific jobs periodically in the
10831145

10841146
* Project-wide
10851147
* `scheduler: engine:` - possible value is `jenkins`.
1148+
* `scheduler: number-of-executors:` - defines the number of executors for the Jenkins instance. The minimum supported Jenkins version is 2.516.3. This property is relevant only for local development and does not affect the Cloud setup.
10861149
* `scheduler: endpoints:` - defines the service's port and web interface that can be accessed via given endpoints.
10871150

10881151

generator/deploy-file-generator/config/validation.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ services.*.engine:
6868
string-type:
6969
services.*.endpoints:
7070
array-type:
71+
services.scheduler.number-of-executors:
72+
integer-type:
7173

7274
# Docker
7375
docker.ssl.enabled:

generator/src/templates/nginx/conf.d/frontend.default.conf.twig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ server {
4444
zedHost: zedHost,
4545
timeout: applicationData['http']['timeout'] | default('1m'),
4646
project: _context,
47-
regionEndpointMap: _context['regionEndpointMap'][endpointData['identifier']]
47+
regionEndpointMap: _context['regionEndpointMap'][endpointData['identifier']],
48+
groupRegion: groupData['region'],
4849
} %}
4950
{% endfor %}
5051
{% endfor %}

generator/src/templates/nginx/http/application.server.conf.twig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,12 @@
5656
fastcgi_param SPRYKER_JENKINS_CSRF_PROTECTION_ENABLED {{ (services['scheduler']['csrf-protection-enabled'] | default(false)) ? 1 : 0 }};
5757
{% endblock location %}
5858
}
59+
60+
location @maintenance {
61+
{% if endpointData['region'] is defined %}
62+
try_files /maintenance/{{ endpointData['identifier'] }}/index.html /maintenance/index.html =503;
63+
{% else %}
64+
try_files /maintenance/{{ endpointData['identifier'] }}/index.html /maintenance/{{ groupRegion }}/index.html /maintenance/index.html =503;
65+
{% endif %}
66+
}
5967
{% endblock locations %}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 422 425 426 428 429 431 451 /errorpage/4xx.html;
22
error_page 500 501 502 504 505 506 507 508 509 510 511 /errorpage/5xx.html;
3-
error_page 503 /maintenance/index.html;
3+
error_page 503 @maintenance;

0 commit comments

Comments
 (0)