Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

### Fixed

### Added
- Migrate Python Flask Quickstarter to FastAPI ([#1170](https://github.com/opendevstack/ods-quickstarters/issues/1170))

## [4.13.1] - 2026-07-30
### Fixed
- Fix jenkins agents python issues with UV ([#1167](https://github.com/opendevstack/ods-quickstarters/pull/1167))
Expand Down
24 changes: 24 additions & 0 deletions be-python-fast-api/Chart.yaml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: v2
name: @component_id@
description: A Helm chart for Kubernetes

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.0.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.0.0"
15 changes: 10 additions & 5 deletions be-python-flask/Jenkinsfile → be-python-fast-api/Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@ odsQuickstarterPipeline(

odsQuickstarterStageCopyFiles(context)

odsQuickstarterStageCreateOpenShiftResources(
context,
[directory: 'common/ocp-config/component-environment']
)

odsQuickstarterStageRenderJenkinsfile(context)

odsQuickstarterStageRenderSonarProperties(context)

renderHelmChart(context)
}

def renderHelmChart(def context) {
def relativeSourceFilePath = "Chart.yaml.template"
def relativeDestinationFilePath = "chart/Chart.yaml"
def absoluteSourceFilePath = "${context.sourceDir}/${relativeSourceFilePath}"
def absoluteDestinationFilePath = "${context.targetDir}/${relativeDestinationFilePath}"
sh(script: "sed 's|@component_id@|${context.componentId}|g' ${absoluteSourceFilePath} > ${absoluteDestinationFilePath}", label: "Render Helm Chart.yaml file")
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ odsComponentPipeline(
]
])
}
odsComponentStageRolloutOpenShiftDeployment(context)
def releaseName = context.componentId
def componentId = context.componentId
odsComponentStageRolloutOpenShiftDeployment(context, [
'selector': "app.kubernetes.io/instance=${releaseName},app.kubernetes.io/name=${componentId}",
'helmEnvBasedValuesFiles': ["values.env.yaml"],
'helmReleaseName': releaseName
])
}

def stageTestSuite(def context) {
Expand Down
65 changes: 65 additions & 0 deletions be-python-fast-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Python FastAPI Quickstarter (be-python-fast-api)

Documentation is located in our [official documentation](https://www.opendevstack.org/ods-documentation/ods-quickstarters/latest/index.html)

Please update documentation in the [antora page directory](https://github.com/opendevstack/ods-quickstarters/tree/master/docs/modules/ROOT/pages)

Tested thru [automated tests](../tests/be-python-flask)

## Purpose

This Quickstarter creates a Python backend service using [FastAPI](https://fastapi.tiangolo.com/) served by [Uvicorn](https://www.uvicorn.org/). It includes a Helm chart for deployment on OpenShift/Kubernetes.

## Folder structure and important files

- `src/`: Application source code
- `src/main.py`: FastAPI application entry point with `/` and `/health` endpoints
- `tests/`: Unit tests using pytest and FastAPI's TestClient
- `docker/`: Files for building the container image
- `docker/Dockerfile`: Container definition (UBI9/Python 3.12 base)
- `docker/run.sh`: Starts the app with `uvicorn`
- `requirements.txt`: Production dependencies (fastapi, uvicorn)
- `tests_requirements.txt`: Test dependencies (pytest, mypy, flake8, httpx)
- `chart/`: Helm chart for deploying the component
- `chart/values.yaml`: Default values (resources, probes, service config)
- `chart/values.dev.yaml`: Overrides for the `dev` environment
- `chart/values.test.yaml`: Overrides for the `test` environment (2 replicas)
- `chart/values.prod.yaml`: Overrides for the `prod` environment (2 replicas)

## Testing locally

### Running unit tests

```bash
python3.12 -m venv venv
. venv/bin/activate
pip install -r tests_requirements.txt
PYTHONPATH=src python3.12 -m pytest tests/
```

### Running the application locally

```bash
. venv/bin/activate
PYTHONPATH=src uvicorn main:app --reload --port 8080
```

### Building the container

```bash
cp -r src docker/app
cp requirements.txt docker/app
docker build -t testing/my-component:$(git rev-parse --short=8 HEAD) docker/
```

### Helm chart linting

```bash
helm lint chart/
```

### Helm chart template processing test

```bash
helm --debug template chart/ --set image.path=testing --set image.name=my-component --set image.tag=$(git rev-parse --short=8 HEAD)
```
File renamed without changes.
23 changes: 23 additions & 0 deletions be-python-fast-api/files/chart/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
26 changes: 26 additions & 0 deletions be-python-fast-api/files/chart/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# IMPORTANT: Content will be recreated from the Chart.yaml.template file by the Jenkins shared library provision job
# NOTE: The content is provided for testing purposes
apiVersion: v2
name: Your helm chart
description: A Helm chart for Kubernetes

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.0.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.0.0"
10 changes: 10 additions & 0 deletions be-python-fast-api/files/chart/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Component '{{ include "chart.fullname" . }}' on version '{{ .Values.imageTag }}' released with Helm!
{{- if .Values.ingress.enabled }}
The component is exposed via the following routes:
{{- $appUrl := .Values.appUrl -}}
{{- range .Values.ingress.hosts }}
{{ printf "https://%s" .host }}
{{- end }}
{{- else }}
The component is not exposed.
{{- end }}
51 changes: 51 additions & 0 deletions be-python-fast-api/files/chart/templates/_affinity.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{{/*
Part of the ODS helm tpl library

Version: 1.0
*/}}


{{/*
Pod affinity/anti-affinity (soft)

Usage: Include where needed, e.g.
````
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
affinity:
podAntiAffinity: {{- include "common.affinities.pods.soft" . | nindent 10}}
````
*/}}
{{- define "common.affinities.pods.soft" -}}
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchLabels: {{- include "common.matchLabels" . | nindent 10 }}
topologyKey: "kubernetes.io/hostname"
{{- end -}}

{{/*
Pod affinity/anti-affinity (hard)

Usage: Include where needed, e.g.
````
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
affinity:
podAntiAffinity: {{- include "common.affinities.pods.hard" . | nindent 10}}
````
*/}}
{{- define "common.affinities.pods.hard" -}}
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchLabels: {{- include "common.matchLabels" . | nindent 10 }}
topologyKey: "kubernetes.io/hostname"
{{- end -}}
62 changes: 62 additions & 0 deletions be-python-fast-api/files/chart/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "chart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "chart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "chart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "chart.labels" -}}
helm.sh/chart: {{ include "chart.chart" . }}
{{ include "chart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "chart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "chart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "chart.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
19 changes: 19 additions & 0 deletions be-python-fast-api/files/chart/templates/_image.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

{{/*
Part of the ODS helm tpl library

Version: 1.0
*/}}

{{/*
Create an image name from the registry, image path, name and tag.
.Values.registry, .Values.imageNamespace, .Values.componentId and .Values.imageTag are injected by the ODS pipeline on deployment.
If not set, values from .Values.image.registry, .Values.image.path, .Values.image.name and .Values.image.tag are used.
*/}}
{{- define "image.fullname" -}}
{{- if (or .Values.registry .Values.image.registry) }}
{{- printf "%s/%s/%s:%s" (or .Values.registry .Values.image.registry) (or .Values.imageNamespace .Values.image.path) (or .Values.componentId .Values.image.name) (or .Values.imageTag .Values.image.tag ) -}}
{{- else }}
{{- printf "%s/%s:%s" (or .Values.imageNamespace .Values.image.path) (or .Values.componentId .Values.image.name) (or .Values.imageTag .Values.image.tag ) -}}
{{- end }}
{{- end }}
11 changes: 11 additions & 0 deletions be-python-fast-api/files/chart/templates/_labels.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{{/*
Part of the ODS helm tpl library

Version: 1.0
*/}}


{{- define "common.matchLabels" -}}
app.kubernetes.io/name: {{ include "chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
Loading
Loading