Skip to content

Commit 7a1ef36

Browse files
author
Radovan Fuchs
committed
Add TLS fixes for konflux run
1 parent 0757895 commit 7a1ef36

10 files changed

Lines changed: 405 additions & 50 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Mock HTTPS OpenAI API for tls.feature (Konflux / Prow; no Docker Compose).
2+
# Llama Stack run.yaml uses https://e2e-mock-tls-inference.<ns>.svc.cluster.local:8443|8444|8445/v1
3+
apiVersion: v1
4+
kind: Pod
5+
metadata:
6+
name: e2e-mock-tls-inference
7+
labels:
8+
app: e2e-mock-tls-inference
9+
spec:
10+
securityContext:
11+
runAsNonRoot: true
12+
seccompProfile:
13+
type: RuntimeDefault
14+
containers:
15+
- name: e2e-mock-tls-inference
16+
image: python:3.12-slim
17+
securityContext:
18+
allowPrivilegeEscalation: false
19+
capabilities:
20+
drop: ["ALL"]
21+
runAsNonRoot: true
22+
runAsUser: 1000
23+
seccompProfile:
24+
type: RuntimeDefault
25+
env:
26+
- name: POD_NAMESPACE
27+
valueFrom:
28+
fieldRef:
29+
fieldPath: metadata.namespace
30+
- name: PYTHONPATH
31+
value: /app:/tmp/pydeps
32+
command:
33+
- /bin/sh
34+
- -c
35+
- |
36+
set -e
37+
pip install --quiet --no-cache-dir --target /tmp/pydeps 'trustme>=1.2.1' 'cryptography>=42.0.0'
38+
NS="${POD_NAMESPACE:-default}"
39+
export TLS_CERT_DNS_NAMES="mock-tls-inference,localhost,127.0.0.1,e2e-mock-tls-inference,e2e-mock-tls-inference.${NS}.svc.cluster.local"
40+
exec python /app/server.py
41+
ports:
42+
- containerPort: 8443
43+
name: tls
44+
- containerPort: 8444
45+
name: mtls
46+
- containerPort: 8445
47+
name: mismatch
48+
volumeMounts:
49+
- name: server-script
50+
mountPath: /app/server.py
51+
subPath: server.py
52+
readOnly: true
53+
- name: certs-work
54+
mountPath: /certs
55+
readinessProbe:
56+
exec:
57+
command:
58+
- python3
59+
- -c
60+
- |
61+
import ssl, urllib.request
62+
ctx = ssl.create_default_context()
63+
ctx.check_hostname = False
64+
ctx.verify_mode = ssl.CERT_NONE
65+
urllib.request.urlopen("https://localhost:8443/health", context=ctx)
66+
initialDelaySeconds: 8
67+
periodSeconds: 5
68+
livenessProbe:
69+
exec:
70+
command:
71+
- python3
72+
- -c
73+
- |
74+
import ssl, urllib.request
75+
ctx = ssl.create_default_context()
76+
ctx.check_hostname = False
77+
ctx.verify_mode = ssl.CERT_NONE
78+
urllib.request.urlopen("https://localhost:8443/health", context=ctx)
79+
initialDelaySeconds: 15
80+
periodSeconds: 20
81+
volumes:
82+
- name: server-script
83+
configMap:
84+
name: e2e-mock-tls-inference-script
85+
- name: certs-work
86+
emptyDir: {}
87+
---
88+
apiVersion: v1
89+
kind: Service
90+
metadata:
91+
name: e2e-mock-tls-inference
92+
spec:
93+
selector:
94+
app: e2e-mock-tls-inference
95+
ports:
96+
- name: tls
97+
port: 8443
98+
targetPort: tls
99+
- name: mtls
100+
port: 8444
101+
targetPort: mtls
102+
- name: mismatch
103+
port: 8445
104+
targetPort: mismatch

tests/e2e-prow/rhoai/manifests/lightspeed/llama-stack-openai.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ spec:
206206
mountPath: /tmp/interception-proxy-ca.pem
207207
subPath: ca.pem
208208
readOnly: true
209+
# tls.feature: client/CA PEMs from Secret e2e-mock-tls-certs (optional).
210+
- name: mock-tls-certs
211+
mountPath: /certs
212+
readOnly: true
209213
volumes:
210214
- name: app-root
211215
emptyDir: {}
@@ -222,3 +226,7 @@ spec:
222226
secret:
223227
secretName: e2e-interception-proxy-ca
224228
optional: true
229+
- name: mock-tls-certs
230+
secret:
231+
secretName: e2e-mock-tls-certs
232+
optional: true

tests/e2e-prow/rhoai/scripts/e2e-ops.sh

