merge fix
This commit is contained in:
commit
0db67b8c6a
8 changed files with 198 additions and 115 deletions
13
.env.example
13
.env.example
|
|
@ -4,8 +4,8 @@ FLOW_ID=1098eea1-6649-4e1d-aed1-b77249fb8dd0
|
|||
# container startup from this value. Do not commit real secrets.
|
||||
OPENSEARCH_PASSWORD=
|
||||
# make here https://console.cloud.google.com/apis/credentials
|
||||
GOOGLE_OAUTH_CLIENT_ID=287178119926-8t3co7hgnc5onv55k7hjv46qdcvbddfm.apps.googleusercontent.com
|
||||
GOOGLE_OAUTH_CLIENT_SECRET=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
|
||||
GOOGLE_OAUTH_CLIENT_ID=
|
||||
GOOGLE_OAUTH_CLIENT_SECRET=
|
||||
# Azure app registration credentials for SharePoint/OneDrive
|
||||
MICROSOFT_GRAPH_OAUTH_CLIENT_ID=
|
||||
MICROSOFT_GRAPH_OAUTH_CLIENT_SECRET=
|
||||
|
|
@ -20,6 +20,9 @@ AWS_SECRET_ACCESS_KEY=
|
|||
# OPTIONAL url for openrag link to langflow in the UI
|
||||
LANGFLOW_PUBLIC_URL=
|
||||
|
||||
# Change the AUTO_LOGIN=False in .env
|
||||
LANGFLOW_SUPERUSER=langflow
|
||||
LANGFLOW_SUPERUSER_PASSWORD=langflow
|
||||
# Langflow auth
|
||||
LANGFLOW_AUTO_LOGIN=False
|
||||
LANGFLOW_SUPERUSER=
|
||||
LANGFLOW_SUPERUSER_PASSWORD=
|
||||
LANGFLOW_NEW_USER_IS_ACTIVE=False
|
||||
LANGFLOW_ENABLE_SUPERUSER_CLI=False
|
||||
|
|
|
|||
199
.github/workflows/build-multiarch.yml
vendored
199
.github/workflows/build-multiarch.yml
vendored
|
|
@ -6,115 +6,126 @@ on:
|
|||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- platform: linux/amd64
|
||||
# backend
|
||||
- image: backend
|
||||
file: ./Dockerfile.backend
|
||||
tag: phact/openrag-backend
|
||||
platform: linux/amd64
|
||||
arch: amd64
|
||||
runs-on: ubuntu-latest
|
||||
arch-suffix: amd64
|
||||
- platform: linux/arm64
|
||||
runs-on: self-hosted
|
||||
arch-suffix: arm64
|
||||
|
||||
- image: backend
|
||||
file: ./Dockerfile.backend
|
||||
tag: phact/openrag-backend
|
||||
platform: linux/arm64
|
||||
arch: arm64
|
||||
runs-on: self-hosted
|
||||
|
||||
# frontend
|
||||
- image: frontend
|
||||
file: ./Dockerfile.frontend
|
||||
tag: phact/openrag-frontend
|
||||
platform: linux/amd64
|
||||
arch: amd64
|
||||
runs-on: ubuntu-latest
|
||||
- image: frontend
|
||||
file: ./Dockerfile.frontend
|
||||
tag: phact/openrag-frontend
|
||||
platform: linux/arm64
|
||||
arch: arm64
|
||||
runs-on: self-hosted
|
||||
|
||||
# opensearch
|
||||
- image: opensearch
|
||||
file: ./Dockerfile
|
||||
tag: phact/openrag-opensearch
|
||||
platform: linux/amd64
|
||||
arch: amd64
|
||||
runs-on: ubuntu-latest
|
||||
- image: opensearch
|
||||
file: ./Dockerfile
|
||||
tag: phact/openrag-opensearch
|
||||
platform: linux/arm64
|
||||
arch: arm64
|
||||
runs-on: self-hosted
|
||||
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Extract version from pyproject.toml
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Version: $VERSION"
|
||||
- name: Extract version from pyproject.toml
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Version: $VERSION"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push backend
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.backend
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: phact/openrag-backend:${{ steps.version.outputs.version }}-${{ matrix.arch-suffix }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Build and push frontend
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.frontend
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: phact/openrag-frontend:${{ steps.version.outputs.version }}-${{ matrix.arch-suffix }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Build and push OpenSearch
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: phact/openrag-opensearch:${{ steps.version.outputs.version }}-${{ matrix.arch-suffix }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Build and push ${{ matrix.image }} (${{ matrix.arch }})
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.file }}
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ matrix.tag }}:${{ steps.version.outputs.version }}-${{ matrix.arch }}
|
||||
cache-from: type=gha,scope=${{ matrix.image }}-${{ matrix.arch }}
|
||||
cache-to: type=gha,mode=max,scope=${{ matrix.image }}-${{ matrix.arch }}
|
||||
|
||||
manifest:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'pull_request'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Extract version from pyproject.toml
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
- name: Extract version from pyproject.toml
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Create and push multi-arch manifests
|
||||
run: |
|
||||
VERSION=${{ steps.version.outputs.version }}
|
||||
|
||||
# Backend manifest
|
||||
docker buildx imagetools create -t phact/openrag-backend:$VERSION \
|
||||
phact/openrag-backend:$VERSION-amd64 \
|
||||
phact/openrag-backend:$VERSION-arm64
|
||||
docker buildx imagetools create -t phact/openrag-backend:latest \
|
||||
phact/openrag-backend:$VERSION-amd64 \
|
||||
phact/openrag-backend:$VERSION-arm64
|
||||
|
||||
# Frontend manifest
|
||||
docker buildx imagetools create -t phact/openrag-frontend:$VERSION \
|
||||
phact/openrag-frontend:$VERSION-amd64 \
|
||||
phact/openrag-frontend:$VERSION-arm64
|
||||
docker buildx imagetools create -t phact/openrag-frontend:latest \
|
||||
phact/openrag-frontend:$VERSION-amd64 \
|
||||
phact/openrag-frontend:$VERSION-arm64
|
||||
|
||||
# OpenSearch manifest
|
||||
docker buildx imagetools create -t phact/openrag-opensearch:$VERSION \
|
||||
phact/openrag-opensearch:$VERSION-amd64 \
|
||||
phact/openrag-opensearch:$VERSION-arm64
|
||||
docker buildx imagetools create -t phact/openrag-opensearch:latest \
|
||||
phact/openrag-opensearch:$VERSION-amd64 \
|
||||
phact/openrag-opensearch:$VERSION-arm64
|
||||
- name: Create and push multi-arch manifests
|
||||
run: |
|
||||
VERSION=${{ steps.version.outputs.version }}
|
||||
|
||||
docker buildx imagetools create -t phact/openrag-backend:$VERSION \
|
||||
phact/openrag-backend:$VERSION-amd64 \
|
||||
phact/openrag-backend:$VERSION-arm64
|
||||
docker buildx imagetools create -t phact/openrag-backend:latest \
|
||||
phact/openrag-backend:$VERSION-amd64 \
|
||||
phact/openrag-backend:$VERSION-arm64
|
||||
|
||||
docker buildx imagetools create -t phact/openrag-frontend:$VERSION \
|
||||
phact/openrag-frontend:$VERSION-amd64 \
|
||||
phact/openrag-frontend:$VERSION-arm64
|
||||
docker buildx imagetools create -t phact/openrag-frontend:latest \
|
||||
phact/openrag-frontend:$VERSION-amd64 \
|
||||
phact/openrag-frontend:$VERSION-arm64
|
||||
|
||||
docker buildx imagetools create -t phact/openrag-opensearch:$VERSION \
|
||||
phact/openrag-opensearch:$VERSION-amd64 \
|
||||
phact/openrag-opensearch:$VERSION-arm64
|
||||
docker buildx imagetools create -t phact/openrag-opensearch:latest \
|
||||
phact/openrag-opensearch:$VERSION-amd64 \
|
||||
phact/openrag-opensearch:$VERSION-arm64
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@ RUN echo "asprof \$@" >> /usr/share/opensearch/profile.sh
|
|||
|
||||
RUN chmod 777 /usr/share/opensearch/profile.sh
|
||||
|
||||
# Copy OIDC and DLS security configuration (as root)
|
||||
COPY securityconfig/ /usr/share/opensearch/securityconfig/
|
||||
RUN chown -R opensearch:opensearch /usr/share/opensearch/securityconfig/
|
||||
|
||||
USER opensearch
|
||||
|
||||
RUN opensearch-plugin remove opensearch-neural-search
|
||||
|
|
@ -46,16 +50,13 @@ RUN echo y | opensearch-plugin install repository-gcs
|
|||
RUN echo y | opensearch-plugin install repository-azure
|
||||
RUN echo y | opensearch-plugin install repository-s3
|
||||
|
||||
# Copy OIDC and DLS security configuration
|
||||
COPY securityconfig/ /usr/share/opensearch/securityconfig/
|
||||
|
||||
# Create a script to apply security configuration after OpenSearch starts
|
||||
RUN echo '#!/bin/bash' > /usr/share/opensearch/setup-security.sh && \
|
||||
echo 'echo "Waiting for OpenSearch to start..."' >> /usr/share/opensearch/setup-security.sh && \
|
||||
echo 'until curl -s -k -u admin:${OPENSEARCH_INITIAL_ADMIN_PASSWORD} https://localhost:9200; do sleep 1; done' >> /usr/share/opensearch/setup-security.sh && \
|
||||
echo 'echo "Generating admin hash from OPENSEARCH_INITIAL_ADMIN_PASSWORD..."' >> /usr/share/opensearch/setup-security.sh && \
|
||||
echo 'if [ -z "${OPENSEARCH_INITIAL_ADMIN_PASSWORD}" ]; then echo "[ERROR] OPENSEARCH_INITIAL_ADMIN_PASSWORD not set"; exit 1; fi' >> /usr/share/opensearch/setup-security.sh && \
|
||||
echo 'HASH=$(/usr/share/opensearch/plugins/opensearch-security/tools/hash.sh -p "${OPENSEARCH_INITIAL_ADMIN_PASSWORD}" | sed -n '\''s/^hash: //p'\'')' >> /usr/share/opensearch/setup-security.sh && \
|
||||
echo 'HASH=$(/usr/share/opensearch/plugins/opensearch-security/tools/hash.sh -p "${OPENSEARCH_INITIAL_ADMIN_PASSWORD}")' >> /usr/share/opensearch/setup-security.sh && \
|
||||
echo 'if [ -z "$HASH" ]; then echo "[ERROR] Failed to generate admin hash"; exit 1; fi' >> /usr/share/opensearch/setup-security.sh && \
|
||||
echo 'sed -i "s|^ hash: \".*\"| hash: \"$HASH\"|" /usr/share/opensearch/securityconfig/internal_users.yml' >> /usr/share/opensearch/setup-security.sh && \
|
||||
echo 'echo "Updated internal_users.yml with runtime-generated admin hash"' >> /usr/share/opensearch/setup-security.sh && \
|
||||
|
|
|
|||
|
|
@ -101,3 +101,5 @@ services:
|
|||
- LANGFLOW_AUTO_LOGIN=${LANGFLOW_AUTO_LOGIN}
|
||||
- LANGFLOW_SUPERUSER=${LANGFLOW_SUPERUSER}
|
||||
- LANGFLOW_SUPERUSER_PASSWORD=${LANGFLOW_SUPERUSER_PASSWORD}
|
||||
- LANGFLOW_NEW_USER_IS_ACTIVE=${LANGFLOW_NEW_USER_IS_ACTIVE}
|
||||
- LANGFLOW_ENABLE_SUPERUSER_CLI=${LANGFLOW_ENABLE_SUPERUSER_CLI}
|
||||
|
|
|
|||
|
|
@ -102,3 +102,5 @@ services:
|
|||
- LANGFLOW_AUTO_LOGIN=${LANGFLOW_AUTO_LOGIN}
|
||||
- LANGFLOW_SUPERUSER=${LANGFLOW_SUPERUSER}
|
||||
- LANGFLOW_SUPERUSER_PASSWORD=${LANGFLOW_SUPERUSER_PASSWORD}
|
||||
- LANGFLOW_NEW_USER_IS_ACTIVE=${LANGFLOW_NEW_USER_IS_ACTIVE}
|
||||
- LANGFLOW_ENABLE_SUPERUSER_CLI=${LANGFLOW_ENABLE_SUPERUSER_CLI}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ class EnvConfig:
|
|||
aws_secret_access_key: str = ""
|
||||
langflow_public_url: str = ""
|
||||
|
||||
# Langflow auth settings
|
||||
langflow_auto_login: str = "False"
|
||||
langflow_new_user_is_active: str = "False"
|
||||
langflow_enable_superuser_cli: str = "False"
|
||||
|
||||
# Document paths (comma-separated)
|
||||
openrag_documents_paths: str = "./documents"
|
||||
|
||||
|
|
@ -98,6 +103,9 @@ class EnvManager:
|
|||
'AWS_SECRET_ACCESS_KEY': 'aws_secret_access_key',
|
||||
'LANGFLOW_PUBLIC_URL': 'langflow_public_url',
|
||||
'OPENRAG_DOCUMENTS_PATHS': 'openrag_documents_paths',
|
||||
'LANGFLOW_AUTO_LOGIN': 'langflow_auto_login',
|
||||
'LANGFLOW_NEW_USER_IS_ACTIVE': 'langflow_new_user_is_active',
|
||||
'LANGFLOW_ENABLE_SUPERUSER_CLI': 'langflow_enable_superuser_cli',
|
||||
}
|
||||
|
||||
if key in attr_map:
|
||||
|
|
@ -193,6 +201,13 @@ class EnvManager:
|
|||
f.write(f"OPENRAG_DOCUMENTS_PATHS={self.config.openrag_documents_paths}\n")
|
||||
f.write("\n")
|
||||
|
||||
# Langflow auth settings
|
||||
f.write("# Langflow auth settings\n")
|
||||
f.write(f"LANGFLOW_AUTO_LOGIN={self.config.langflow_auto_login}\n")
|
||||
f.write(f"LANGFLOW_NEW_USER_IS_ACTIVE={self.config.langflow_new_user_is_active}\n")
|
||||
f.write(f"LANGFLOW_ENABLE_SUPERUSER_CLI={self.config.langflow_enable_superuser_cli}\n")
|
||||
f.write("\n")
|
||||
|
||||
# OAuth settings
|
||||
if self.config.google_oauth_client_id or self.config.google_oauth_client_secret:
|
||||
f.write("# Google OAuth settings\n")
|
||||
|
|
|
|||
|
|
@ -282,6 +282,47 @@ class ConfigScreen(Screen):
|
|||
self.inputs["openrag_documents_paths"] = input_widget
|
||||
yield Static(" ")
|
||||
|
||||
# Langflow Auth Settings
|
||||
yield Static("Langflow Auth Settings", classes="tab-header")
|
||||
yield Static(" ")
|
||||
|
||||
# Langflow Auto Login
|
||||
yield Label("Langflow Auto Login")
|
||||
current_value = getattr(self.env_manager.config, "langflow_auto_login", "False")
|
||||
input_widget = Input(
|
||||
placeholder="False",
|
||||
value=current_value,
|
||||
id="input-langflow_auto_login"
|
||||
)
|
||||
yield input_widget
|
||||
self.inputs["langflow_auto_login"] = input_widget
|
||||
yield Static(" ")
|
||||
|
||||
# Langflow New User Is Active
|
||||
yield Label("Langflow New User Is Active")
|
||||
current_value = getattr(self.env_manager.config, "langflow_new_user_is_active", "False")
|
||||
input_widget = Input(
|
||||
placeholder="False",
|
||||
value=current_value,
|
||||
id="input-langflow_new_user_is_active"
|
||||
)
|
||||
yield input_widget
|
||||
self.inputs["langflow_new_user_is_active"] = input_widget
|
||||
yield Static(" ")
|
||||
|
||||
# Langflow Enable Superuser CLI
|
||||
yield Label("Langflow Enable Superuser CLI")
|
||||
current_value = getattr(self.env_manager.config, "langflow_enable_superuser_cli", "False")
|
||||
input_widget = Input(
|
||||
placeholder="False",
|
||||
value=current_value,
|
||||
id="input-langflow_enable_superuser_cli"
|
||||
)
|
||||
yield input_widget
|
||||
self.inputs["langflow_enable_superuser_cli"] = input_widget
|
||||
yield Static(" ")
|
||||
yield Static(" ")
|
||||
|
||||
# Langflow Secret Key removed from UI; generated automatically on save
|
||||
|
||||
# Add optional fields only in full mode
|
||||
|
|
@ -379,7 +420,7 @@ class ConfigScreen(Screen):
|
|||
new_value = getattr(self.env_manager.config, field_name)
|
||||
input_widget.value = new_value
|
||||
|
||||
self.notify("Generated secure passwords", severity="info")
|
||||
self.notify("Generated secure passwords", severity="information")
|
||||
|
||||
def action_save(self) -> None:
|
||||
"""Save the configuration."""
|
||||
|
|
@ -398,7 +439,7 @@ class ConfigScreen(Screen):
|
|||
|
||||
# Save to file
|
||||
if self.env_manager.save_env_file():
|
||||
self.notify("Configuration saved successfully!", severity="success")
|
||||
self.notify("Configuration saved successfully!", severity="information")
|
||||
# Switch to monitor screen
|
||||
from .monitor import MonitorScreen
|
||||
self.app.push_screen(MonitorScreen())
|
||||
|
|
|
|||
|
|
@ -166,10 +166,22 @@ class MonitorScreen(Screen):
|
|||
return
|
||||
|
||||
services = await self.container_manager.get_service_status(force_refresh=True)
|
||||
# Fetch image info independent of service state
|
||||
project_images = await self.container_manager.get_project_images_info()
|
||||
digest_map = {img: dig for img, dig in project_images}
|
||||
images = [img for img, _ in project_images]
|
||||
# Collect images actually reported by running/stopped containers so names match runtime
|
||||
images_set = set()
|
||||
for svc in services.values():
|
||||
img = (svc.image or "").strip()
|
||||
if img and img != "N/A":
|
||||
images_set.add(img)
|
||||
# Ensure compose-declared images are also shown (e.g., langflow when stopped)
|
||||
try:
|
||||
for img in self.container_manager._parse_compose_images(): # best-effort, no YAML dep
|
||||
if img:
|
||||
images_set.add(img)
|
||||
except Exception:
|
||||
pass
|
||||
images = list(images_set)
|
||||
# Lookup digests/IDs for these image names
|
||||
digest_map = await self.container_manager.get_images_digests(images)
|
||||
|
||||
# Clear existing rows
|
||||
self.services_table.clear()
|
||||
|
|
@ -188,13 +200,9 @@ class MonitorScreen(Screen):
|
|||
service_info.image or "N/A",
|
||||
digest_map.get(service_info.image or "", "-")
|
||||
)
|
||||
# Populate images table (unique images)
|
||||
# Populate images table (unique images as reported by runtime)
|
||||
if self.images_table:
|
||||
seen=set()
|
||||
for image in images:
|
||||
if not image or image in seen:
|
||||
continue
|
||||
seen.add(image)
|
||||
for image in sorted(images):
|
||||
self.images_table.add_row(image, digest_map.get(image, "-"))
|
||||
# Update controls based on overall state
|
||||
self._update_controls(list(services.values()))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue