FileGrant Infrastructure - Local Setup (OpenShift Local / CRC)

This guide walks you through running the entire FileGrant infrastructure locally on OpenShift Local (CRC) for development and testing purposes.

Overview

This setup runs all services locally without public DNS, SSL certificates, or external Routes. All services are accessed via oc port-forward.

Differences from Production

FeatureProductionLocalhost
DNSPublic domainsNot required
SSL/TLSTLS edge via RouteDisabled
RoutesOpenShift RoutesDisabled (port-forward)
ResourcesFull CPU/memoryReduced for local machines
Logging stackLoki + Alloy + Grafana (full resources)Loki + Alloy + Grafana (reduced resources)
PersistenceLarge volumesSmall volumes (2-5 Gi)

Minimum System Requirements

  • CPU: 4 cores (8 recommended for CRC)
  • RAM: 12 GB (16 GB recommended)
  • Disk: 35 GB of free space

Prerequisites

Installing OpenShift Local (CRC)

  1. Download OpenShift Local (CRC)

    Go to the Red Hat Console — OpenShift Local page (a free Red Hat account is required).

    Download the installer for your operating system:

    • Windows: Download the .msi installer, run it, and follow the wizard. CRC will be added to your PATH automatically.
    • macOS: Download the .pkg installer and run it, or use Homebrew:
      brew install --cask crc
    • Linux (RHEL/Fedora/Ubuntu): Download the .tar.xz archive, extract it, and move the binary to your PATH:
      tar -xvf crc-linux-amd64.tar.xz
      sudo cp crc-linux-*-amd64/crc /usr/local/bin/
      crc version

    On the same page, click Copy pull secret and save it — you will need it when starting CRC for the first time.

  2. Run initial setup and start the cluster

    Initial setup (first time only)
    # Initial setup (first time only)
    crc setup
    
    # Start the cluster with sufficient resources
    crc start --cpus 6 --memory 14336 --disk-size 50
    
    # When prompted, enter your pull secret
  3. Configure your environment

    Configure environment
    eval $(crc oc-env)
    oc login -u kubeadmin -p $(crc console --credentials | grep kubeadmin | awk '{print $NF}')
    oc status
  4. Verify the cluster

    Verify cluster
    oc get nodes
    oc version

External Dependencies

MySQL 8.4.8

The application requires a MySQL database running outside the cluster. Start it with Docker:

Start MySQL with Docker
docker run -d --name mysql -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=rootpassword \
  -e MYSQL_DATABASE=filegrant \
  -e MYSQL_USER=filegrant \
  -e MYSQL_PASSWORD=filegrantpassword \
  -v mysql-data:/var/lib/mysql \
  mysql:8.4.8

Configure Azure Container Registry (ACR) Access

All service images are hosted on Azure Container Registry. Before installing the chart, create the imagePullSecret:

Create project and ACR secret
oc new-project filegrant-local

oc create secret docker-registry acr-secret \
  --docker-server=cybergrantregistry-cuash9ckhse5gcha.azurecr.io \
  --docker-username=<SERVICE_PRINCIPAL_ID> \
  --docker-password=<SERVICE_PRINCIPAL_PASSWORD> \
  -n filegrant-local

Installation (Three-Phase Deploy)

The installation requires 3 phases because the infrastructure has sequential dependencies:

  1. FileGrantAPI and RabbitMQ must start first (they are the core services)
  2. RabbitMQ must be configured (virtual host and first user) before other services can connect
  3. FGLicense must start to perform the initial EEVMS variable setup in storage (without these variables, EEVMS certificates cannot be authorized)
  4. Only after the initial setup can you generate certificates for CGSignalR and PDFProcessing and authorize the EEVMS keys
Deployment flow
Phase 1: Bootstrap - FileGrantAPI + RabbitMQ + FGLicense
  |
  +-- Prepare values-secrets.yaml (without EEVMS certificates)
  +-- helm install (only FileGrantAPI, RabbitMQ, FGLicense)
  +-- Wait for pods to be Running
  +-- Configure RabbitMQ (virtual host + first user)
  +-- FGLicense: initial EEVMS variable setup in storage
  |
