diff --git a/.github/actions/lfai-core/action.yaml b/.github/actions/lfai-core/action.yaml index 40807f8c3..29221c0aa 100644 --- a/.github/actions/lfai-core/action.yaml +++ b/.github/actions/lfai-core/action.yaml @@ -22,7 +22,7 @@ runs: - name: Deploy LFAI-API shell: bash run: | - make build-api LOCAL_VERSION=e2e-test + make build-api LOCAL_VERSION=e2e-test FLAVOR=upstream docker image prune -af uds zarf package deploy packages/api/zarf-package-leapfrogai-api-amd64-e2e-test.tar.zst --confirm rm packages/api/zarf-package-leapfrogai-api-amd64-e2e-test.tar.zst diff --git a/.github/actions/uds-cluster/action.yaml b/.github/actions/uds-cluster/action.yaml index 694dfb1de..683aa2652 100644 --- a/.github/actions/uds-cluster/action.yaml +++ b/.github/actions/uds-cluster/action.yaml @@ -6,6 +6,8 @@ inputs: description: Registry1 Username registry1Password: description: Registry1 Password + ghToken: + description: GitHub Token runs: using: composite @@ -13,8 +15,9 @@ runs: - name: Setup UDS Environment uses: defenseunicorns/uds-common/.github/actions/setup@822dac4452e6815aadcf09f487406ff258756a0c # v0.14.0 with: - username: ${{ inputs.registry1Username }} - password: ${{ inputs.registry1Password }} + registry1Username: ${{ inputs.registry1Username }} + registry1Password: ${{ inputs.registry1Password }} + ghToken: ${{ inputs.ghToken }} udsCliVersion: 0.14.0 - name: Checkout Repo @@ -23,4 +26,4 @@ runs: - name: Create UDS Cluster shell: bash run: | - UDS_CONFIG=.github/config/uds-config.yaml make create-uds-cpu-cluster \ No newline at end of file + UDS_CONFIG=.github/config/uds-config.yaml make create-uds-cpu-cluster diff --git a/.github/workflows/e2e-llama-cpp-python.yaml b/.github/workflows/e2e-llama-cpp-python.yaml index 66cd16bfb..5c6768596 100644 --- a/.github/workflows/e2e-llama-cpp-python.yaml +++ b/.github/workflows/e2e-llama-cpp-python.yaml @@ -68,6 +68,7 @@ jobs: with: registry1Username: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} registry1Password: ${{ secrets.IRON_BANK_ROBOT_PASSWORD }} + ghToken: ${{ secrets.GITHUB_TOKEN }} - name: Setup LFAI-API and Supabase uses: ./.github/actions/lfai-core diff --git a/.github/workflows/e2e-playwright.yaml b/.github/workflows/e2e-playwright.yaml index 7d9eb3234..5ebf2f5f4 100644 --- a/.github/workflows/e2e-playwright.yaml +++ b/.github/workflows/e2e-playwright.yaml @@ -81,6 +81,7 @@ jobs: with: registry1Username: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} registry1Password: ${{ secrets.IRON_BANK_ROBOT_PASSWORD }} + ghToken: ${{ secrets.GITHUB_TOKEN }} - name: Create Test User run: | diff --git a/.github/workflows/e2e-registry1-weekly.yaml b/.github/workflows/e2e-registry1-weekly.yaml new file mode 100644 index 000000000..48c87c864 --- /dev/null +++ b/.github/workflows/e2e-registry1-weekly.yaml @@ -0,0 +1,127 @@ +name: e2e-registry1-weekly + +on: + schedule: + - cron: "0 0 * * 6" # Run every Sunday at 12 AM EST + workflow_dispatch: # trigger manually as needed + pull_request: + types: + - opened # default trigger + - reopened # default trigger + - synchronize # default trigger + - ready_for_review # don't run on draft PRs + - milestoned # allows us to trigger on bot PRs + paths: + - .github/workflows/e2e-registry1-weekly.yaml + - uds-bundles/latest/** + +concurrency: + group: e2e-registry1-weekly-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + test-flavors: + runs-on: ai-ubuntu-big-boy-8-core + name: e2e_registry1_weekly + + permissions: + contents: read + packages: write + id-token: write # This is needed for OIDC federation. + + steps: + - name: Checkout Repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Setup Python + uses: ./.github/actions/python + + - name: Setup UDS Cluster + uses: ./.github/actions/uds-cluster + with: + registry1Username: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} + registry1Password: ${{ secrets.IRON_BANK_ROBOT_PASSWORD }} + ghToken: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Playwright + run: | + npm --prefix src/leapfrogai_ui ci + npx --prefix src/leapfrogai_ui playwright install + + - name: Create Registry1 Packages + run: | + LOCAL_VERSION=registry1 FLAVOR=registry1 make build-api + + # Mutate UDS bundle definition to use Registry1 packages + - name: Mutation to Registry1 Bundle + run: | + uds zarf tools yq -i '.packages[1] |= del(.repository)' uds-bundles/latest/cpu/uds-bundle.yaml + uds zarf tools yq -i '.packages[1] |= .ref = "registry1"' uds-bundles/latest/cpu/uds-bundle.yaml + uds zarf tools yq -i '.packages[1] |= .path = "../../../packages/api"' uds-bundles/latest/cpu/uds-bundle.yaml + uds zarf tools yq -i '.metadata.version = "registry1"' uds-bundles/latest/cpu/uds-bundle.yaml + + - name: Create and Deploy Bundle + run: | + cd uds-bundles/latest/cpu + uds create . --confirm && \ + uds deploy uds-bundle-leapfrogai-amd64-registry1.tar.zst \ + --set LEAPFROGAI_API_BASE_URL="http://leapfrogai-api.leapfrogai.svc.cluster.local:8080" --confirm --no-progress && \ + rm -rf uds-bundle-leapfrogai-amd64-registry1.tar.zst && \ + docker system prune -af + + - name: Generate Secrets + id: generate_secrets + run: | + PASSWORD=$(cat <(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9!@#$%^&*()_+-=[]{}|;:,.<>?' | head -c 20) <(echo '!@1Aa') | fold -w1 | shuf | tr -d '\n') + echo "::add-mask::$PASSWORD" + echo "FAKE_E2E_USER_PASSWORD=$PASSWORD" >> $GITHUB_OUTPUT + ANON_KEY=$(uds zarf tools kubectl get secret supabase-bootstrap-jwt -n leapfrogai -o jsonpath='{.data.anon-key}' | base64 -d) + echo "::add-mask::$ANON_KEY" + echo "ANON_KEY=$ANON_KEY" >> $GITHUB_OUTPUT + SERVICE_ROLE_KEY=$(uds zarf tools kubectl get secret -n leapfrogai supabase-bootstrap-jwt -o jsonpath={.data.service-key} | base64 -d) + echo "::add-mask::$SERVICE_ROLE_KEY" + echo "SERVICE_ROLE_KEY=$SERVICE_ROLE_KEY" >> $GITHUB_OUTPUT + + - name: Verify Secrets + run: | + echo "FAKE_E2E_USER_PASSWORD is set: ${{ steps.generate_secrets.outputs.FAKE_E2E_USER_PASSWORD != '' }}" + echo "ANON_KEY is set: ${{ steps.generate_secrets.outputs.ANON_KEY != '' }}" + echo "SERVICE_ROLE_KEY is set: ${{ steps.generate_secrets.outputs.SERVICE_ROLE_KEY != '' }}" + + # Backends + - name: Run Backend Tests + env: + ANON_KEY: ${{ steps.generate_secrets.outputs.ANON_KEY }} + run: | + python -m pytest ./tests/e2e/test_llama.py -v + python -m pytest ./tests/e2e/test_text_embeddings.py -v + python -m pytest ./tests/e2e/test_whisper.py -v + python -m pytest ./tests/e2e/test_supabase.py -v + python -m pytest ./tests/e2e/test_api.py -v + + - name: Run Playwright E2E Tests + env: + SERVICE_ROLE_KEY: ${{ steps.generate_secrets.outputs.SERVICE_ROLE_KEY }} + FAKE_E2E_USER_PASSWORD: ${{ steps.generate_secrets.outputs.FAKE_E2E_USER_PASSWORD }} + ANON_KEY: ${{ steps.generate_secrets.outputs.ANON_KEY }} + run: | + chmod +x ./.github/scripts/createUser.sh + ./.github/scripts/createUser.sh + + cp src/leapfrogai_ui/.env.example src/leapfrogai_ui/.env + mkdir -p playwright/auth + touch playwright/auth.user.json + + SERVICE_ROLE_KEY=$SERVICE_ROLE_KEY TEST_ENV=CI USERNAME=doug PASSWORD=$FAKE_E2E_USER_PASSWORD PUBLIC_SUPABASE_ANON_KEY=$ANON_KEY npm --prefix src/leapfrogai_ui run test:integration:ci + + - name: Archive Playwright Report + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: src/leapfrogai_ui/e2e-report/ + retention-days: 30 diff --git a/.github/workflows/e2e-text-embeddings.yaml b/.github/workflows/e2e-text-embeddings.yaml index eba01378d..20f7eb97a 100644 --- a/.github/workflows/e2e-text-embeddings.yaml +++ b/.github/workflows/e2e-text-embeddings.yaml @@ -70,6 +70,7 @@ jobs: with: registry1Username: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} registry1Password: ${{ secrets.IRON_BANK_ROBOT_PASSWORD }} + ghToken: ${{ secrets.GITHUB_TOKEN }} - name: Setup LFAI-API and Supabase uses: ./.github/actions/lfai-core diff --git a/.github/workflows/e2e-vllm.yaml b/.github/workflows/e2e-vllm.yaml index cedfab53e..1d037fc57 100644 --- a/.github/workflows/e2e-vllm.yaml +++ b/.github/workflows/e2e-vllm.yaml @@ -68,10 +68,12 @@ jobs: additionalOptionalDep: dev-vllm - name: Setup UDS Environment - uses: defenseunicorns/uds-common/.github/actions/setup@05f42bb3117b66ebef8c72ae050b34bce19385f5 + uses: defenseunicorns/uds-common/.github/actions/setup@822dac4452e6815aadcf09f487406ff258756a0c # v0.14.0 with: - username: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} - password: ${{ secrets.IRON_BANK_ROBOT_PASSWORD }} + registry1Username: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} + registry1Password: ${{ secrets.IRON_BANK_ROBOT_PASSWORD }} + ghToken: ${{ secrets.GITHUB_TOKEN }} + udsCliVersion: 0.14.0 ########## c # vLLM diff --git a/.github/workflows/e2e-whisper.yaml b/.github/workflows/e2e-whisper.yaml index 7c3908aa5..dee2cf45a 100644 --- a/.github/workflows/e2e-whisper.yaml +++ b/.github/workflows/e2e-whisper.yaml @@ -70,6 +70,7 @@ jobs: with: registry1Username: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} registry1Password: ${{ secrets.IRON_BANK_ROBOT_PASSWORD }} + ghToken: ${{ secrets.GITHUB_TOKEN }} - name: Setup LFAI-API and Supabase uses: ./.github/actions/lfai-core diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c03767b30..9c0825e3a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -65,8 +65,8 @@ jobs: docker buildx build --platform amd64,arm64 --build-arg LOCAL_VERSION=${{ steps.get_version.outputs.version-without-v }} -t ghcr.io/defenseunicorns/leapfrogai/leapfrogai-api:${{ steps.get_version.outputs.version-without-v }} --push -f packages/api/Dockerfile . docker buildx build --platform amd64,arm64 -t ghcr.io/defenseunicorns/leapfrogai/api-migrations:${{ steps.get_version.outputs.version-without-v }} --push -f Dockerfile.migrations --build-arg="MIGRATIONS_DIR=packages/api/supabase/migrations" . - zarf package create packages/api --set=LEAPFROGAI_IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --confirm - zarf package create packages/api --set=LEAPFROGAI_IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --confirm + zarf package create packages/api --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --flavor upstream --confirm + zarf package create packages/api --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --flavor upstream --confirm zarf package publish zarf-package-leapfrogai-api-amd64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai zarf package publish zarf-package-leapfrogai-api-arm64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai @@ -79,8 +79,8 @@ jobs: docker buildx build --platform amd64,arm64 -t ghcr.io/defenseunicorns/leapfrogai/leapfrogai-ui:${{ steps.get_version.outputs.version-without-v }} --push src/leapfrogai_ui docker buildx build --platform amd64,arm64 -t ghcr.io/defenseunicorns/leapfrogai/ui-migrations:${{ steps.get_version.outputs.version-without-v }} --push -f Dockerfile.migrations --build-arg="MIGRATIONS_DIR=src/leapfrogai_ui/supabase/migrations" . - zarf package create packages/ui --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --confirm - zarf package create packages/ui --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --confirm + zarf package create packages/ui --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --flavor upstream --confirm + zarf package create packages/ui --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --flavor upstream --confirm zarf package publish zarf-package-leapfrogai-ui-amd64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai zarf package publish zarf-package-leapfrogai-ui-arm64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai @@ -92,8 +92,8 @@ jobs: run: | docker buildx build --platform amd64,arm64 -t ghcr.io/defenseunicorns/leapfrogai/supabase-migrations:${{ steps.get_version.outputs.version-without-v }} --push -f Dockerfile.migrations --build-arg="MIGRATIONS_DIR=packages/supabase/migrations" . - zarf package create packages/supabase --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --confirm - zarf package create packages/supabase --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --confirm + zarf package create packages/supabase --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --flavor upstream --confirm + zarf package create packages/supabase --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --flavor upstream --confirm zarf package publish zarf-package-supabase-amd64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai zarf package publish zarf-package-supabase-arm64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai @@ -102,8 +102,8 @@ jobs: run: | docker buildx build --platform amd64,arm64 --build-arg LOCAL_VERSION=${{ steps.get_version.outputs.version-without-v }} -t ghcr.io/defenseunicorns/leapfrogai/repeater:${{ steps.get_version.outputs.version-without-v }} --push -f packages/repeater/Dockerfile . - zarf package create packages/repeater --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --confirm - zarf package create packages/repeater --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --confirm + zarf package create packages/repeater --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --flavor upstream --confirm + zarf package create packages/repeater --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --flavor upstream --confirm zarf package publish zarf-package-repeater-amd64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai zarf package publish zarf-package-repeater-arm64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai @@ -115,8 +115,8 @@ jobs: run: | docker buildx build --platform amd64,arm64 --build-arg LOCAL_VERSION=${{ steps.get_version.outputs.version-without-v }} -t ghcr.io/defenseunicorns/leapfrogai/llama-cpp-python:${{ steps.get_version.outputs.version-without-v }} --push -f packages/llama-cpp-python/Dockerfile . - zarf package create packages/llama-cpp-python --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --confirm - zarf package create packages/llama-cpp-python --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --confirm + zarf package create packages/llama-cpp-python --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --flavor upstream --confirm + zarf package create packages/llama-cpp-python --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --flavor upstream --confirm zarf package publish zarf-package-llama-cpp-python-amd64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai zarf package publish zarf-package-llama-cpp-python-arm64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai @@ -128,7 +128,7 @@ jobs: run: | docker buildx build --build-arg LOCAL_VERSION=${{ steps.get_version.outputs.version-without-v }} -t ghcr.io/defenseunicorns/leapfrogai/vllm:${{ steps.get_version.outputs.version-without-v }} --push -f packages/vllm/Dockerfile . - zarf package create packages/vllm --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --confirm + zarf package create packages/vllm --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --flavor upstream --confirm zarf package publish zarf-package-vllm-amd64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai @@ -139,8 +139,8 @@ jobs: run: | docker buildx build --platform amd64,arm64 --build-arg LOCAL_VERSION=${{ steps.get_version.outputs.version-without-v }} -t ghcr.io/defenseunicorns/leapfrogai/text-embeddings:${{ steps.get_version.outputs.version-without-v }} --push -f packages/text-embeddings/Dockerfile . - zarf package create packages/text-embeddings --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --confirm - zarf package create packages/text-embeddings --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --confirm + zarf package create packages/text-embeddings --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --flavor upstream --confirm + zarf package create packages/text-embeddings --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --flavor upstream --confirm zarf package publish zarf-package-text-embeddings-amd64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai zarf package publish zarf-package-text-embeddings-arm64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai @@ -152,8 +152,8 @@ jobs: run: | docker buildx build --platform amd64,arm64 --build-arg LOCAL_VERSION=${{ steps.get_version.outputs.version-without-v }} -t ghcr.io/defenseunicorns/leapfrogai/whisper:${{ steps.get_version.outputs.version-without-v }} --push -f packages/whisper/Dockerfile . - zarf package create packages/whisper --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --confirm - zarf package create packages/whisper --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --confirm + zarf package create packages/whisper --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --flavor upstream --confirm + zarf package create packages/whisper --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --flavor upstream --confirm zarf package publish zarf-package-whisper-amd64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai zarf package publish zarf-package-whisper-arm64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai diff --git a/Makefile b/Makefile index 3515ff30a..732abe4e5 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ REG_NAME ?= registry LOCAL_VERSION ?= $(shell git rev-parse --short HEAD) DOCKER_FLAGS := ZARF_FLAGS := +FLAVOR := upstream SILENT_DOCKER_FLAGS := --quiet SILENT_ZARF_FLAGS := --no-progress -l warn --no-color MAX_JOBS := 4 @@ -59,26 +60,29 @@ build-supabase: local-registry docker-supabase docker push ${DOCKER_FLAGS} localhost:${REG_PORT}/defenseunicorns/leapfrogai/supabase-migrations:${LOCAL_VERSION} ## Build the Zarf package - uds zarf package create packages/supabase -a ${ARCH} -o packages/supabase --registry-override=ghcr.io=localhost:${REG_PORT} --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm + uds zarf package create packages/supabase --flavor ${FLAVOR} -a ${ARCH} -o packages/supabase --registry-override=ghcr.io=localhost:${REG_PORT} --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm docker-api: local-registry sdk-wheel @echo $(DOCKER_FLAGS) @echo $(ZARF_FLAGS) +ifeq ($(FLAVOR),upstream) ## Build the API image (and tag it for the local registry) docker build ${DOCKER_FLAGS} --platform=linux/${ARCH} --build-arg LOCAL_VERSION=${LOCAL_VERSION} -t ghcr.io/defenseunicorns/leapfrogai/leapfrogai-api:${LOCAL_VERSION} -f packages/api/Dockerfile . docker tag ghcr.io/defenseunicorns/leapfrogai/leapfrogai-api:${LOCAL_VERSION} localhost:${REG_PORT}/defenseunicorns/leapfrogai/leapfrogai-api:${LOCAL_VERSION} - +endif ## Build the migration container for this version of the API docker build ${DOCKER_FLAGS} --platform=linux/${ARCH} -t ghcr.io/defenseunicorns/leapfrogai/api-migrations:${LOCAL_VERSION} -f Dockerfile.migrations --build-arg="MIGRATIONS_DIR=packages/api/supabase/migrations" . docker tag ghcr.io/defenseunicorns/leapfrogai/api-migrations:${LOCAL_VERSION} localhost:${REG_PORT}/defenseunicorns/leapfrogai/api-migrations:${LOCAL_VERSION} build-api: local-registry docker-api ## Build the leapfrogai_api container and Zarf package +ifeq ($(FLAVOR),upstream) ## Push the images to the local registry (Zarf is super slow if the image is only in the local daemon) docker push ${DOCKER_FLAGS} localhost:${REG_PORT}/defenseunicorns/leapfrogai/leapfrogai-api:${LOCAL_VERSION} +endif docker push ${DOCKER_FLAGS} localhost:${REG_PORT}/defenseunicorns/leapfrogai/api-migrations:${LOCAL_VERSION} ## Build the Zarf package - uds zarf package create packages/api -a ${ARCH} -o packages/api --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set LEAPFROGAI_IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm + uds zarf package create packages/api --flavor ${FLAVOR} -a ${ARCH} -o packages/api --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm docker-ui: ## Build the UI image (and tag it for the local registry) @@ -95,7 +99,7 @@ build-ui: local-registry docker-ui ## Build the leapfrogai_ui container and Zarf docker push ${DOCKER_FLAGS} localhost:${REG_PORT}/defenseunicorns/leapfrogai/ui-migrations:${LOCAL_VERSION} ## Build the Zarf package - uds zarf package create packages/ui -a ${ARCH} -o packages/ui --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm + uds zarf package create packages/ui --flavor ${FLAVOR} -a ${ARCH} -o packages/ui --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm docker-llama-cpp-python: sdk-wheel ## Build the image (and tag it for the local registry) @@ -107,7 +111,7 @@ build-llama-cpp-python: local-registry docker-llama-cpp-python ## Build the llam docker push ${DOCKER_FLAGS} localhost:${REG_PORT}/defenseunicorns/leapfrogai/llama-cpp-python:${LOCAL_VERSION} ## Build the Zarf package - uds zarf package create packages/llama-cpp-python -a ${ARCH} -o packages/llama-cpp-python --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm + uds zarf package create packages/llama-cpp-python --flavor ${FLAVOR} -a ${ARCH} -o packages/llama-cpp-python --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm docker-vllm: sdk-wheel ## Build the image (and tag it for the local registry) @@ -119,7 +123,7 @@ build-vllm: local-registry docker-vllm ## Build the vllm container and Zarf pack docker push ${DOCKER_FLAGS} localhost:${REG_PORT}/defenseunicorns/leapfrogai/vllm:${LOCAL_VERSION} ## Build the Zarf package - uds zarf package create packages/vllm -a ${ARCH} -o packages/vllm --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm + uds zarf package create packages/vllm --flavor ${FLAVOR} -a ${ARCH} -o packages/vllm --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm docker-text-embeddings: sdk-wheel ## Build the image (and tag it for the local registry) @@ -131,7 +135,7 @@ build-text-embeddings: local-registry docker-text-embeddings ## Build the text-e docker push ${DOCKER_FLAGS} localhost:${REG_PORT}/defenseunicorns/leapfrogai/text-embeddings:${LOCAL_VERSION} ## Build the Zarf package - uds zarf package create packages/text-embeddings -a ${ARCH} -o packages/text-embeddings --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm + uds zarf package create packages/text-embeddings --flavor ${FLAVOR} -a ${ARCH} -o packages/text-embeddings --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm docker-whisper: sdk-wheel @@ -144,7 +148,7 @@ build-whisper: local-registry docker-whisper ## Build the whisper container and docker push ${DOCKER_FLAGS} localhost:${REG_PORT}/defenseunicorns/leapfrogai/whisper:${LOCAL_VERSION} ## Build the Zarf package - uds zarf package create packages/whisper -a ${ARCH} -o packages/whisper --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm + uds zarf package create packages/whisper --flavor ${FLAVOR} -a ${ARCH} -o packages/whisper --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm docker-repeater: sdk-wheel ## Build the image (and tag it for the local registry) @@ -156,7 +160,7 @@ build-repeater: local-registry docker-repeater ## Build the repeater container a docker push ${DOCKER_FLAGS} localhost:${REG_PORT}/defenseunicorns/leapfrogai/repeater:${LOCAL_VERSION} ## Build the Zarf package - uds zarf package create packages/repeater -a ${ARCH} -o packages/repeater --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm + uds zarf package create packages/repeater --flavor ${FLAVOR} -a ${ARCH} -o packages/repeater --registry-override=ghcr.io=localhost:${REG_PORT} --insecure --set IMAGE_VERSION=${LOCAL_VERSION} ${ZARF_FLAGS} --confirm build-cpu: build-supabase build-api build-ui build-llama-cpp-python build-text-embeddings build-whisper ## Build all zarf packages for a cpu-enabled deployment of LFAI diff --git a/README.md b/README.md index ae3cf0a7f..d8781727b 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,29 @@ LeapfrogAI provides several backends for a variety of use cases. Below is the ba The [repeater](packages/repeater/) "model" is a basic "backend" that parrots all inputs it receives back to the user. It is built out the same way all the actual backends are and it is primarily used for testing the API. +### Flavors + +Each component has different images and values that refer to a specific image registry and/or hardening source. These images are packaged using [Zarf Flavors](https://docs.zarf.dev/ref/examples/package-flavors/): + +1. `upstream`: uses upstream vendor images from open source container registries and repositories +2. 🚧 `registry1`: uses [IronBank hardened images](https://repo1.dso.mil/dsop) from the Repo1 harbor registry + +Below is the current component flavors list: + +| Component | `upstream` | `registry1` | +| ---------------------------------------------- | ------------ | ------------- | +| [api](packages/api/) | ✅ | ✅ | +| [ui](packages/ui/) | ✅ | 🚧 | +| [supabase](packages/supabase/) | ✅ | 🚧 | +| [migrations](./Dockerfile.migrations) | ✅ | 🚧 | +| [llama-cpp-python](packages/llama-cpp-python/) | ✅ | 🚧 | +| [whisper](packages/whisper/) | ✅ | 🚧 | +| [text-embeddings](packages/text-embeddings/) | ✅ | 🚧 | +| [vllm](packages/vllm/) | ✅ | 🚧 | +| [vllm](packages/vllm/) | ✅ | 🚧 | + +Flavors with any components labelled as 🚧 are not available as a quick start bundle deployment yet. Please refer to the [DEVELOPMENT.md](./docs/DEVELOPMENT.md) for instructions on how to build a component's Zarf package for local testing. + ## Usage To build a LeapfrogAI UDS bundle and deploy it, please refer to the [LeapfrogAI Documentation Website](https://docs.leapfrog.ai/docs/). In the documentation website, you'll find system requirements and instructions for all things LeapfrogAI that aren't associated to local development and contributing. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index b9759cf3f..a75275760 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -70,7 +70,7 @@ For example, the LeapfrogAI API requires a `config.yaml` be supplied when spun u ## Package Development -If you don't want to [build an entire bundle](#bundle-development), or you want to "dev-loop" on a single package in an existing [UDS Kubernetes cluster](../packages/k3d-gpu/README.md) you can do so by performing the following. +If you don't want to [build an entire bundle](#bundle-development), or you want to "dev-loop" on a single package in an existing [UDS Kubernetes cluster](../packages/k3d-gpu/README.md) you can do so by following the instructions below. For example, this is how you build and (re)deploy a local DEV version of a package: @@ -80,8 +80,9 @@ uds zarf package remove leapfrogai-api --confirm uds zarf tools registry prune --confirm # create and deploy the new package -LOCAL_VERSION=dev REGISTRY_PORT=5000 ARCH=amd64 make build-api -LOCAL_VERSION=dev REGISTRY_PORT=5000 ARCH=amd64 make deploy-api +# FLAVOR can be upstream (default) or registry1 - see README for availability details +LOCAL_VERSION=dev FLAVOR=upstream REGISTRY_PORT=5000 ARCH=amd64 make build-api +LOCAL_VERSION=dev FLAVOR=upstream REGISTRY_PORT=5000 ARCH=amd64 make deploy-api ``` For example, this is how you pull and deploy a LATEST version of a package: @@ -97,17 +98,20 @@ uds zarf package deploy zarf-package-*.tar.zst --confirm 1. Install all the necessary package creation dependencies: ```bash - python -m pip install "huggingface_hub[cli,hf_transfer]" "transformers[torch]" ctranslate2 + python -m pip install ".[dev]" + python -m pip install ".[dev-whisper]" + python -m pip install ".[dev-vllm]" ``` 2. Build all of the packages you need at once with **ONE** of the following Make targets: ```bash - LOCAL_VERSION=dev ARCH=amd64 make build-cpu # ui, api, llama-cpp-python, text-embeddings, whisper, supabase + # FLAVOR can be upstream (default) or registry1 - see README for availability details + LOCAL_VERSION=dev FLAVOR=upstream ARCH=amd64 make build-cpu # ui, api, llama-cpp-python, text-embeddings, whisper, supabase # OR - LOCAL_VERSION=dev ARCH=amd64 make build-gpu # ui, api, vllm, text-embeddings, whisper, supabase + LOCAL_VERSION=dev FLAVOR=upstream ARCH=amd64 make build-gpu # ui, api, vllm, text-embeddings, whisper, supabase # OR - LOCAL_VERSION=dev ARCH=amd64 make build-all # all of the components + LOCAL_VERSION=dev FLAVOR=upstream ARCH=amd64 make build-all # all of the components ``` **OR** @@ -115,13 +119,14 @@ uds zarf package deploy zarf-package-*.tar.zst --confirm You can build components individually using the following Make targets: ```bash - LOCAL_VERSION=dev ARCH=amd64 make build-ui - LOCAL_VERSION=dev ARCH=amd64 make build-api - LOCAL_VERSION=dev ARCH=amd64 make build-supabase - LOCAL_VERSION=dev ARCH=amd64 make build-vllm # if you have NVIDIA GPUs (AMR64 not supported) - LOCAL_VERSION=dev ARCH=amd64 make build-llama-cpp-python # if you have CPU only - LOCAL_VERSION=dev ARCH=amd64 make build-text-embeddings - LOCAL_VERSION=dev ARCH=amd64 make build-whisper + # FLAVOR can be upstream (default) or registry1 - see README for availability details + LOCAL_VERSION=dev FLAVOR=upstream ARCH=amd64 make build-ui + LOCAL_VERSION=dev FLAVOR=upstream ARCH=amd64 make build-api + LOCAL_VERSION=dev FLAVOR=upstream ARCH=amd64 make build-supabase + LOCAL_VERSION=dev FLAVOR=upstream ARCH=amd64 make build-vllm # if you have NVIDIA GPUs (AMR64 not supported) + LOCAL_VERSION=dev FLAVOR=upstream ARCH=amd64 make build-llama-cpp-python # if you have CPU only + LOCAL_VERSION=dev FLAVOR=upstream ARCH=amd64 make build-text-embeddings + LOCAL_VERSION=dev FLAVOR=upstream ARCH=amd64 make build-whisper ``` 3. Create the UDS bundle, modifying the `uds-config.yaml` as required: @@ -148,14 +153,16 @@ To run the same commands in MacOS, you will need to prepend your command with a To demonstrate what this would look like for an Apple Silicon Mac: -``` shell -REG_PORT=5001 ARCH=arm64 LOCAL_VERSION=dev make build-cpu +```bash +# FLAVOR can be upstream (default) or registry1 - see README for availability details +REG_PORT=5001 ARCH=arm64 LOCAL_VERSION=dev FLAVOR=upstream make build-cpu ``` To demonstrate what this would look like for an older Intel Mac: -``` shell -REG_PORT=5001 ARCH=arm64 LOCAL_VERSION=dev make build-cpu +```bash +# FLAVOR can be upstream (default) or registry1 - see README for availability details +REG_PORT=5001 ARCH=arm64 LOCAL_VERSION=dev FLAVOR=upstream make build-cpu ``` ## Access diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile index 4bd36c4ad..de2256e9a 100644 --- a/packages/api/Dockerfile +++ b/packages/api/Dockerfile @@ -2,8 +2,11 @@ ARG LOCAL_VERSION FROM ghcr.io/defenseunicorns/leapfrogai/leapfrogai-sdk:${LOCAL_VERSION} AS sdk FROM ghcr.io/defenseunicorns/leapfrogai/python:3.11-dev AS builder + ARG SDK_DEST=src/leapfrogai_sdk/build + USER root + WORKDIR /leapfrogai # copy the api dependencies over @@ -13,9 +16,9 @@ COPY src/leapfrogai_api src/leapfrogai_api RUN python -m venv .venv ENV PATH="/leapfrogai/.venv/bin:$PATH" -RUN rm -f packages/api/build/*.whl -RUN python -m pip wheel src/leapfrogai_api -w packages/api/build --find-links=${SDK_DEST} -RUN pip install packages/api/build/leapfrogai_api*.whl --no-index --find-links=packages/api/build/ +RUN rm -f packages/api/build/*.whl && \ + python -m pip wheel src/leapfrogai_api -w packages/api/build --find-links=${SDK_DEST} && \ + pip install packages/api/build/leapfrogai_api*.whl --no-index --find-links=packages/api/build/ FROM ghcr.io/defenseunicorns/leapfrogai/python:3.11 ENV PATH="/leapfrogai/.venv/bin:$PATH" diff --git a/packages/api/README.md b/packages/api/README.md index 3d451decb..aa2b34690 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -23,7 +23,7 @@ To build and deploy the API Zarf package into an existing [UDS Kubernetes cluste > Execute the following commands from the root of the LeapfrogAI repository ```bash -make build-api LOCAL_VERSION=dev +make build-api LOCAL_VERSION=dev FLAVOR=upstream uds zarf package deploy packages/api/zarf-package-leapfrogai-api-*-dev.tar.zst --confirm ``` diff --git a/packages/api/chart/Chart.yaml b/packages/api/chart/Chart.yaml index 441339660..fda0acd45 100644 --- a/packages/api/chart/Chart.yaml +++ b/packages/api/chart/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 -name: leapfrogai -description: A deployment of AI tools +name: api +description: "A Python API that shadows the OpenAI API specification" # A chart can be either an 'application' or a 'library' chart. # @@ -23,4 +23,6 @@ version: 0.11.0 # 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.16.0" +# x-release-please-start-version +appVersion: 0.11.0 +# x-release-please-end diff --git a/packages/api/chart/templates/_helpers.tpl b/packages/api/chart/templates/_helpers.tpl new file mode 100644 index 000000000..d40086141 --- /dev/null +++ b/packages/api/chart/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* +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 }} +app: {{ include "chart.fullname" . }} + +{{/* +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.api.serviceAccount.create }} +{{- default (include "chart.fullname" .) .Values.api.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.api.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/packages/api/chart/templates/api/deployment.yaml b/packages/api/chart/templates/api/deployment.yaml index 98ce1fb12..64e7dbccf 100644 --- a/packages/api/chart/templates/api/deployment.yaml +++ b/packages/api/chart/templates/api/deployment.yaml @@ -1,80 +1,86 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: api-deployment + name: {{ include "chart.fullname" . }} namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} spec: - replicas: {{ .Values.api.replcias }} + replicas: {{ .Values.api.replicas }} strategy: rollingUpdate: maxUnavailable: 0 type: RollingUpdate selector: matchLabels: - app: api + {{- include "chart.selectorLabels" . | nindent 6 }} template: metadata: labels: - app: api + {{- include "chart.selectorLabels" . | nindent 8 }} spec: - serviceAccountName: read-configmaps + serviceAccountName: {{ include "chart.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: - name: sidecar - image: kiwigrid/k8s-sidecar:{{ .Values.image.kiwigridTag }} + image: "{{ .Values.kiwigrid.image.repository }}:{{ .Values.kiwigrid.image.tag }}" + imagePullPolicy: {{ .Values.kiwigrid.image.imagePullPolicy }} volumeMounts: - - name: api-model - mountPath: /config/ + - name: api-model + mountPath: /config/ env: - - name: LABEL - value: "leapfrogai" - - name: FOLDER - value: /config/ - - name: RESOURCE - value: both - - name: UNIQUE_FILENAMES - value: "true" - - name: NAMESPACE - value: leapfrogai + - name: LABEL + value: "leapfrogai" + - name: FOLDER + value: /config/ + - name: RESOURCE + value: both + - name: UNIQUE_FILENAMES + value: "true" + - name: NAMESPACE + value: leapfrogai + securityContext: + {{- toYaml .Values.kiwigrid.securityContext | nindent 12 }} - name: api-container - image: ghcr.io/defenseunicorns/leapfrogai/leapfrogai-api:{{ .Values.image.lfaiAPITag }} - imagePullPolicy: Always + image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.api.image.imagePullPolicy }} env: - - name: LFAI_CONFIG_PATH - value: /config/ - - name: LFAI_CONFIG_FILENAME - value: "*.toml" - - name: DEFAULT_EMBEDDINGS_MODEL - value: "{{ .Values.api.defaultEmbeddingsModel }}" - - name: PORT - value: "{{ .Values.api.port }}" - - name: SUPABASE_URL - value: "{{ .Values.supabase.url }}" - - name: SUPABASE_ANON_KEY - valueFrom: - secretKeyRef: - name: supabase-bootstrap-jwt - key: anon-key - optional: true + - name: LFAI_CONFIG_PATH + value: /config/ + - name: LFAI_CONFIG_FILENAME + value: "*.toml" + - name: DEFAULT_EMBEDDINGS_MODEL + value: "{{ .Values.api.env.defaultEmbeddingsModel }}" + - name: PORT + value: "{{ .Values.api.port }}" + - name: SUPABASE_URL + value: "{{ .Values.supabase.env.url }}" + - name: SUPABASE_ANON_KEY + valueFrom: + secretKeyRef: + name: supabase-bootstrap-jwt + key: anon-key + optional: true ports: - - containerPort: 8080 + - containerPort: {{ .Values.api.port }} livenessProbe: httpGet: path: /healthz - port: 8080 + port: {{ .Values.api.port }} initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /healthz - port: 8080 + port: {{ .Values.api.port }} initialDelaySeconds: 10 periodSeconds: 10 securityContext: - runAsUser: 65532 - runAsGroup: 65532 + {{- toYaml .Values.api.securityContext | nindent 12 }} volumeMounts: - - name: api-model - mountPath: /config + - name: api-model + mountPath: /config volumes: - - name: api-model - emptyDir: {} + - name: api-model + emptyDir: {} diff --git a/packages/api/chart/templates/api/permissions.yaml b/packages/api/chart/templates/api/permissions.yaml index 21790f415..3ca06df4b 100644 --- a/packages/api/chart/templates/api/permissions.yaml +++ b/packages/api/chart/templates/api/permissions.yaml @@ -1,34 +1,40 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: read-configmaps + name: {{ include "chart.serviceAccountName" . }} namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: read-configmaps + name: {{ include "chart.fullname" . }}-read-configmaps namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} rules: -- apiGroups: - - "" - resources: - - configmaps - - secrets - verbs: - - get - - list - - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: read-configmaps + name: {{ include "chart.fullname" . }}-read-configmaps namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: read-configmaps + name: {{ include "chart.fullname" . }}-read-configmaps subjects: -- kind: ServiceAccount - name: read-configmaps + - kind: ServiceAccount + name: {{ include "chart.serviceAccountName" . }} diff --git a/packages/api/chart/templates/api/service.yaml b/packages/api/chart/templates/api/service.yaml index 6244f5723..33ea860f6 100644 --- a/packages/api/chart/templates/api/service.yaml +++ b/packages/api/chart/templates/api/service.yaml @@ -1,19 +1,20 @@ apiVersion: v1 kind: Service metadata: - name: api + name: {{ include "chart.fullname" . }} namespace: {{ .Release.Namespace }} annotations: - zarf.dev/connect-description: "Load the OpenAPI spec for the LFAI API" + zarf.dev/connect-description: "Load the OpenAPI specification for the LeapfrogAI API" zarf.dev/connect-url: "/docs" labels: - zarf.dev/connect-name: lfai-api + {{- include "chart.labels" . | nindent 4 }} + zarf.dev/connect-name: {{ include "chart.fullname" . }} spec: selector: - app: api + {{- include "chart.selectorLabels" . | nindent 4 }} ports: - name: http protocol: TCP - port: 8080 - targetPort: 8080 + port: {{ .Values.api.port }} + targetPort: {{ .Values.api.port }} type: ClusterIP diff --git a/packages/api/chart/templates/migration-job.yaml b/packages/api/chart/templates/migration-job.yaml index 1ba7570b3..6b511d7f5 100644 --- a/packages/api/chart/templates/migration-job.yaml +++ b/packages/api/chart/templates/migration-job.yaml @@ -1,37 +1,40 @@ apiVersion: batch/v1 kind: Job metadata: - name: api-migrations-{{ .Values.image.lfaiAPITag }} + name: {{ include "chart.fullname" . }}-migrations-{{ .Values.api.migration.image.tag | default .Chart.AppVersion }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} spec: template: + metadata: + labels: + {{- include "chart.selectorLabels" . | nindent 8 }} spec: + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: - - name: supabase-cli - image: "ghcr.io/defenseunicorns/leapfrogai/api-migrations:{{ .Values.image.lfaiAPITag }}" - env: + - name: supabase-cli + image: "{{ .Values.api.migration.image.repository }}:{{ .Values.api.migration.image.tag | default .Chart.AppVersion }}" + env: - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: supabase-postgresql key: postgres-password - name: MIGRATION_NAMESPACE - value: "{{ .Values.api.migration.namespace }}" + value: "{{ .Release.Namespace }}" - name: MIGRATION_SERVICE_NAME - value: "{{ .Values.api.migration.serviceName }}" + value: "{{ .Values.api.migration.env.serviceName }}" - name: MIGRATION_SERVICE_PORT - value: "{{ .Values.api.migration.servicePort }}" - - # NOTE: This command is assuming the default username. - command: ["/bin/sh"] - args: - - -c - - >- - supabase migration fetch --db-url="postgresql://postgres:$POSTGRES_PASSWORD@$MIGRATION_SERVICE_NAME.$MIGRATION_NAMESPACE.svc.cluster.local:$MIGRATION_SERVICE_PORT/postgres" --debug || true && - supabase db push --db-url="postgresql://postgres:$POSTGRES_PASSWORD@$MIGRATION_SERVICE_NAME.$MIGRATION_NAMESPACE.svc.cluster.local:$MIGRATION_SERVICE_PORT/postgres" --include-all --debug - securityContext: - runAsUser: {{ .Values.image.securityContext.runAsUser }} - runAsGroup: {{ .Values.image.securityContext.runAsGroup }} - securityContext: - fsGroup: {{ .Values.image.securityContext.fsGroup }} + value: "{{ .Values.api.migration.env.servicePort }}" + command: ["/bin/sh"] + args: + - -c + - >- + supabase migration fetch --db-url="postgresql://postgres:$POSTGRES_PASSWORD@$MIGRATION_SERVICE_NAME.$MIGRATION_NAMESPACE.svc.cluster.local:$MIGRATION_SERVICE_PORT/postgres" --debug || true && + supabase db push --db-url="postgresql://postgres:$POSTGRES_PASSWORD@$MIGRATION_SERVICE_NAME.$MIGRATION_NAMESPACE.svc.cluster.local:$MIGRATION_SERVICE_PORT/postgres" --include-all --debug + securityContext: + {{- toYaml .Values.api.migration.securityContext | nindent 12 }} restartPolicy: Never backoffLimit: 4 diff --git a/packages/api/chart/templates/namespace.yaml b/packages/api/chart/templates/namespace.yaml index 0172d6405..8044650e6 100644 --- a/packages/api/chart/templates/namespace.yaml +++ b/packages/api/chart/templates/namespace.yaml @@ -1,4 +1,6 @@ apiVersion: v1 kind: Namespace metadata: - name: leapfrogai + name: {{ .Release.Namespace | default "leapfrogai" }} + labels: + {{- include "chart.labels" . | nindent 4 }} diff --git a/packages/api/chart/templates/uds-package.yaml b/packages/api/chart/templates/uds-package.yaml index 188fafe90..e10dccc89 100644 --- a/packages/api/chart/templates/uds-package.yaml +++ b/packages/api/chart/templates/uds-package.yaml @@ -1,18 +1,20 @@ -{{- if .Values.api.exposeAPI }} +{{- if .Values.api.env.exposeAPI }} apiVersion: uds.dev/v1alpha1 kind: Package metadata: - name: leapfrogai-api + name: {{ include "chart.fullname" . }} namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} spec: network: expose: - - service: api + - service: {{ include "chart.fullname" . }} podLabels: - app: api - host: {{ .Values.package.host }} + {{- include "chart.selectorLabels" . | nindent 10 }} + host: {{ include "chart.fullname" . }} gateway: tenant - port: 8080 + port: {{ .Values.api.port }} allow: - direction: Ingress @@ -23,6 +25,6 @@ spec: - direction: Egress podLabels: - app: api + {{- include "chart.selectorLabels" . | nindent 10 }} remoteGenerated: Anywhere {{- end }} diff --git a/packages/api/chart/values.yaml b/packages/api/chart/values.yaml index 463f941a7..8e1e5ac20 100644 --- a/packages/api/chart/values.yaml +++ b/packages/api/chart/values.yaml @@ -1,27 +1,68 @@ -image: - # x-release-please-start-version - lfaiAPITag: 0.11.0 - # x-release-please-end - kiwigridTag: 1.23.3 +podSecurityContext: + runAsNonRoot: true + fsGroup: 65532 + +api: + image: + repository: ghcr.io/defenseunicorns/leapfrogai/leapfrogai-api + # x-release-please-start-version + tag: 0.11.0 + # x-release-please-end + imagePullPolicy: Always + + replicas: 1 securityContext: runAsUser: 65532 runAsGroup: 65532 - fsGroup: 65532 + runAsNonRoot: true + capabilities: + drop: + - ALL -supabase: - url: "http://supabase-kong.leapfrogai.svc.cluster.local:80" - -api: - replicas: 1 port: 8080 - exposeAPI: true - defaultEmbeddingsModel: "###ZARF_VAR_DEFAULT_EMBEDDINGS_MODEL###" + + env: + exposeAPI: "true" + defaultEmbeddingsModel: "text-embeddings" + + serviceAccount: + name: leapfrogai-api + create: true migration: - namespace: "leapfrogai" - serviceName: "supabase-postgresql" - servicePort: "5432" + image: + repository: ghcr.io/defenseunicorns/leapfrogai/api-migrations + # x-release-please-start-version + tag: 0.11.0 + # x-release-please-end + imagePullPolicy: Always + securityContext: + runAsUser: 65532 + runAsGroup: 65532 + runAsNonRoot: true + capabilities: + drop: + - ALL + + env: + serviceName: "supabase-postgresql" + servicePort: 5432 + +supabase: + env: + url: "http://supabase-kong.leapfrogai.svc.cluster.local:80" -package: - host: leapfrogai-api +kiwigrid: + image: + repository: kiwigrid/k8s-sidecar + tag: 1.23.3 + imagePullPolicy: Always + + securityContext: + runAsUser: 65532 + runAsGroup: 65532 + runAsNonRoot: true + capabilities: + drop: + - ALL diff --git a/packages/api/common/zarf.yaml b/packages/api/common/zarf.yaml new file mode 100644 index 000000000..a4709c24a --- /dev/null +++ b/packages/api/common/zarf.yaml @@ -0,0 +1,28 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/zarf-dev/zarf/main/zarf.schema.json + +kind: ZarfPackageConfig +metadata: + description: "LeapfrogAI API common" + name: leapfrogai-api-common + version: "###ZARF_PKG_TMPL_IMAGE_VERSION###" + +components: + - name: leapfrogai-api + description: "The LeapfrogAI Python API that shadows the OpenAI API specification" + required: true + charts: + - name: leapfrogai + namespace: leapfrogai + localPath: ../chart + # x-release-please-start-version + version: 0.11.0 + # x-release-please-end + actions: + onDeploy: + after: + - wait: + cluster: + kind: Job + name: leapfrogai-api-migrations-###ZARF_PKG_TMPL_IMAGE_VERSION### + namespace: leapfrogai + condition: complete diff --git a/packages/api/config.example.yaml b/packages/api/config.example.yaml deleted file mode 100644 index 07d9242d0..000000000 --- a/packages/api/config.example.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# This is an example configuration file for the API service -# If deploying onto kubernetes, the helm chart will automatically generate the configuration based on config-maps in the cluster -# The code that reads this file exists in `src/leapfrogai_api/utils/config.py` -models: -- name: vllm - backend: localhost:50051 \ No newline at end of file diff --git a/packages/api/lfai-values.yaml b/packages/api/lfai-values.yaml deleted file mode 100644 index 9a7ce1bfa..000000000 --- a/packages/api/lfai-values.yaml +++ /dev/null @@ -1,6 +0,0 @@ -image: - lfaiAPITag: ###ZARF_CONST_LEAPFROGAI_API_VERSION### - kiwigridTag: ###ZARF_CONST_KIWIGRID_VERSION### - -api: - exposeAPI: ###ZARF_VAR_EXPOSE_API### diff --git a/packages/api/values/registry1-values.yaml b/packages/api/values/registry1-values.yaml new file mode 100644 index 000000000..70e3bcad2 --- /dev/null +++ b/packages/api/values/registry1-values.yaml @@ -0,0 +1,21 @@ +api: + image: + repository: registry1.dso.mil/ironbank/opensource/defenseunicorns/leapfrogai/api + # x-release-please-start-version + tag: v0.11.0 + # x-release-please-end + + env: + exposeAPI: "###ZARF_VAR_EXPOSE_API###" + defaultEmbeddingsModel: "###ZARF_VAR_DEFAULT_EMBEDDINGS_MODEL###" + + migration: + image: + # TODO: replace with Ironbank image once hardened: registry1.dso.mil/ironbank/opensource/defenseunicorns/leapfrogai/api/migrations + repository: ghcr.io/defenseunicorns/leapfrogai/api-migrations + tag: ###ZARF_CONST_IMAGE_VERSION### + +kiwigrid: + image: + repository: registry1.dso.mil/ironbank/kiwigrid/k8s-sidecar + tag: 1.23.3 diff --git a/packages/api/values/upstream-values.yaml b/packages/api/values/upstream-values.yaml new file mode 100644 index 000000000..655d18b4f --- /dev/null +++ b/packages/api/values/upstream-values.yaml @@ -0,0 +1,18 @@ +api: + image: + repository: ghcr.io/defenseunicorns/leapfrogai/leapfrogai-api + tag: ###ZARF_CONST_IMAGE_VERSION### + + env: + exposeAPI: "###ZARF_VAR_EXPOSE_API###" + defaultEmbeddingsModel: "###ZARF_VAR_DEFAULT_EMBEDDINGS_MODEL###" + + migration: + image: + repository: ghcr.io/defenseunicorns/leapfrogai/api-migrations + tag: ###ZARF_CONST_IMAGE_VERSION### + +kiwigrid: + image: + repository: kiwigrid/k8s-sidecar + tag: 1.23.3 diff --git a/packages/api/zarf.yaml b/packages/api/zarf.yaml index 926c4aaf1..fb3e6a089 100644 --- a/packages/api/zarf.yaml +++ b/packages/api/zarf.yaml @@ -2,16 +2,13 @@ kind: ZarfPackageConfig metadata: - description: "LeapfrogAI" + description: "LeapfrogAI API" name: leapfrogai-api - version: "###ZARF_PKG_TMPL_LEAPFROGAI_IMAGE_VERSION###" + version: "###ZARF_PKG_TMPL_IMAGE_VERSION###" constants: - - name: LEAPFROGAI_API_VERSION - value: "###ZARF_PKG_TMPL_LEAPFROGAI_IMAGE_VERSION###" - - - name: KIWIGRID_VERSION - value: "1.23.3" + - name: IMAGE_VERSION + value: "###ZARF_PKG_TMPL_IMAGE_VERSION###" variables: - name: EXPOSE_API @@ -21,27 +18,34 @@ variables: default: "text-embeddings" components: - - name: leapfrogai + - name: leapfrogai-api + description: "A Python API that shadows the OpenAI API specification" + only: + flavor: upstream required: true + import: + path: common charts: - - name: leapfrogai - namespace: leapfrogai - localPath: chart - # x-release-please-start-version - version: 0.11.0 - # x-release-please-end - valuesFiles: - - "lfai-values.yaml" + - name: leapfrogai + valuesFiles: + - "values/upstream-values.yaml" images: - - "ghcr.io/defenseunicorns/leapfrogai/leapfrogai-api:###ZARF_PKG_TMPL_LEAPFROGAI_IMAGE_VERSION###" - - "ghcr.io/defenseunicorns/leapfrogai/api-migrations:###ZARF_PKG_TMPL_LEAPFROGAI_IMAGE_VERSION###" + - "ghcr.io/defenseunicorns/leapfrogai/leapfrogai-api:###ZARF_PKG_TMPL_IMAGE_VERSION###" + - "ghcr.io/defenseunicorns/leapfrogai/api-migrations:###ZARF_PKG_TMPL_IMAGE_VERSION###" - "kiwigrid/k8s-sidecar:1.23.3" - actions: - onDeploy: - after: - - wait: - cluster: - kind: Job - name: api-migrations-###ZARF_PKG_TMPL_LEAPFROGAI_IMAGE_VERSION### - namespace: leapfrogai - condition: complete + + - name: leapfrogai-api + only: + flavor: registry1 + required: true + import: + path: common + charts: + - name: leapfrogai + valuesFiles: + - "values/registry1-values.yaml" + images: + - "registry1.dso.mil/ironbank/opensource/defenseunicorns/leapfrogai/api:v0.11.0" + # TODO: replace with Ironbank image once hardened: registry1.dso.mil/ironbank/opensource/defenseunicorns/leapfrogai/api/migrations + - "ghcr.io/defenseunicorns/leapfrogai/api-migrations:###ZARF_PKG_TMPL_IMAGE_VERSION###" + - "registry1.dso.mil/ironbank/kiwigrid/k8s-sidecar:1.23.3" diff --git a/packages/llama-cpp-python/zarf.yaml b/packages/llama-cpp-python/zarf.yaml index 054f09130..0f24d1529 100644 --- a/packages/llama-cpp-python/zarf.yaml +++ b/packages/llama-cpp-python/zarf.yaml @@ -27,6 +27,8 @@ variables: components: - name: llama-cpp-python-model required: true + only: + flavor: upstream charts: - name: llama-cpp-python-model namespace: leapfrogai diff --git a/packages/repeater/zarf.yaml b/packages/repeater/zarf.yaml index 19fb7b665..e69f0604b 100644 --- a/packages/repeater/zarf.yaml +++ b/packages/repeater/zarf.yaml @@ -12,6 +12,8 @@ constants: components: - name: repeater required: true + only: + flavor: upstream charts: - name: repeater namespace: leapfrogai diff --git a/packages/supabase/zarf.yaml b/packages/supabase/zarf.yaml index 094219fcd..6b8e3796c 100644 --- a/packages/supabase/zarf.yaml +++ b/packages/supabase/zarf.yaml @@ -56,6 +56,8 @@ variables: components: - name: supabase required: true + only: + flavor: upstream charts: # This exists because the jwt token job fails to run in the main helm chart at the proper time due to its reliance on `helm.sh/hook: post-install`. # This annotation causes it to run at the end of the Supabase Zarf component. @@ -99,6 +101,8 @@ components: - name: supabase-post-process description: "Perform necessary post processing here" required: true + only: + flavor: upstream actions: onDeploy: before: @@ -120,6 +124,8 @@ components: - name: supabase-migrations description: "Migrations that operate on a database configuration level that require higher elevated permissions (ie adding extensions)" required: true + only: + flavor: upstream charts: - name: supabase-migrations namespace: leapfrogai diff --git a/packages/text-embeddings/zarf.yaml b/packages/text-embeddings/zarf.yaml index bff729139..37e9ce115 100644 --- a/packages/text-embeddings/zarf.yaml +++ b/packages/text-embeddings/zarf.yaml @@ -35,6 +35,8 @@ variables: components: - name: text-embeddings-model required: true + only: + flavor: upstream charts: - name: text-embeddings-model namespace: leapfrogai diff --git a/packages/ui/zarf.yaml b/packages/ui/zarf.yaml index 93ae95896..448e10587 100644 --- a/packages/ui/zarf.yaml +++ b/packages/ui/zarf.yaml @@ -12,7 +12,7 @@ constants: variables: - name: LEAPFROGAI_API_BASE_URL #LEAPFROGAI_API_BASE_URL description: The base URL for the LeapfrogAI API - default: http://api.leapfrogai.svc.cluster.local:8080 + default: http://leapfrogai-api.leapfrogai.svc.cluster.local:8080 prompt: true sensitive: true - name: OPENAI_API_KEY @@ -62,6 +62,8 @@ variables: components: - name: leapfrogai-ui required: true + only: + flavor: upstream charts: - name: leapfrogai-ui namespace: leapfrogai diff --git a/packages/vllm/zarf.yaml b/packages/vllm/zarf.yaml index c48f9914f..8e7dca6cd 100644 --- a/packages/vllm/zarf.yaml +++ b/packages/vllm/zarf.yaml @@ -26,6 +26,8 @@ variables: components: - name: vllm-model required: true + only: + flavor: upstream charts: - name: vllm-model namespace: leapfrogai diff --git a/packages/whisper/zarf.yaml b/packages/whisper/zarf.yaml index e34e8f458..f3fc4215b 100644 --- a/packages/whisper/zarf.yaml +++ b/packages/whisper/zarf.yaml @@ -36,6 +36,8 @@ variables: components: - name: whisper-model required: true + only: + flavor: upstream charts: - name: whisper-model namespace: leapfrogai diff --git a/website/content/en/docs/local-deploy-guide/components.md b/website/content/en/docs/local-deploy-guide/components.md index 7bf1b6550..f062994f0 100644 --- a/website/content/en/docs/local-deploy-guide/components.md +++ b/website/content/en/docs/local-deploy-guide/components.md @@ -27,15 +27,30 @@ Each component has different images and values that refer to a specific image re 1. `upstream`: uses upstream vendor images from open source container registries and repositories 2. 🚧 `registry1`: uses [IronBank hardened images](https://repo1.dso.mil/dsop) from the Repo1 harbor registry -3. 🚧 `unicorn`: uses [Chainguard hardened images](https://www.chainguard.dev/chainguard-images) from the Chainguard registry + +Below is the current component flavors list: + +| Component | `upstream` | `registry1` | +| ---------------------------------------------- | ------------ | ------------- | +| [api](packages/api/) | ✅ | ✅ | +| [ui](packages/ui/) | ✅ | 🚧 | +| [supabase](packages/supabase/) | ✅ | 🚧 | +| [migrations](./Dockerfile.migrations) | ✅ | 🚧 | +| [llama-cpp-python](packages/llama-cpp-python/) | ✅ | 🚧 | +| [whisper](packages/whisper/) | ✅ | 🚧 | +| [text-embeddings](packages/text-embeddings/) | ✅ | 🚧 | +| [vllm](packages/vllm/) | ✅ | 🚧 | +| [vllm](packages/vllm/) | ✅ | 🚧 | + +Flavors with any components labelled as 🚧 are not available as a quick start bundle deployment yet. Please refer to the [DEVELOPMENT.md](https://github.com/defenseunicorns/leapfrogai/blob/main/docs/DEVELOPMENT.md) for instructions on how to build a component's Zarf package for local testing. ### Artifact Support -LeapfrogAI contains built-in embeddings for RAG and transcription / translation solutions that can handle many different file types. Many of these capabilities are accessible via the LeapfrogAI API. The support artifact types are as follows: +LeapfrogAI contains built-in embeddings for RAG and transcription / translation solutions that can handle many different file types. Many of these capabilities are accessible via the LeapfrogAI API. The supported artifact types are as follows: #### Transcription / Translation -- All formats supported by `ffmpeg -formats`, e.g., `.mp3`, `.wav`, `.mp4`, etc. +- All formats supported by `ffmpeg` as listed using `ffmpeg -formats`, e.g., `.mp3`, `.wav`, `.mp4`, etc. #### Embeddings for RAG diff --git a/website/content/en/docs/local-deploy-guide/quick_start.md b/website/content/en/docs/local-deploy-guide/quick_start.md index 63d90ebc6..c58198a7f 100644 --- a/website/content/en/docs/local-deploy-guide/quick_start.md +++ b/website/content/en/docs/local-deploy-guide/quick_start.md @@ -71,7 +71,7 @@ If you already have a pre-built UDS bundle, please skip to [Deploying the UDS Bu 2. Deploy the bundle you created in the [previous steps](#building-the-uds-bundle): ```bash - # make sure you ar ein the directory with the UDS bundle archive + # make sure you are in the directory with the UDS bundle archive uds deploy uds-bundle-leapfrogai*.tar.zst ```