Commit e5eedd47 authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

feat: enhance portal chart with improved descriptions, configuration, and secrets management

parent 502559ba
Loading
Loading
Loading
Loading
+1 −1
Changes for README.md: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ Intended for local development, integration testing, and demos. **Not for produc
| PostgreSQL | `oop` | Shared instance; one database and role per component |
| AI2 MCP | `oop` | MCP server exposing CAMARA-compliant tools |
| AI2 AI Agent | `oop` | Natural language interface backed by Groq |
| Portal | `oop` | Next.js web frontend for the OOP platform |
| Portal | `oop` | Developer portal: web UI and its backend (login, OEG and AI2 proxy, API clients) |

---

+2 −0
Changes for environments/kind/values.yaml: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -94,6 +94,8 @@ ai2:
portal:
  image:
    pullPolicy: IfNotPresent
  oeg:
    publicUrl: http://localhost:32263


databus:
+3 −4
Changes for oop-platform-chart/charts/portal/Chart.yaml: 3 added lines, 4 removed lines.
Original line number Diff line number Diff line
apiVersion: v2
name: portal
description: Helm chart for the OOP Portal 
description: Helm chart for the OOP Portal (developer portal UI and its backend)
type: application
version: 1.0.0
appVersion: "1.0.0"
appVersion: "2.0.0"
keywords:
  - frontend
  - oop
  - etsi
  - portal
home: https://labs.etsi.org/rep/oop/code/dev-portal
home: https://labs.etsi.org/rep/oop/code/portal
maintainers:
  - name: OOP Team
+37 −76
Changes for oop-platform-chart/charts/portal/README.md: 37 added lines, 76 removed lines.
Original line number Diff line number Diff line
# Portal Helm Chart

Next.js web frontend for the Open Operator Platform (OOP).
Deploys the OOP developer portal: one container in which the backend serves the web UI and
its API (`/api/*`) on the same address, so the login cookies stay first-party.

## Overview
The portal needs, from the umbrella chart:

This Helm chart deploys the **Portal** — a browser-based UI that lets operators
interact with the platform through the OEG northbound API.
- **PostgreSQL**: database and role `portal`, an entry in `postgresql.databases`. An init
  container waits until the role can log in.
- **Keycloak** (unless `global.auth.enabled=false`): the `oop-portal` client logs users in, and
  `oop-portal-provisioner` creates developers' API clients. Their secrets come from the
  `keycloak-credentials` Secret.
- **OEG** and the **AI2 agent**, which the backend forwards `/api/oeg/*` and `/api/ai2/chat` to.

## Prerequisites
## Addresses

- Kubernetes 1.19+
- Helm 3.0+
- OEG deployed and reachable at the configured `config.oegServiceUrl`
Browsers reach the portal and Keycloak on public URLs built from `global.publicHost`, `global.scheme`
and `global.nodePorts`, as the keycloak chart builds them. The backend's own calls to Keycloak use
`global.keycloak.host`/`port` instead, since the public address may not be reachable from pods.

## Installation

When deploying via the OOP umbrella chart this sub-chart is included automatically.
To install it standalone:

```bash
helm install portal . -n oop --create-namespace
```
If you set the keycloak chart's `hostname` or `realms.oop.portal.baseUrl`, set `keycloak.publicUrl`
or `publicUrl` here to match.

## Configuration

| Parameter | Description | Default |
|-----------|-------------|---------|
| `replicaCount` | Number of pod replicas | `1` |
| `image.repository` | Container image repository | `labs.etsi.org:5050/oop/code/dev-portal` |
| `image.tag` | Container image tag | `1.0.0` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
| `config.oegServiceUrl` | In-cluster URL of the OEG service | `http://oeg:80/oeg/1.0.0` |
| `service.type` | Kubernetes service type | `ClusterIP` |
| `service.port` | Service port | `80` |
| `service.targetPort` | Container port (Next.js) | `3000` |
| `service.nodePort` | NodePort value (when `type: NodePort`) | `""` |
| `resources.limits.cpu` | CPU limit | `500m` |
| `resources.limits.memory` | Memory limit | `512Mi` |
| `resources.requests.cpu` | CPU request | `100m` |
| `resources.requests.memory` | Memory request | `256Mi` |

## Kind / local development overrides

The `environments/kind/values.yaml` file exposes the portal on NodePort `30082`:

```yaml
portal:
  image:
    pullPolicy: IfNotPresent
  service:
    type: NodePort
    nodePort: 30082
```

Access the portal at **http://localhost:30082** after deploying on kind.
| `image.repository` | Image repository | `labs.etsi.org:5050/oop/code/portal` |
| `image.tag` | Image tag, also reported as the app version | `2.0.0` |
| `publicUrl` | Address browsers reach the portal on | `<scheme>://<public host>:<NodePort>` |
| `oeg.url` | Where `/api/oeg/*` is forwarded to | `http://oeg:80` |
| `oeg.publicUrl` | OEG address shown with developers' API clients | `""` (not shown) |
| `ai2.chatUrl` | AI2 agent chat endpoint; empty turns the chat off | `http://ai2-ai-agent:9013/groq-mcp` |
| `keycloak.publicUrl` | Keycloak's public URL (token issuer) | `<scheme>://<public host>:<global.nodePorts.keycloak>` |
| `keycloak.existingSecret` | Secret with the client secrets | `keycloak-credentials` |
| `keycloak.provisioner.enabled` | API clients feature | `true` |
| `keycloak.provisioner.oegClientId` | The keycloak chart's `realms.oop.oeg.internalId` | `oeg-client` |
| `database.name` / `database.user` | Database and role | `portal` |
| `database.passwordKey` | Key of the role's password in `global.postgresql.secretName` | `portal-password` |
| `service.type` | Service type | `ClusterIP` (`NodePort` in the umbrella chart) |
| `service.nodePort` | NodePort | `global.nodePorts.portal` |

The API products shown in the portal come from `global.apiProducts`, the same list Keycloak's
roles are built from.

API clients' registration tokens are encrypted with a key generated into the Secret
`portal-credentials` on first install. It is kept on `helm uninstall`, like the database it
belongs with.

## Troubleshooting

```bash
# Check pod status
kubectl get pods -n oop -l app.kubernetes.io/name=portal

# View logs
kubectl logs -f deployment/portal -n oop

# Inspect the ConfigMap
kubectl get configmap -n oop | grep portal
kubectl describe configmap <portal-config-name> -n oop
```

## Upgrade

```bash
helm upgrade oop-platform ./oop-platform-chart \
  -n oop \
  -f environments/kind/values.yaml
```

## Uninstall

Uninstall via the umbrella chart:

```bash
helm uninstall oop-platform -n oop
```

Or disable only the portal without removing the release:

```bash
helm upgrade oop-platform ./oop-platform-chart \
  -n oop \
  -f environments/kind/values.yaml \
  --set portal.enabled=false
kubectl logs deployment/portal -n oop -c wait-for-database
```
+0 −16
Changes for oop-platform-chart/charts/portal/templates/NOTES.txt: 0 added lines, 16 removed lines.
Original line number Diff line number Diff line
Portal frontend has been deployed.

1. Get the application URL by running these commands:
{{- if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "portal.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
  kubectl get --namespace {{ .Release.Namespace }} svc {{ include "portal.fullname" . }} -w
{{- else if contains "ClusterIP" .Values.service.type }}
  kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "portal.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }}
  echo "Visit http://127.0.0.1:{{ .Values.service.port }}"
{{- end }}

OEG_SERVICE_URL is set to: {{ .Values.config.oegServiceUrl }}
Loading