Lines changed: 162 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
# disrupt-llama-stack - Delete llama-stack pod to disrupt connection
2626
# deploy-e2e-tunnel-proxy - Deploy in-cluster tunnel proxy (proxy.feature step)
2727
# deploy-e2e-interception-proxy - Deploy in-cluster interception proxy (proxy.feature step)
28+
# deploy-e2e-mock-tls-inference - Deploy mock HTTPS inference server (tls.feature step)
29+
# sync-mock-tls-certs-secret - Publish /certs PEMs to Secret for llama-stack mount
2830

2931
set -e
3032

@@ -331,7 +333,55 @@ cmd_restart_lightspeed() {
331333
echo "✓ Lightspeed restart complete"
332334
}
333335

336+
cmd_reload_llama_stack_config() {
337+
local llama_pod_name="llama-stack-service"
338+
local tmp
339+
340+
echo "===== Reloading llama-stack run.yaml (container restart, no pod recreate) ====="
341+
tmp=$(mktemp)
342+
if ! oc get configmap llama-stack-config -n "$NAMESPACE" \
343+
-o jsonpath='{.data.run\.yaml}' >"$tmp"; then
344+
rm -f "$tmp"
345+
echo "ERROR: failed to read llama-stack-config run.yaml" >&2
346+
return 1
347+
fi
348+
if [[ ! -s "$tmp" ]]; then
349+
rm -f "$tmp"
350+
echo "ERROR: llama-stack-config run.yaml is empty" >&2
351+
return 1
352+
fi
353+
if ! oc cp "$tmp" "$NAMESPACE/$llama_pod_name:/opt/app-root/run.yaml" \
354+
-c llama-stack-container; then
355+
rm -f "$tmp"
356+
echo "ERROR: failed to copy run.yaml into llama-stack pod" >&2
357+
return 1
358+
fi
359+
rm -f "$tmp"
360+
echo "Restarting llama-stack-container to pick up run.yaml..."
361+
oc exec -n "$NAMESPACE" "$llama_pod_name" -c llama-stack-container -- bash -c 'kill 1' \
362+
2>/dev/null || true
363+
wait_for_pod "$llama_pod_name" 45
364+
if ! wait_for_llama_stack_http_health 35; then
365+
echo "===== Llama-stack reload FAILED (HTTP not healthy) ====="
366+
return 1
367+
fi
368+
if ! cmd_restart_llama_port_forward; then
369+
echo "ERROR: Llama pod is up but localhost:${LOCAL_LLAMA_PORT:-8321} port-forward failed"
370+
return 1
371+
fi
372+
echo "===== Llama-stack config reload complete ====="
373+
}
374+
334375
cmd_restart_llama_stack() {
376+
if [[ "${E2E_KONFLUX_E2E:-0}" == "1" && "${E2E_LLAMA_RELOAD_CONFIG_ONLY:-0}" == "1" ]]; then
377+
if oc get pod llama-stack-service -n "$NAMESPACE" &>/dev/null; then
378+
if cmd_reload_llama_stack_config; then
379+
return 0
380+
fi
381+
echo "WARN: llama config reload failed; falling back to full pod restart" >&2
382+
fi
383+
fi
384+
335385
echo "===== Restoring llama-stack service ====="
336386
# Pod.spec is largely immutable; delete so apply creates a pod with current volumes/env.
337387
echo "Deleting llama-stack pod (if any) before apply..."
@@ -350,6 +400,14 @@ cmd_restart_llama_stack() {
350400
exit 1
351401
fi
352402
fi
403+
if [[ "${E2E_COPY_MOCK_TLS_CERTS_TO_LLAMA:-0}" == "1" \
404+
&& "${E2E_LLAMA_RELOAD_CONFIG_ONLY:-0}" != "1" ]]; then
405+
echo "[e2e-ops] Syncing e2e-mock-tls-certs secret before llama-stack apply..."
406+
if ! cmd_sync_mock_tls_certs_secret; then
407+
echo "===== Llama-stack restore FAILED (mock TLS certs secret sync) ====="
408+
exit 1
409+
fi
410+
fi
353411
_LLAMA_SVC_FQDN="llama-stack-service-svc.${NAMESPACE}.svc.cluster.local"
354412
oc create secret generic llama-stack-ip-secret \
355413
--from-literal=key="$_LLAMA_SVC_FQDN" \
@@ -365,7 +423,17 @@ cmd_restart_llama_stack() {
365423
exit 1
366424
fi
367425
fi
368-
if ! wait_for_llama_stack_http_health 50; then
426+
if [[ "${E2E_COPY_MOCK_TLS_CERTS_TO_LLAMA:-0}" == "1" ]]; then
427+
if ! _verify_mock_tls_certs_mounted_in_llama; then
428+
echo "===== Llama-stack restore FAILED (mock TLS certs not mounted) ====="
429+
exit 1
430+
fi
431+
fi
432+
local llama_health_attempts=50
433+
if [[ "${E2E_COPY_MOCK_TLS_CERTS_TO_LLAMA:-0}" == "1" ]]; then
434+
llama_health_attempts=75
435+
fi
436+
if ! wait_for_llama_stack_http_health "$llama_health_attempts"; then
369437
echo "===== Llama-stack restore FAILED (HTTP not healthy) ====="
370438
exit 1
371439
fi
@@ -709,6 +777,69 @@ cmd_copy_interception_proxy_ca_to_llama() {
709777
cmd_sync_interception_proxy_ca_secret
710778
}
711779

780+
_MOCK_TLS_CERT_FILES=(
781+
ca.crt
782+
client.crt
783+
client.key
784+
untrusted-ca.crt
785+
expired-ca.crt
786+
untrusted-client.crt
787+
untrusted-client.key
788+
expired-client.crt
789+
)
790+
791+
cmd_sync_mock_tls_certs_secret() {
792+
local mock_pod_name tmpdir f
793+
mock_pod_name=$(oc get pod -n "$NAMESPACE" -l app=e2e-mock-tls-inference \
794+
-o jsonpath='{.items[0].metadata.name}' 2>/dev/null) || mock_pod_name=""
795+
796+
if [[ -z "$mock_pod_name" ]]; then
797+
echo "ERROR: no e2e-mock-tls-inference pod in namespace $NAMESPACE" >&2
798+
echo " Run: e2e-ops.sh deploy-e2e-mock-tls-inference" >&2
799+
return 1
800+
fi
801+
802+
tmpdir=$(mktemp -d)
803+
for f in "${_MOCK_TLS_CERT_FILES[@]}"; do
804+
if ! oc exec -n "$NAMESPACE" "$mock_pod_name" -c e2e-mock-tls-inference -- \
805+
cat "/certs/$f" >"$tmpdir/$f"; then
806+
echo "ERROR: failed to read /certs/$f from e2e-mock-tls-inference pod" >&2
807+
rm -rf "$tmpdir"
808+
return 1
809+
fi
810+
if [[ ! -s "$tmpdir/$f" ]]; then
811+
echo "ERROR: /certs/$f is empty in e2e-mock-tls-inference pod" >&2
812+
rm -rf "$tmpdir"
813+
return 1
814+
fi
815+
done
816+
817+
if ! oc create secret generic e2e-mock-tls-certs \
818+
--from-file="$tmpdir" \
819+
-n "$NAMESPACE" \
820+
--dry-run=client -o yaml | oc apply -f -; then
821+
echo "ERROR: failed to apply e2e-mock-tls-certs secret" >&2
822+
rm -rf "$tmpdir"
823+
return 1
824+
fi
825+
rm -rf "$tmpdir"
826+
echo "✓ Secret e2e-mock-tls-certs updated (${#_MOCK_TLS_CERT_FILES[@]} files)"
827+
}
828+
829+
_verify_mock_tls_certs_mounted_in_llama() {
830+
local llama_pod_name="llama-stack-service"
831+
if oc exec -n "$NAMESPACE" "$llama_pod_name" -c llama-stack-container -- \
832+
sh -c 'test -s /certs/ca.crt && test -s /certs/client.crt && test -s /certs/client.key'; then
833+
echo "✓ mock TLS certs present under /certs in llama-stack"
834+
return 0
835+
fi
836+
echo "ERROR: /certs missing or incomplete in llama-stack pod" >&2
837+
oc get secret e2e-mock-tls-certs -n "$NAMESPACE" 2>&1 || true
838+
oc exec -n "$NAMESPACE" "$llama_pod_name" -c llama-stack-container -- \
839+
ls -la /certs 2>&1 || true
840+
return 1
841+
}
842+
712843
_e2e_repo_root() {
713844
cd "$SCRIPT_DIR/../../../.." && pwd
714845
}
@@ -745,6 +876,28 @@ cmd_deploy_e2e_interception_proxy() {
745876
echo "✓ e2e-interception-proxy ready at http://e2e-interception-proxy.${NAMESPACE}.svc.cluster.local:8889"
746877
}
747878

879+
cmd_deploy_e2e_mock_tls_inference() {
880+
local repo_root
881+
repo_root="$(_e2e_repo_root)"
882+
echo "Deploying e2e-mock-tls-inference in namespace $NAMESPACE..."
883+
oc create configmap e2e-mock-tls-inference-script -n "$NAMESPACE" \
884+
--from-file=server.py="$repo_root/tests/e2e/mock_tls_inference_server/server.py" \
885+
--dry-run=client -o yaml | oc apply -f -
886+
oc delete pod e2e-mock-tls-inference -n "$NAMESPACE" --ignore-not-found=true --wait=true 2>/dev/null || true
887+
oc apply -n "$NAMESPACE" -f "$MANIFEST_DIR/e2e-mock-tls-inference.yaml"
888+
if ! oc wait pod/e2e-mock-tls-inference -n "$NAMESPACE" --for=condition=Ready --timeout=240s; then
889+
echo "ERROR: e2e-mock-tls-inference failed to become ready" >&2
890+
oc describe pod/e2e-mock-tls-inference -n "$NAMESPACE" 2>/dev/null | tail -30 || true
891+
oc logs e2e-mock-tls-inference -n "$NAMESPACE" --tail=40 2>&1 || true
892+
return 1
893+
fi
894+
echo "✓ e2e-mock-tls-inference ready at https://e2e-mock-tls-inference.${NAMESPACE}.svc.cluster.local:8443"
895+
if ! cmd_sync_mock_tls_certs_secret; then
896+
echo "WARNING: mock TLS server is up but e2e-mock-tls-certs secret sync failed" >&2
897+
return 1
898+
fi
899+
}
900+
748901
cmd_disrupt_llama_stack() {
749902
local pod_name="llama-stack-service"
750903

@@ -815,6 +968,12 @@ case "$COMMAND" in
815968
deploy-e2e-interception-proxy)
816969
cmd_deploy_e2e_interception_proxy
817970
;;
971+
deploy-e2e-mock-tls-inference)
972+
cmd_deploy_e2e_mock_tls_inference
973+
;;
974+
sync-mock-tls-certs-secret)
975+
cmd_sync_mock_tls_certs_secret
976+
;;
818977
*)
819978
echo "Usage: $0 <command> [args...]"
820979
echo ""
@@ -833,6 +992,8 @@ case "$COMMAND" in
833992
echo " sync-interception-proxy-ca-secret - Publish trustme CA to Secret for llama mount"
834993
echo " deploy-e2e-tunnel-proxy - Deploy in-cluster tunnel proxy pod"
835994
echo " deploy-e2e-interception-proxy - Deploy in-cluster interception proxy pod"
995+
echo " deploy-e2e-mock-tls-inference - Deploy mock HTTPS inference server (tls.feature)"
996+
echo " sync-mock-tls-certs-secret - Publish mock TLS /certs PEMs to Secret for llama"
836997
exit 1
837998
;;
838999
esac