Phase 2: Generate certificates and authorize EEVMS
  |
  +-- Generate PFX certificates for CGSignalR and PDFProcessing
  +-- Update values-secrets.yaml with certificates
  +-- Port-forward FileGrantAPI
  +-- Authorize EEVMS keys
  |
Phase 3: Enable all services
  |
  +-- helm upgrade (CGSignalR and PDFProcessing enabled)
  +-- CGSignalR and PDFProcessing start and load secrets from EEVMS
  +-- Final verification

Step 1: Create the Initial values-secrets.yaml

Create a values-secrets.yaml file with secrets for the bootstrap services. Do not commit this file to version control (it is already in .gitignore).

EEVMS Certificates

At this stage, EEVMS certificates for CGSignalR and PDFProcessing are not needed yet. They will be added in Phase 2.

Generate initial values-secrets.yaml
cat > values-secrets.yaml << EOF
global:
  editorApiKey: "<EDITOR_API_KEY>"

filegrantapi:
  secrets:
    masterCertificateBase64: "<MASTER_CERT_BASE64>"
    masterCertificatePassword: "<MASTER_CERT_PASSWORD>"
    secretsAzureConnectionString: "<AZURE_BLOB_CONNECTION_STRING>"

fglicense:
  secrets:
    monitoringApiKey: "<MONITORING_API_KEY>"
    grafanaToken: "<GRAFANA_TOKEN>"

filegrantfe:
  env:
    pdfProcessingBaseUrl: "<TO_BE_DEFINED>"
    officeExcelIconUrl: "<TO_BE_DEFINED>"
    officeWordIconUrl: "<TO_BE_DEFINED>"
    officeWopisourceUrl: "<TO_BE_DEFINED>"
    officeWopitestUrl: "<TO_BE_DEFINED>"
    officePowerpointUrl: "<TO_BE_DEFINED>"
    officeExcelUrl: "<TO_BE_DEFINED>"
    officeWordUrl: "<TO_BE_DEFINED>"
    stripePublicKey: "<TO_BE_DEFINED>"
    cryptoKey: "<TO_BE_DEFINED>"
    remotegrantAgentBaseUrl: "<TO_BE_DEFINED>"
    apiBaseUrl: "<TO_BE_DEFINED>"
    azureResourcesContainer: "<TO_BE_DEFINED>"
    wasmModuleBytes: "0,97,115,109,..."
    websocketUrl: "<TO_BE_DEFINED>"
    reactPdfLicenseKey: "<TO_BE_DEFINED>"
EOF

Replace the placeholders with actual values:

PlaceholderValueNotes
<EDITOR_API_KEY>e.g. eevms-migrate-2026-temp-keyShared between FileGrantAPI and FGLicense
<MASTER_CERT_BASE64>EEVMS master certificateBase64 of the master PFX
<MASTER_CERT_PASSWORD>Master certificate password
<AZURE_BLOB_CONNECTION_STRING>Azure Blob connection stringFor EEVMS secrets storage
<MONITORING_API_KEY>e.g. Secret!Shared API key for health checks between services
<GRAFANA_TOKEN>e.g. glsa_BQ9fRqh5Aq...Grafana service account token
<TO_BE_DEFINED> (frontend variables)See Frontend Variables table belowEnvironment variables for the frontend

Other FGLicense Variables

