Skip to content

Commit f40018f

Browse files
authored
Merge pull request #40 from linuxfoundation/jme/LFXV2-325
add swagger-ui integration with proper base path support
2 parents 45bb901 + 511a987 commit f40018f

File tree

7 files changed

+308
-0
lines changed

7 files changed

+308
-0
lines changed

.cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"sslmode",
2828
"subchart",
2929
"subcharts",
30+
"swaggerapi",
3031
"tcsh",
3132
"totp",
3233
"traefik",
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Copyright The Linux Foundation and each contributor to LFX.
2+
# SPDX-License-Identifier: MIT
3+
---
4+
{{- if .Values.lfx.swagger_ui.enabled }}
5+
apiVersion: v1
6+
kind: ConfigMap
7+
metadata:
8+
name: swagger-ui-merge-script
9+
namespace: {{ .Release.Namespace }}
10+
labels:
11+
app: swagger_ui
12+
data:
13+
merge-specs.sh: |
14+
#!/bin/sh
15+
set -e
16+
17+
echo "Starting OpenAPI spec merge process..."
18+
19+
# Install openapi-merge-cli and curl
20+
echo "Installing openapi-merge-cli and curl..."
21+
npm install -g openapi-merge-cli
22+
apk add --no-cache curl
23+
24+
# Create temp directory for config
25+
TEMP_DIR="/tmp/specs"
26+
mkdir -p $TEMP_DIR
27+
28+
# Create merge configuration for openapi-merge-cli with URLs
29+
echo '{
30+
"inputs": [
31+
{{- range $index, $spec := .Values.lfx.swagger_ui.specs }}
32+
{{- if $index }},{{- end }}
33+
{
34+
"inputURL": {{ printf "%s/%s" $.Values.lfx.swagger_ui.server $spec | quote }}
35+
}
36+
{{- end }}
37+
],
38+
"output": "shared/openapi-merged.yaml"
39+
}' > $TEMP_DIR/merge-config.json
40+
41+
# Ensure shared directory exists and use openapi-merge-cli to fetch and merge the specs
42+
mkdir -p /shared
43+
# Create symlink in working directory to point to the shared volume
44+
ln -sf /shared $TEMP_DIR/shared
45+
echo "Generated config:"
46+
cat $TEMP_DIR/merge-config.json
47+
48+
# Validate all URLs first - fail if any return 404 or are unreachable
49+
echo "Validating all OpenAPI spec URLs..."
50+
{{- range $index, $spec := .Values.lfx.swagger_ui.specs }}
51+
{{- $fullURL := printf "%s/%s" $.Values.lfx.swagger_ui.server $spec }}
52+
echo "Checking {{ $fullURL }}..."
53+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "{{ $fullURL }}")
54+
if [ "$HTTP_CODE" -ne "200" ]; then
55+
echo "✗ ERROR: {{ $fullURL }} returned HTTP $HTTP_CODE"
56+
exit 1
57+
fi
58+
echo "✓ {{ $fullURL }} is accessible (HTTP 200)"
59+
{{- end }}
60+
61+
echo "Using openapi-merge-cli for fetching and merging..."
62+
cd $TEMP_DIR
63+
openapi-merge-cli --config merge-config.json
64+
65+
echo "OpenAPI spec merge completed!"
66+
67+
# Install yq for YAML manipulation
68+
apk add --no-cache yq
69+
70+
# Remove the server component so we can add our own
71+
yq eval 'del(.servers)' -i /shared/openapi-merged.yaml
72+
73+
yq eval '.servers = [{"url": "{{ .Values.lfx.swagger_ui.server }}", "description": "Default api server"}]' -i /shared/openapi-merged.yaml
74+
75+
{{- if .Values.lfx.swagger_ui.auth.enabled }}
76+
# Add OAuth2 security scheme to the merged spec
77+
echo "Adding OIDC configuration to merged spec..."
78+
79+
# Merge the auth config into the OpenAPI spec using direct yq operations
80+
echo "Merging auth config with OpenAPI spec..."
81+
82+
# Add components.securitySchemes to the spec with client ID
83+
# https://auth.k8s.orb.local/api/oidc/authorization
84+
yq eval '.components.securitySchemes.oidc = {"type": "oauth2", "flows": {"implicit": {"authorizationUrl": "{{ .Values.lfx.swagger_ui.auth.authorizationUrl }}", "scopes": {"api:access": "Access to the API"}}}}' -i /shared/openapi-merged.yaml
85+
86+
87+
# Remove global security requirement (endpoints have their own security)
88+
yq eval 'del(.security)' -i /shared/openapi-merged.yaml
89+
90+
# Add oidc as an alternative security option to all endpoints
91+
yq eval '.paths[].*.security += [{"oidc": ["api:access"]}]' -i /shared/openapi-merged.yaml
92+
93+
echo "✓ oidc configuration added to OpenAPI spec"
94+
{{- end }}
95+
96+
echo "Contents of /shared/:"
97+
ls -la /shared/
98+
if [ -f "/shared/openapi-merged.yaml" ]; then
99+
echo "✓ openapi-merged.yaml exists!"
100+
echo "File size: $(wc -c < /shared/openapi-merged.yaml) bytes"
101+
echo "First few lines:"
102+
head -10 /shared/openapi-merged.yaml
103+
else
104+
echo "✗ openapi-merged.yaml NOT found!"
105+
fi
106+
{{- end }}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright The Linux Foundation and each contributor to LFX.
2+
# SPDX-License-Identifier: MIT
3+
---
4+
{{- if .Values.lfx.swagger_ui.enabled }}
5+
apiVersion: apps/v1
6+
kind: Deployment
7+
metadata:
8+
name: swagger-ui
9+
namespace: {{ .Release.Namespace }}
10+
labels:
11+
app: swagger-ui
12+
spec:
13+
replicas: 1
14+
selector:
15+
matchLabels:
16+
app: swagger-ui
17+
template:
18+
metadata:
19+
labels:
20+
app: swagger-ui
21+
spec:
22+
initContainers:
23+
- name: spec-merger
24+
image: {{ .Values.lfx.swagger_ui.merger.image }}:{{ .Values.lfx.swagger_ui.merger.tag }}
25+
command:
26+
- /bin/sh
27+
- /scripts/merge-specs.sh
28+
volumeMounts:
29+
- name: shared-volume
30+
mountPath: /shared
31+
- name: merge-script
32+
mountPath: /scripts
33+
resources:
34+
requests:
35+
memory: "64Mi"
36+
cpu: "100m"
37+
limits:
38+
memory: "128Mi"
39+
cpu: "200m"
40+
containers:
41+
- name: swagger-ui
42+
image: {{ .Values.lfx.swagger_ui.image }}:{{ .Values.lfx.swagger_ui.tag }}
43+
ports:
44+
- name: http
45+
containerPort: 8080
46+
volumeMounts:
47+
- name: shared-volume
48+
mountPath: /usr/share/nginx/html/spec
49+
env:
50+
- name: SWAGGER_JSON_URL
51+
value: "spec/openapi-merged.yaml"
52+
- name: OAUTH_CLIENT_ID
53+
value: {{ .Values.lfx.swagger_ui.auth.clientId | quote }}
54+
resources:
55+
requests:
56+
memory: "64Mi"
57+
cpu: "100m"
58+
limits:
59+
memory: "128Mi"
60+
cpu: "200m"
61+
readinessProbe:
62+
httpGet:
63+
path: /
64+
port: http
65+
initialDelaySeconds: 5
66+
periodSeconds: 10
67+
livenessProbe:
68+
httpGet:
69+
path: /
70+
port: http
71+
initialDelaySeconds: 15
72+
periodSeconds: 20
73+
volumes:
74+
- name: shared-volume
75+
emptyDir: {}
76+
- name: merge-script
77+
configMap:
78+
name: swagger-ui-merge-script
79+
defaultMode: 0755
80+
{{- end }}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Copyright The Linux Foundation and each contributor to LFX.
2+
# SPDX-License-Identifier: MIT
3+
---
4+
{{- if and .Values.lfx.swagger_ui.enabled (or .Values.gateway.enabled .Values.lfx.parentGateway.enabled) }}
5+
apiVersion: gateway.networking.k8s.io/v1
6+
kind: HTTPRoute
7+
metadata:
8+
name: swagger-ui
9+
namespace: {{ .Release.Namespace }}
10+
spec:
11+
parentRefs:
12+
{{- if .Values.gateway.enabled }}
13+
- name: {{ .Values.gateway.name | default "lfx-platform-gateway" }}
14+
sectionName: {{ include "lfx-platform.default-listener" . }}
15+
namespace: {{ .Release.Namespace }}
16+
{{- else }}
17+
- name: {{ .Values.lfx.parentGateway.name }}
18+
sectionName: {{ .Values.lfx.parentGateway.sectionName }}
19+
namespace: {{ .Values.lfx.parentGateway.namespace }}
20+
{{- end }}
21+
hostnames:
22+
- "lfx-api.{{ .Values.lfx.domain }}"
23+
rules:
24+
- matches:
25+
- path:
26+
type: PathPrefix
27+
value: /docs
28+
filters:
29+
{{- if and .Values.heimdall.enabled .Values.lfx.swagger_ui.auth.enabled }}
30+
- type: ExtensionRef
31+
extensionRef:
32+
group: traefik.io
33+
kind: Middleware
34+
name: heimdall
35+
{{- end }}
36+
- type: URLRewrite
37+
urlRewrite:
38+
path:
39+
type: ReplacePrefixMatch
40+
replacePrefixMatch: /
41+
backendRefs:
42+
- name: swagger-ui
43+
port: 80
44+
{{- end }}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright The Linux Foundation and each contributor to LFX.
2+
# SPDX-License-Identifier: MIT
3+
---
4+
{{- if and .Values.lfx.swagger_ui.enabled .Values.heimdall.enabled }}
5+
apiVersion: heimdall.dadrus.github.com/v1alpha4
6+
kind: RuleSet
7+
metadata:
8+
name: lfx-swagger-ui
9+
namespace: {{ .Release.Namespace }}
10+
spec:
11+
rules:
12+
- id: "rule:lfx:swagger_ui:public"
13+
match:
14+
methods:
15+
- GET
16+
routes:
17+
- path: /docs/
18+
- path: /docs/**
19+
execute:
20+
- authorizer: allow_all
21+
{{- end }}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright The Linux Foundation and each contributor to LFX.
2+
# SPDX-License-Identifier: MIT
3+
---
4+
{{- if .Values.lfx.swagger_ui.enabled }}
5+
apiVersion: v1
6+
kind: Service
7+
metadata:
8+
name: swagger-ui
9+
namespace: {{ .Release.Namespace }}
10+
labels:
11+
app: swagger-ui
12+
spec:
13+
ports:
14+
- name: http
15+
port: 80
16+
targetPort: 8080
17+
selector:
18+
app: swagger-ui
19+
{{- end }}

charts/lfx-platform/values.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@ lfx:
1919
whoami:
2020
enabled: true
2121

22+
swagger_ui:
23+
enabled: true
24+
image: swaggerapi/swagger-ui
25+
tag: latest
26+
merger:
27+
image: node
28+
tag: 24-alpine
29+
auth:
30+
enabled: true
31+
domain: "https://auth.k8s.orb.local"
32+
authorizationUrl: "https://auth.k8s.orb.local/api/oidc/authorization"
33+
clientId: "docs"
34+
server: "http://lfx-api.k8s.orb.local"
35+
specs:
36+
- "_projects/openapi3.yaml"
37+
- "_query/openapi3.yaml"
38+
2239
# Tells rulesets to use the oidc_contextualizer, needed for
2340
# local dev with authelia
2441
use_oidc_contextualizer: true
@@ -427,6 +444,26 @@ authelia:
427444
- refresh_token
428445
authorization_policy: one_factor
429446
token_endpoint_auth_method: client_secret_basic
447+
- client_id: docs
448+
client_name: LFX Swagger UI Docs
449+
public: true
450+
redirect_uris:
451+
- "http://lfx-api.k8s.orb.local/docs/oauth2-redirect.html"
452+
- "https://lfx-api.k8s.orb.local/docs/oauth2-redirect.html"
453+
scopes:
454+
- openid
455+
- email
456+
- profile
457+
- api:access
458+
audience:
459+
- "http://lfx-api.k8s.orb.local"
460+
grant_types:
461+
- implicit
462+
authorization_policy: one_factor
463+
response_types:
464+
- code
465+
- id_token
466+
- token
430467

431468
authelia_generate_jwks:
432469
enabled: true

0 commit comments

Comments
 (0)