tests/e2e/configuration/server-mode/lightspeed-stack-tls.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ service:
88
access_log: true
99
llama_stack:
1010
use_as_library_client: false
11-
url: http://llama-stack:8321
11+
url: http://${env.E2E_LLAMA_HOSTNAME}:8321
1212
api_key: xyzzy
1313
user_data_collection:
1414
feedback_enabled: true

tests/e2e/features/environment.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
reset_llama_stack_disrupt_once_tracking,
2727
reset_llama_stack_was_running,
2828
)
29+
from tests.e2e.features.steps.tls import reset_tls_prow_restart_optimization_state
2930
from tests.e2e.utils.llama_stack_utils import register_shield
3031
from tests.e2e.utils.prow_utils import (
3132
restart_pod,
@@ -451,6 +452,8 @@ def before_feature(context: Context, feature: Feature) -> None:
451452
context.active_lightspeed_stack_config_basename = None
452453
# One real Llama disruption per feature (module-level flag; survives context resets)
453454
reset_llama_stack_disrupt_once_tracking()
455+
if feature.filename and "tls.feature" in feature.filename:
456+
reset_tls_prow_restart_optimization_state()
454457

455458
try:
456459
max_flaky = int(os.getenv("E2E_FLAKY_MAX_ATTEMPTS", _E2E_FLAKY_MAX_ATTEMPTS))

tests/e2e/features/steps/proxy.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,8 @@ def restore_if_modified(context: Context) -> None:
295295
_stop_proxy(context, "tunnel_proxy", "proxy_loop")
296296
_stop_proxy(context, "interception_proxy", "interception_proxy_loop")
297297
os.environ.pop("E2E_COPY_INTERCEPTION_CA_TO_LLAMA", None)
298+
os.environ.pop("E2E_COPY_MOCK_TLS_CERTS_TO_LLAMA", None)
299+
os.environ.pop("E2E_LLAMA_RELOAD_CONFIG_ONLY", None)
298300
if hasattr(context, "needs_interception_ca_on_llama"):
299301
delattr(context, "needs_interception_ca_on_llama")
300302

0 commit comments

Comments
 (0)