Other FGLicense variables (monitoring URLs, Grafana configuration) are already configured in values-localhost.yaml with internal cluster URLs (http://filegrantapi:8080, http://cgsignalr:8080, etc.).

Step 2: Phase 1 - Install Bootstrap Services

Install the chart with only FileGrantAPI, RabbitMQ, and FGLicense enabled. CGSignalR and PDFProcessing are disabled because the EEVMS variables do not exist yet:

Helm install (Phase 1)
helm install filegrant . \
  --namespace filegrant-local \
  --create-namespace \
  -f values-localhost.yaml \
  -f values-secrets.yaml \
  --set cgsignalr.enabled=false \
  --set filegrantpdfprocessing.enabled=false

Step 3: Wait for Pods to Be Running

Watch pods
oc get pods -n filegrant-local -w

Wait until filegrantapi, rabbitmq, and fglicense are in Running state with READY 1/1:

Expected pod status
NAME                            READY   STATUS    RESTARTS   AGE
rabbitmq-0                      1/1     Running   0          2m
filegrantfe-xxx-yyy             1/1     Running   0          2m
filegrantapi-xxx-yyy            1/1     Running   0          2m
fglicense-xxx-yyy               1/1     Running   0          2m
loki-0                          1/1     Running   0          2m
alloy-xxx-yyy                   1/1     Running   0          2m
grafana-xxx-yyy                 1/1     Running   0          2m

Press Ctrl+C to exit the watch.

Step 4: Configure RabbitMQ

RabbitMQ requires virtual host and first application user configuration before other services can connect.

Open a separate terminal and start the port-forward for the management UI:

Port-forward RabbitMQ Management
oc port-forward -n filegrant-local svc/rabbitmq 15672:15672

Open http://localhost:15672 and log in with the credentials configured in values-localhost.yaml (default: admin-rmq / password from the values file).

  1. Create the Virtual Host: go to Admin > Virtual Hosts, create the vhost required for FileGrant (e.g. /filegrant)
  2. Create the application user: go to Admin > Users, create the user that services will use to connect to RabbitMQ
  3. Assign permissions: set the user permissions on the created virtual host (configure, write, read: .*)

Step 5: FGLicense - Initial EEVMS Variable Setup

FGLicense must perform the initial setup to create all required variables in the EEVMS storage. Without this step, EEVMS certificates cannot be authorized because the variables do not exist yet.

Open a separate terminal and start the port-forward for FGLicense:

Port-forward FGLicense
oc port-forward -n filegrant-local svc/fglicense 5003:8080

Access http://localhost:5003 and complete the initial setup. FGLicense will:

  • Create all required variables in the EEVMS storage
  • Set initial configuration values (connection strings, JWT keys, etc.)
  • Prepare the storage for EEVMS certificate authorization

Required Step

This step is mandatory. If skipped, the EEVMS authorization script (Step 8) will fail with not_found errors for all variables.

Step 6: Generate EEVMS Certificates

Now that the variables exist in storage, generate a PFX certificate for each service that uses EEVMS (CGSignalR and PDFProcessing). The certificates are used to authenticate with FileGrantAPI via RSA signature.

Generate certificates
./scripts/generate-eevms-certs.sh

For production, use --password to protect the PFX files:

Generate with password protection
./scripts/generate-eevms-certs.sh --password "A_SECURE_PASSWORD"

Expected output:

Certificate generation output
=============================================
 EEVMS Certificate Generation
=============================================

--- cgsignalr ---
  Private key:     certs/cgsignalr-key.pem
  Certificate:     certs/cgsignalr-cert.pem
  PFX:             certs/cgsignalr.pfx
  PFX base64:      certs/cgsignalr.b64
  Public key:      certs/cgsignalr-pubkey.pem

--- filegrantpdfprocessing ---
  Private key:     certs/filegrantpdfprocessing-key.pem
  Certificate:     certs/filegrantpdfprocessing-cert.pem
  PFX:             certs/filegrantpdfprocessing.pfx
  PFX base64:      certs/filegrantpdfprocessing.b64
  Public key:      certs/filegrantpdfprocessing-pubkey.pem

Step 7: Update values-secrets.yaml with Certificates

Add the generated EEVMS certificates to the values-secrets.yaml file:

Append certificates to values-secrets.yaml
# Read the base64 values of the generated certificates
SIGNALR_CERT=$(cat certs/cgsignalr.b64)
PDFPROC_CERT=$(cat certs/filegrantpdfprocessing.b64)

# Append CGSignalR and PDFProcessing sections to the file
cat >> values-secrets.yaml << EOF

cgsignalr:
  eevms:
    apiSecret: "${SIGNALR_CERT}"
    apiSecretPassword: ""

filegrantpdfprocessing:
  eevms:
    apiSecret: "${PDFPROC_CERT}"
    apiSecretPassword: ""
EOF

Manual Alternative

Alternatively, you can manually edit values-secrets.yaml and add the cgsignalr and filegrantpdfprocessing sections.

Step 8: Port-Forward FileGrantAPI and Authorize EEVMS Keys

Open a separate terminal and start the port-forward for FileGrantAPI:

Port-forward FileGrantAPI
oc port-forward -n filegrant-local svc/filegrantapi 5001:8080

Verify it is accessible:

Verify FileGrantAPI
curl -s http://localhost:5001/api/ver

Run the authorization script. This registers the public keys of the certificates generated in Step 6 in the EEVMS system, so that CGSignalR and PDFProcessing can read the secrets:

Authorize keys
./scripts/authorize-eevms-keys.sh \
  --api-url http://localhost:5001 \
  --api-key "<EDITOR_API_KEY>"

API Key

Use the same editorApiKey from your values-secrets.yaml.

Expected output:

Authorization output
=============================================
 EEVMS Key Authorization
=============================================

--- cgsignalr (alias: cgsignalr) ---
  Authorized:           11
  Already authorized:   0
  Not found:            0
    [+] FILEGRANT-API-JWT-KEY -> authorized
    [+] FILEGRANT-API-JWT-ISSUER -> authorized
    ...

--- filegrantpdfprocessing (alias: filegrantpdfprocessing) ---
  Authorized:           10
  Already authorized:   0
  Not found:            0
    [+] FILEGRANT-MASTER-ENCRYPTED-SYMMETRIC-KEY -> authorized
    ...

Variables Not Found

If some variables show not_found, go back to Step 5 and verify that FGLicense has completed the initial setup. The variables must exist in the EEVMS storage before they can be authorized.

Step 9: Phase 3 - Enable All Services

Now that the keys are authorized and the certificates are in values-secrets.yaml, enable CGSignalR and PDFProcessing:

Helm upgrade (Phase 3)
helm upgrade filegrant . \
  --namespace filegrant-local \
  -f values-localhost.yaml \
  -f values-secrets.yaml

All Services Enabled

Without the --set *.enabled=false flags, all services are enabled by default.

This starts:

  • CGSignalR -- connects to FileGrantAPI via EEVMS and loads 11 secrets
  • PDFProcessing -- connects to FileGrantAPI via EEVMS and loads 10 secrets

Step 10: Verify the Deployment

Verify all pods and logs
# Check that all pods are Running
oc get pods -n filegrant-local

# Check CGSignalR logs (should show "EEVMS: Successfully loaded 11 secrets")
oc logs -n filegrant-local -l app=cgsignalr --tail=20

# Check PDFProcessing logs (should show "EEVMS: Successfully loaded 10 secrets")
oc logs -n filegrant-local -l app=filegrantpdfprocessing --tail=20

# Check FGLicense logs (should start without errors)
oc logs -n filegrant-local -l app=fglicense --tail=20

Expected output:

Expected final pod status
NAME                                     READY   STATUS    RESTARTS   AGE
rabbitmq-0                               1/1     Running   0          10m
filegrantfe-xxx-yyy                      1/1     Running   0          10m
filegrantapi-xxx-yyy                     1/1     Running   0          10m
fglicense-xxx-yyy                        1/1     Running   0          10m
cgsignalr-xxx-yyy                        1/1     Running   0          1m
filegrantpdfprocessing-xxx-yyy           1/1     Running   0          1m
loki-0                                   1/1     Running   0          10m
alloy-xxx-yyy                            1/1     Running   0          10m
grafana-xxx-yyy                          1/1     Running   0          10m

FGLicense: Environment Variables

Secrets (in values-secrets.yaml)

VariableHelm ValueDescription
MONITORING_API_KEYfglicense.secrets.monitoringApiKeyShared API key for health checks
GRAFANA_TOKENfglicense.secrets.grafanaTokenGrafana service account token
EDITOR_API_KEYglobal.editorApiKeyEEVMS admin API key (shared with FileGrantAPI)

Configuration (in values-localhost.yaml)

VariableDefault ValueDescription
FG_APIhttp://filegrantapi:8080FileGrant API URL
MONITORING_SIGNALR_URLhttp://cgsignalr:8080CGSignalR health check
MONITORING_RABBITMQ_URLhttp://rabbitmq:15672RabbitMQ health check
MONITORING_PDF_PROCESSING_URLhttp://filegrantpdfprocessing:8080PDFProcessing health check
MONITORING_FILEGRANT_API_URLhttp://filegrantapi:8080FileGrantAPI health check
MONITORING_LISTMONK_URLhttps://listmonk-dev.cybergrant.ioListmonk health check (external)
MONITORING_FILEGRANT_FE_URLhttp://filegrantfe:8080Frontend health check
GRAFANA_URLhttp://grafana:3000Grafana URL
GRAFANA_LOKI_DATASOURCE_ID1Loki datasource ID in Grafana
GRAFANA_LOKI_LABEL_KEYcontainerLabel key for Loki queries
GRAFANA_LOKI_SERVICE_NAMESapp-filegrant-1|...Service names for Loki queries (pipe-separated)

Override Monitoring URLs

To override a monitoring URL (e.g. point to an external service), use --set:

helm upgrade filegrant . \
  -f values-localhost.yaml \
  -f values-secrets.yaml \
  --set fglicense.env.monitoringSignalrUrl="https://signalr-dev.cybergrant.io"

Environment Variables by Service

FileGrantAPI (EEVMS Server)

VariableTypeDescription
MASTER_CERTIFICATE_BASE64SecretEEVMS master certificate (base64)
MASTER_CERTIFICATE_PASSWORDSecretMaster certificate password
SECRETS_STORAGE_PROVIDERConfigStorage provider (azureblob)
SECRETS_AZURE_CONNECTION_STRINGSecretAzure Blob Storage connection string
SECRETS_AZURE_CONTAINERConfigAzure container name
SECRETS_AZURE_BLOB_NAMEConfigBlob name for encrypted secrets
EDITOR_API_KEYSecretAdmin API key for EEVMS management

CGSignalR (EEVMS Client)

VariableTypeDescription
FILEGRANT_API_URLConfigFileGrant API URL
FILEGRANT_API_SECRETSecretPFX certificate (base64) for EEVMS authentication
FILEGRANT_API_SECRET_PASSWORDSecretPFX password (empty if unprotected)

PDFProcessing (EEVMS Client)

VariableTypeDescription
FILEGRANT_API_URLConfigFileGrant API URL
FILEGRANT_API_SECRETSecretPFX certificate (base64) for EEVMS authentication
FILEGRANT_API_SECRET_PASSWORDSecretPFX password (empty if unprotected)

FGLicense

VariableTypeDescription
FG_APIConfigFileGrant API URL
MONITORING_API_KEYSecretShared API key for monitoring
MONITORING_SIGNALR_URLConfigSignalR health check URL
MONITORING_RABBITMQ_URLConfigRabbitMQ health check URL
MONITORING_PDF_PROCESSING_URLConfigPDF Processing health check URL
MONITORING_FILEGRANT_API_URLConfigFileGrant API health check URL
MONITORING_LISTMONK_URLConfigListmonk health check URL
MONITORING_FILEGRANT_FE_URLConfigFrontend health check URL
GRAFANA_URLConfigGrafana URL
GRAFANA_TOKENSecretGrafana service account token
GRAFANA_LOKI_DATASOURCE_IDConfigLoki datasource ID in Grafana
GRAFANA_LOKI_LABEL_KEYConfigLabel key for Loki queries
GRAFANA_LOKI_SERVICE_NAMESConfigService names for Loki queries (pipe-separated)
EDITOR_API_KEYSecretEditor API key

FileGrant Frontend

The frontend requires the following environment variables to work correctly. They are configured in values-secrets.yaml under filegrantfe.env:

VariableTypeDescription
VITE_APP_PDF_PROCESSING_BASE_URLConfigPDF Processing service base URL
VITE_APP_OFFICE_EXCEL_ICON_URLConfigExcel icon URL for Office Online
VITE_APP_OFFICE_WORD_ICON_URLConfigWord icon URL for Office Online
VITE_APP_OFFICE_WOPISOURCE_URLConfigWOPI source URL for Office Online
VITE_APP_OFFICE_WOPITEST_URLConfigWOPI test URL (OneNote)
VITE_APP_OFFICE_POWERPOINT_URLConfigPowerPoint Online URL
VITE_APP_OFFICE_EXCEL_URLConfigExcel Online URL
VITE_APP_OFFICE_WORD_URLConfigWord Online URL
VITE_APP_STRIPE_PUBLIC_KEYConfigStripe public key for payments
VITE_APP_CRYPTO_KEYConfigApplication cryptographic key
VITE_APP_REMOTEGRANT_AGENT_BASE_URLConfigRemoteGrant agent base URL
VITE_APP_API_BASE_URLConfigFileGrant API base URL
VITE_APP_AZURE_RESOURCES_CONTAINERConfigAzure container name for resources
VITE_APP_WASM_MODULE_BYTESConfigWASM module bytes (pre-configured)
VITE_APP_WEBSOCKET_URLConfigWebSocket service URL (SignalR)
VITE_APP_REACT_PDF_LICENSE_KEYConfigReact PDF license key

Accessing Services (Port Map)

ServiceCommandURL
Frontendoc port-forward -n filegrant-local svc/filegrantfe 4200:8080http://localhost:4200
CGSignalRoc port-forward -n filegrant-local svc/signalrserviceapi 5000:8080http://localhost:5000
FileGrantAPIoc port-forward -n filegrant-local svc/filegrantapi 5001:8080http://localhost:5001
PDF Processingoc port-forward -n filegrant-local svc/filegrantpdfprocessing 5002:8080http://localhost:5002
FGLicenseoc port-forward -n filegrant-local svc/fglicense 5003:8080http://localhost:5003
RabbitMQ Managementoc port-forward -n filegrant-local svc/rabbitmq 15672:15672http://localhost:15672
RabbitMQ AMQPoc port-forward -n filegrant-local svc/rabbitmq 5672:5672amqp://localhost:5672
Grafanaoc port-forward -n filegrant-local svc/grafana 3000:3000http://localhost:3000

Quick Access Scripts

Windows (PowerShell)
Start-Job -ScriptBlock { oc port-forward -n filegrant-local svc/filegrantfe 4200:8080 }
Start-Job -ScriptBlock { oc port-forward -n filegrant-local svc/signalrserviceapi 5000:8080 }
Start-Job -ScriptBlock { oc port-forward -n filegrant-local svc/filegrantapi 5001:8080 }
Start-Job -ScriptBlock { oc port-forward -n filegrant-local svc/filegrantpdfprocessing 5002:8080 }
Start-Job -ScriptBlock { oc port-forward -n filegrant-local svc/fglicense 5003:8080 }
Start-Job -ScriptBlock { oc port-forward -n filegrant-local svc/rabbitmq 15672:15672 }
Start-Job -ScriptBlock { oc port-forward -n filegrant-local svc/grafana 3000:3000 }
Write-Host "All port-forwards started."
Write-Host "Run 'Get-Job | Stop-Job' to stop all."
Linux/macOS (Bash)
#!/bin/bash
oc port-forward -n filegrant-local svc/filegrantfe 4200:8080 &
oc port-forward -n filegrant-local svc/signalrserviceapi 5000:8080 &
oc port-forward -n filegrant-local svc/filegrantapi 5001:8080 &
oc port-forward -n filegrant-local svc/filegrantpdfprocessing 5002:8080 &
oc port-forward -n filegrant-local svc/fglicense 5003:8080 &
oc port-forward -n filegrant-local svc/rabbitmq 15672:15672 &
oc port-forward -n filegrant-local svc/grafana 3000:3000 &
echo "All port-forwards started. Press Ctrl+C to stop."
wait

Default Credentials

ServiceUsernamePassword
RabbitMQadmin-rmqSee values-localhost.yaml
GrafanaadminSee values-localhost.yaml

Optional: Disable the Logging Stack

If you do not need logging, you can disable Loki, Alloy, and Grafana to save resources:

Disable logging stack
helm upgrade filegrant . \
  --namespace filegrant-local \
  -f values-localhost.yaml \
  --set loki.enabled=false \
  --set alloy.enabled=false \
  --set grafana.enabled=false

Common Operations

View Pod Logs

View logs
oc logs -n filegrant-local -l app=filegrantapi -f
oc logs -n filegrant-local -l app=signalrserviceapi --tail=50

Restart a Service

Restart a deployment
oc rollout restart deployment filegrantapi -n filegrant-local

Check Resource Usage

Check resource usage
oc adm top pods -n filegrant-local

Update After Code Changes

Update deployment
# Restart with the current image
oc rollout restart deployment filegrantapi -n filegrant-local

# Or update with a specific image tag
helm upgrade filegrant . \
  --namespace filegrant-local \
  -f values-localhost.yaml \
  --set filegrantapi.image.tag=v1.2.3

Troubleshooting

CGSignalR or PDFProcessing in CrashLoopBackOff After Phase 2

Cause: EEVMS keys were not authorized, or some variables do not exist in EEVMS.

Check logs
oc logs -n filegrant-local -l app=cgsignalr --tail=30

Typical error messages:

  • "EEVMS: Not authorized for variable 'XXX'" -- public key not authorized
  • "EEVMS: API returned 401" -- invalid PFX certificate
  • "EEVMS: Failed to initialize" -- FileGrantAPI not reachable

Solution:

  1. Verify FileGrantAPI is Running

    oc get pods -n filegrant-local -l app=filegrantapi
  2. Re-run the authorization script

    oc port-forward -n filegrant-local svc/filegrantapi 5001:8080
    ./scripts/authorize-eevms-keys.sh --api-url http://localhost:5001 --api-key "<EDITOR_API_KEY>"
  3. Restart the pods

    oc rollout restart deployment cgsignalr -n filegrant-local
    oc rollout restart deployment filegrantpdfprocessing -n filegrant-local

EEVMS Variables "not_found" During Authorization

Cause: The variable does not exist yet in the EEVMS document.

Solution: Create the missing variable (with an empty value for now) and then re-run the authorization:

Create missing variable and re-authorize
# Create the missing variable
curl -s -X POST "http://localhost:5001/api/v1/secrets/admin/VARIABLE_NAME" \
  -H "X-Editor-Api-Key: <EDITOR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"value": ""}'

# Re-run the authorization
./scripts/authorize-eevms-keys.sh \
  --api-url http://localhost:5001 \
  --api-key "<EDITOR_API_KEY>"

Pods Stuck in Pending

The machine may not have enough resources. Inspect the pod and node allocation:

Diagnose pending pods
oc describe pod -n filegrant-local <pod-name>
oc describe node | grep -A 5 "Allocated resources"

Fix: Increase CRC resources (crc stop && crc start --cpus 8 --memory 16384) or disable unnecessary services:

Disable non-essential services
helm upgrade filegrant . \
  --namespace filegrant-local \
  -f values-localhost.yaml \
  --set filegrantpdfprocessing.enabled=false \
  --set fglicense.enabled=false

Pod in CrashLoopBackOff

Check pod logs
# Check current logs
oc logs -n filegrant-local <pod-name>

# Check previous container logs
oc logs -n filegrant-local <pod-name> --previous

SCC Errors (Permission Denied)

If a pod does not start due to permission issues:

Inspect SCC
oc get scc
oc describe scc alloy-scc
oc describe pod -n filegrant-local -l app=alloy

Port-Forward Disconnects

Port-forwards may drop due to inactivity. Re-run the command or use the quick access script provided above.

Image Pull Errors

All images are hosted on Azure Container Registry. Verify that the imagePullSecret exists:

Verify and recreate ACR secret
oc get secret acr-secret -n filegrant-local

# If missing, recreate it:
oc create secret docker-registry acr-secret \
  --docker-server=cybergrantregistry-cuash9ckhse5gcha.azurecr.io \
  --docker-username=<SERVICE_PRINCIPAL_ID> \
  --docker-password=<SERVICE_PRINCIPAL_PASSWORD> \
  -n filegrant-local

Cleanup

Stop All Services (Keep Data)

Scale down all services
oc scale deployment --all -n filegrant-local --replicas=0
oc scale statefulset --all -n filegrant-local --replicas=0

Resume Services

Resume services via Helm
helm upgrade filegrant . \
  --namespace filegrant-local \
  -f values-localhost.yaml

Uninstall Everything

Full uninstall
helm uninstall filegrant -n filegrant-local
oc delete project filegrant-local

Stop CRC

Stop and delete CRC
# Stop (keeps state)
crc stop

# Delete completely
crc delete

Development Tips

  1. Don't enable everything -- Start only the services you need. Disable PDF Processing and FGLicense if you only need the API.
  2. Use Grafana for logs -- Access at http://localhost:3000 then navigate to Explore and select Loki as the data source. For quick debugging, oc logs -f works just as well.
  3. Shell into pods for debugging:
    oc exec -it -n filegrant-local deploy/filegrantapi -- /bin/bash
  4. Check internal connectivity between services:
    oc exec -n filegrant-local deploy/signalrserviceapi -- curl -s http://rabbitmq:15672
  5. OpenShift Web Console: CRC provides a web console accessible with:
    crc console