volknode 0.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- volknode-0.2.5/.gitignore +21 -0
- volknode-0.2.5/.netlify/netlify.toml +26 -0
- volknode-0.2.5/.python-version +1 -0
- volknode-0.2.5/=0.20.0 +0 -0
- volknode-0.2.5/PKG-INFO +11 -0
- volknode-0.2.5/README.md +0 -0
- volknode-0.2.5/Taskfile.yml +44 -0
- volknode-0.2.5/gitlab/ci.yml +121 -0
- volknode-0.2.5/gitlab/scripts/run-tests-on-gcloud.sh +252 -0
- volknode-0.2.5/gitlab/scripts/test-installsh.sh +345 -0
- volknode-0.2.5/installsh/install.sh +283 -0
- volknode-0.2.5/pyproject.toml +33 -0
- volknode-0.2.5/pyrightconfig.json +6 -0
- volknode-0.2.5/scripts/generate-code-from-openapi.sh +14 -0
- volknode-0.2.5/uv.lock +845 -0
- volknode-0.2.5/volknode/__init__.py +0 -0
- volknode-0.2.5/volknode/main.py +214 -0
- volknode-0.2.5/volknode/src/core/__init__.py +0 -0
- volknode-0.2.5/volknode/src/core/result.py +26 -0
- volknode-0.2.5/volknode/src/core/validation.py +20 -0
- volknode-0.2.5/volknode/src/csr/__init__.py +0 -0
- volknode-0.2.5/volknode/src/csr/csr_service.py +47 -0
- volknode-0.2.5/volknode/src/csr/key_pair_generator.py +34 -0
- volknode-0.2.5/volknode/src/dependency_resolver.py +33 -0
- volknode-0.2.5/volknode/src/dependency_resolver_test.py +56 -0
- volknode-0.2.5/volknode/src/domain/__init__.py +0 -0
- volknode-0.2.5/volknode/src/domain/csr_credentials.py +7 -0
- volknode-0.2.5/volknode/src/domain/llm_model.py +12 -0
- volknode-0.2.5/volknode/src/domain/llm_node_certificate.py +6 -0
- volknode-0.2.5/volknode/src/domain/nexus_certificate.py +6 -0
- volknode-0.2.5/volknode/src/domain/running_vllm_config.py +7 -0
- volknode-0.2.5/volknode/src/http_client/.gitignore +23 -0
- volknode-0.2.5/volknode/src/http_client/README.md +124 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/__init__.py +8 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/__init__.py +1 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/__init__.py +1 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/change_password.py +197 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/converse.py +178 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/create_personal_access_token.py +193 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/create_user.py +207 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/delay_converse_indefinitely_for_prompt.py +127 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/delete_conversation.py +185 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/delete_user.py +189 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/dislike_message.py +182 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/edit_sent_message.py +196 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/get_app_context.py +150 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/get_conversation_by_id.py +182 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/get_conversations.py +190 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/get_my_profile.py +158 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/is_live.py +141 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/is_ready.py +141 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/like_message.py +182 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/list_personal_access_tokens.py +158 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/login_with_credentials.py +193 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/register_llm_node.py +208 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/rename_conversation.py +206 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/reset_app.py +107 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/retry_ai_response.py +175 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/revoke_personal_access_token.py +196 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/stop_indefinite_converse_answer_for_prompt.py +127 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/view_llm_nodes.py +201 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/api/default/view_users.py +190 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/client.py +271 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/errors.py +14 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/__init__.py +109 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/ai_assistant_started_typing_event.py +76 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/ai_retry_started_event.py +76 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/app_context_response.py +122 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/available_model.py +92 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/business_constraints.py +76 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/change_password_request.py +92 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/conversation.py +84 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/conversation_with_messages.py +110 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/conversations_response.py +118 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/converse_request.py +86 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/converse_response_server_event.py +182 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/converse_response_server_event_event_type.py +12 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/create_personal_access_token_request.py +101 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/create_user_request.py +120 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/delay_converse_indefinitely_for_prompt_request.py +76 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/edit_sent_message_request.py +76 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/edit_sent_message_response_server_event.py +166 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/edit_sent_message_response_server_event_event_type.py +11 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/error.py +101 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/error_event.py +88 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/list_personal_access_tokens_response.py +94 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/logged_in_user.py +100 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/login_with_credentials_request.py +84 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/message.py +120 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/message_author.py +8 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/message_edited_event.py +76 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/my_profile_response.py +122 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/new_conversation_started_event.py +76 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/no_available_models_event.py +84 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/pagination.py +84 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/permissions.py +92 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/personal_access_token_created_successfully.py +92 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/personal_access_token_list_item.py +120 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/prompted_message_saved_event.py +76 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/register_llm_node_request.py +124 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/register_llm_node_response.py +100 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/rename_conversation_request.py +76 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/reply_chunk.py +100 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/reply_chunk_content.py +88 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/reply_chunk_content_content_type.py +7 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/retry_ai_response_response_server_event.py +166 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/retry_ai_response_response_server_event_event_type.py +11 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/stop_indefinite_converse_answer_for_prompt_request.py +76 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/successful_login_response.py +84 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/user_created_successfully.py +108 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/user_resource_operations.py +84 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/user_role.py +88 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/user_role_name.py +8 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/view_llm_nodes_response.py +108 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/view_one_llm_node.py +100 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/view_one_user.py +132 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/models/view_users_response.py +108 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/py.typed +1 -0
- volknode-0.2.5/volknode/src/http_client/ai_suite_client/types.py +53 -0
- volknode-0.2.5/volknode/src/http_client/pyproject.toml +26 -0
- volknode-0.2.5/volknode/src/llm/__init__.py +16 -0
- volknode-0.2.5/volknode/src/llm/allowed_models.py +35 -0
- volknode-0.2.5/volknode/src/llm/fake_llm_runner.py +32 -0
- volknode-0.2.5/volknode/src/llm/fake_vllm_server.py +154 -0
- volknode-0.2.5/volknode/src/llm/llm_integration_test.py +331 -0
- volknode-0.2.5/volknode/src/llm/llm_runner.py +15 -0
- volknode-0.2.5/volknode/src/llm/pulled_model_info.py +9 -0
- volknode-0.2.5/volknode/src/llm/real_llm_runner.py +84 -0
- volknode-0.2.5/volknode/src/mtls/__init__.py +0 -0
- volknode-0.2.5/volknode/src/mtls/mtls_client.py +37 -0
- volknode-0.2.5/volknode/src/mtls/mtls_reverse_proxy.py +76 -0
- volknode-0.2.5/volknode/src/nexus/__init__.py +0 -0
- volknode-0.2.5/volknode/src/nexus/create_personal_access_token_test.py +77 -0
- volknode-0.2.5/volknode/src/nexus/fake_certificate_authority.py +94 -0
- volknode-0.2.5/volknode/src/nexus/fake_nexus.py +105 -0
- volknode-0.2.5/volknode/src/nexus/login_integration_test.py +67 -0
- volknode-0.2.5/volknode/src/nexus/nexus.py +22 -0
- volknode-0.2.5/volknode/src/nexus/real_nexus.py +48 -0
- volknode-0.2.5/volknode/src/nexus/register_llm_node_test.py +420 -0
- volknode-0.2.5/volknode/src/repository/__init__.py +7 -0
- volknode-0.2.5/volknode/src/repository/csr_credentials_repository.py +44 -0
- volknode-0.2.5/volknode/src/repository/llm_model_repository.py +70 -0
- volknode-0.2.5/volknode/src/repository/llm_node_certificate_repository.py +43 -0
- volknode-0.2.5/volknode/src/repository/nexus_certificate_repository.py +43 -0
- volknode-0.2.5/volknode/src/repository/running_vllm_config_repository.py +44 -0
- volknode-0.2.5/volknode/src/usecases/pull_model/__init__.py +0 -0
- volknode-0.2.5/volknode/src/usecases/pull_model/input.py +21 -0
- volknode-0.2.5/volknode/src/usecases/pull_model/interactor.py +20 -0
- volknode-0.2.5/volknode/src/usecases/pull_model/interactor_test.py +77 -0
- volknode-0.2.5/volknode/src/usecases/register_llm_node/__init__.py +0 -0
- volknode-0.2.5/volknode/src/usecases/register_llm_node/input.py +52 -0
- volknode-0.2.5/volknode/src/usecases/register_llm_node/interactor.py +62 -0
- volknode-0.2.5/volknode/src/usecases/register_llm_node/interactor_test.py +285 -0
- volknode-0.2.5/volknode/src/usecases/run_llm_node/__init__.py +0 -0
- volknode-0.2.5/volknode/src/usecases/run_llm_node/input.py +22 -0
- volknode-0.2.5/volknode/src/usecases/run_llm_node/interactor.py +33 -0
- volknode-0.2.5/volknode/src/usecases/run_llm_node/interactor_test.py +119 -0
- volknode-0.2.5/volknode/src/usecases/serve_llm/__init__.py +1 -0
- volknode-0.2.5/volknode/src/usecases/serve_llm/input.py +38 -0
- volknode-0.2.5/volknode/src/usecases/serve_llm/input_test.py +42 -0
- volknode-0.2.5/volknode/src/usecases/serve_llm/interactor.py +45 -0
- volknode-0.2.5/volknode/src/usecases/serve_llm/interactor_test.py +174 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
node_modules
|
|
2
|
+
*.env
|
|
3
|
+
ai-suite/llm-node/.venv
|
|
4
|
+
!*.example.env
|
|
5
|
+
!devcontainer.config.env
|
|
6
|
+
temp
|
|
7
|
+
ai-suite/nexus/src/temp/*
|
|
8
|
+
!ai-suite/nexus/src/temp
|
|
9
|
+
!ai-suite/nexus/src/temp/temp
|
|
10
|
+
|
|
11
|
+
ai-suite/bin
|
|
12
|
+
secrets
|
|
13
|
+
inventory.ini
|
|
14
|
+
|
|
15
|
+
.claude/
|
|
16
|
+
dist/
|
|
17
|
+
gcloud_admin_service_account_key.json
|
|
18
|
+
|
|
19
|
+
__pycache__/
|
|
20
|
+
|
|
21
|
+
.pytest_cache
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
plugins = []
|
|
2
|
+
headers = []
|
|
3
|
+
redirects = []
|
|
4
|
+
|
|
5
|
+
[functions]
|
|
6
|
+
|
|
7
|
+
[functions."*"]
|
|
8
|
+
|
|
9
|
+
[build]
|
|
10
|
+
publish = "/monorepo/ai-suite/llm-node"
|
|
11
|
+
publishOrigin = "default"
|
|
12
|
+
base = "/monorepo/ai-suite/llm-node"
|
|
13
|
+
|
|
14
|
+
[build.environment]
|
|
15
|
+
|
|
16
|
+
[build.processing]
|
|
17
|
+
|
|
18
|
+
[build.processing.css]
|
|
19
|
+
|
|
20
|
+
[build.processing.html]
|
|
21
|
+
|
|
22
|
+
[build.processing.images]
|
|
23
|
+
|
|
24
|
+
[build.processing.js]
|
|
25
|
+
|
|
26
|
+
[build.services]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
volknode-0.2.5/=0.20.0
ADDED
|
File without changes
|
volknode-0.2.5/PKG-INFO
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: volknode
|
|
3
|
+
Version: 0.2.5
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: attrs>=22.2.0
|
|
7
|
+
Requires-Dist: cryptography>=44.0.0
|
|
8
|
+
Requires-Dist: httpx<0.29.0,>=0.23.0
|
|
9
|
+
Requires-Dist: huggingface-hub<1.0,>=0.34.0
|
|
10
|
+
Requires-Dist: python-dateutil>=2.8.0
|
|
11
|
+
Requires-Dist: typer>=0.20.0
|
volknode-0.2.5/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
version: "3"
|
|
2
|
+
vars:
|
|
3
|
+
GITLAB_PROJECT_ID:
|
|
4
|
+
sh: cat ../../global-configuration.json | jq -r ".gitlabProjectId"
|
|
5
|
+
|
|
6
|
+
tasks:
|
|
7
|
+
test:nexus:integration:
|
|
8
|
+
desc: |
|
|
9
|
+
Run integration tests against the nexus backend.
|
|
10
|
+
Requires the nexus backend to be running (use task ai-suite:nexus:containers:keep-up-with-fake-llm-real-ca).
|
|
11
|
+
dir: ./
|
|
12
|
+
cmds:
|
|
13
|
+
- uv run pytest volknode/src/nexus/ -v
|
|
14
|
+
|
|
15
|
+
test:unit:
|
|
16
|
+
desc: Run unit tests
|
|
17
|
+
dir: ./
|
|
18
|
+
cmds:
|
|
19
|
+
- uv run pytest volknode/src/usecases/ -v
|
|
20
|
+
|
|
21
|
+
volknode-with-fake-llm:
|
|
22
|
+
desc: Run volknode with a fake LLM runner
|
|
23
|
+
dir: ./
|
|
24
|
+
cmds:
|
|
25
|
+
- USE_FAKE_LLM=true uv run python -m volknode.main {{.CLI_ARGS}}
|
|
26
|
+
|
|
27
|
+
volknode-with-fake-llm-and-nexus:
|
|
28
|
+
desc: Run volknode with a fake LLM runner
|
|
29
|
+
dir: ./
|
|
30
|
+
cmds:
|
|
31
|
+
- USE_FAKE_LLM=true USE_FAKE_NEXUS=true uv run python -m volknode.main {{.CLI_ARGS}}
|
|
32
|
+
|
|
33
|
+
volknode:
|
|
34
|
+
desc: Run volknode
|
|
35
|
+
dir: ./
|
|
36
|
+
cmds:
|
|
37
|
+
- USE_FAKE_LLM=false uv run python -m volknode.main {{.CLI_ARGS}}
|
|
38
|
+
|
|
39
|
+
build:
|
|
40
|
+
desc: Build volknode executable with PyInstaller
|
|
41
|
+
dir: ./
|
|
42
|
+
cmds:
|
|
43
|
+
- mkdir -p ./installsh/dist
|
|
44
|
+
- cp ./installsh/install.sh ./installsh/dist/
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
stages:
|
|
2
|
+
- commit-stage
|
|
3
|
+
- deploy-to-test
|
|
4
|
+
|
|
5
|
+
variables:
|
|
6
|
+
ENVIRONMENT: CI
|
|
7
|
+
|
|
8
|
+
llm-node-nexus-integration-tests:
|
|
9
|
+
stage: commit-stage
|
|
10
|
+
image:
|
|
11
|
+
name: gitlab.internal.volksai.io:5050/volksai/monorepo/generic-ci-image:latest
|
|
12
|
+
entrypoint: [""]
|
|
13
|
+
pull_policy: if-not-present
|
|
14
|
+
variables:
|
|
15
|
+
TESTCONTAINERS_HOST_OVERRIDE: host.docker.internal
|
|
16
|
+
TESTCONTAINERS_RYUK_DISABLED: "true"
|
|
17
|
+
NEXUS_HOST: host.docker.internal
|
|
18
|
+
NEXUS_CONTAINER_NAME: nexus-$CI_JOB_ID
|
|
19
|
+
LOCAL_ENV_NEXUS_DB_HOST_INTERNALLY_DOCKER: dev-postgres-$CI_JOB_ID
|
|
20
|
+
LOCAL_ENV_NEXUS_DB_PORT_INTERNALLY_DOCKER: "5432"
|
|
21
|
+
LOCAL_ENV_NEXUS_DB_USER: "username"
|
|
22
|
+
LOCAL_ENV_NEXUS_DB_PASSWORD: "password"
|
|
23
|
+
LOCAL_ENV_NEXUS_DB_NAME: "database"
|
|
24
|
+
POSTGRES_VERSION: "17.4"
|
|
25
|
+
rules:
|
|
26
|
+
- if: '$RUN_ALL_TESTS == "true"'
|
|
27
|
+
- if: '$CI_PIPELINE_SOURCE == "push"'
|
|
28
|
+
changes:
|
|
29
|
+
- ai-suite/llm-node/**/*
|
|
30
|
+
- ai-suite/nexus/**/*
|
|
31
|
+
- ai-suite/openapi/**/*
|
|
32
|
+
tags:
|
|
33
|
+
- docker-executor
|
|
34
|
+
before_script:
|
|
35
|
+
- ln -sfn $CI_PROJECT_DIR /monorepo
|
|
36
|
+
- cd $CI_PROJECT_DIR/ai-suite/nexus/local-development/devcontainers && go mod download
|
|
37
|
+
- cd $CI_PROJECT_DIR
|
|
38
|
+
- cd $CI_PROJECT_DIR/ai-suite/llm-node && uv sync & UV_SYNC_PID=$!
|
|
39
|
+
- nohup task ai-suite:nexus:containers:keep-up-with-fake-llm-real-ca > backend-dev.log 2>&1 &
|
|
40
|
+
- $CI_PROJECT_DIR/scripts/wait-for-container.sh $NEXUS_CONTAINER_NAME
|
|
41
|
+
- nexus_port=$(docker inspect --format='{{(index (index .NetworkSettings.Ports "8080/tcp") 0).HostPort}}' $NEXUS_CONTAINER_NAME)
|
|
42
|
+
- $CI_PROJECT_DIR/scripts/wait-for-http-status-200.sh http://host.docker.internal:$nexus_port/chat-backend/is-live
|
|
43
|
+
- echo "NEXUS_PORT=$nexus_port" >> $CI_PROJECT_DIR/nexus.env
|
|
44
|
+
- wait $UV_SYNC_PID
|
|
45
|
+
script:
|
|
46
|
+
- source $CI_PROJECT_DIR/nexus.env
|
|
47
|
+
- NEXUS_PORT=$NEXUS_PORT task ai-suite:llm-node:test:nexus:integration
|
|
48
|
+
after_script:
|
|
49
|
+
- echo "--- backend-dev.log ---" && cat $CI_PROJECT_DIR/backend-dev.log 2>/dev/null || true
|
|
50
|
+
- echo "--- docker ps -a ---" && docker ps -a 2>/dev/null || true
|
|
51
|
+
- echo "Cleaning up job containers"
|
|
52
|
+
- docker stop $NEXUS_CONTAINER_NAME $LOCAL_ENV_NEXUS_DB_HOST_INTERNALLY_DOCKER 2>/dev/null || true
|
|
53
|
+
- docker rm $NEXUS_CONTAINER_NAME $LOCAL_ENV_NEXUS_DB_HOST_INTERNALLY_DOCKER 2>/dev/null || true
|
|
54
|
+
- docker network prune -f 2>/dev/null || true
|
|
55
|
+
|
|
56
|
+
deploy-volksnode-to-pypi:
|
|
57
|
+
stage: deploy-to-test
|
|
58
|
+
needs: []
|
|
59
|
+
allow_failure: true
|
|
60
|
+
retry: 2
|
|
61
|
+
image:
|
|
62
|
+
name: gitlab.internal.volksai.io:5050/volksai/monorepo/generic-ci-image:latest
|
|
63
|
+
entrypoint: [""]
|
|
64
|
+
pull_policy: if-not-present
|
|
65
|
+
rules:
|
|
66
|
+
- if: '$RUN_ALL_TESTS == "true"'
|
|
67
|
+
- if: '$CI_PIPELINE_SOURCE == "push"'
|
|
68
|
+
changes:
|
|
69
|
+
- ai-suite/llm-node/**/*
|
|
70
|
+
tags:
|
|
71
|
+
- docker-executor
|
|
72
|
+
variables:
|
|
73
|
+
UV_PUBLISH_TOKEN: $PYPI_TOKEN
|
|
74
|
+
script:
|
|
75
|
+
- cd $CI_PROJECT_DIR/ai-suite/llm-node
|
|
76
|
+
- uv build
|
|
77
|
+
- uv publish
|
|
78
|
+
|
|
79
|
+
test-llm-node-installsh:
|
|
80
|
+
stage: slow-tests
|
|
81
|
+
resource_group: test-llm-node-installsh
|
|
82
|
+
needs: []
|
|
83
|
+
image:
|
|
84
|
+
name: gitlab.internal.volksai.io:5050/volksai/monorepo/generic-ci-image:latest
|
|
85
|
+
entrypoint: [""]
|
|
86
|
+
pull_policy: if-not-present
|
|
87
|
+
rules:
|
|
88
|
+
- if: '$RUN_ALL_TESTS == "true"'
|
|
89
|
+
- if: '$CI_PIPELINE_SOURCE == "push"'
|
|
90
|
+
changes:
|
|
91
|
+
- ai-suite/llm-node/**/*
|
|
92
|
+
tags:
|
|
93
|
+
- docker-executor
|
|
94
|
+
variables:
|
|
95
|
+
NETLIFY_AUTH_TOKEN: $NETLIFY_AUTH_TOKEN
|
|
96
|
+
NETLIFY_LLM_NODE_INSTALLSH_TEST_SITE_ID: $NETLIFY_LLM_NODE_INSTALLSH_TEST_SITE_ID
|
|
97
|
+
GCLOUD_SERVICE_ACCOUNT_KEY: $GCLOUD_SERVICE_ACCOUNT_KEY
|
|
98
|
+
script:
|
|
99
|
+
- $CI_PROJECT_DIR/gitlab/scripts/configure-resource-group-newest-first.sh test-llm-node-installsh
|
|
100
|
+
- chmod +x $CI_PROJECT_DIR/ai-suite/llm-node/gitlab/scripts/test-installsh.sh
|
|
101
|
+
- $CI_PROJECT_DIR/ai-suite/llm-node/gitlab/scripts/test-installsh.sh
|
|
102
|
+
|
|
103
|
+
llm-node-vllm-integration-tests:
|
|
104
|
+
stage: slow-tests
|
|
105
|
+
resource_group: llm-node-vllm-integration-tests
|
|
106
|
+
needs: []
|
|
107
|
+
image:
|
|
108
|
+
name: gitlab.internal.volksai.io:5050/volksai/monorepo/generic-ci-image:latest
|
|
109
|
+
entrypoint: [""]
|
|
110
|
+
pull_policy: if-not-present
|
|
111
|
+
rules:
|
|
112
|
+
- if: '$RUN_ALL_TESTS == "true"'
|
|
113
|
+
- if: '$CI_PIPELINE_SOURCE == "push"'
|
|
114
|
+
changes:
|
|
115
|
+
- ai-suite/llm-node/**/*
|
|
116
|
+
tags:
|
|
117
|
+
- docker-executor
|
|
118
|
+
script:
|
|
119
|
+
- $CI_PROJECT_DIR/gitlab/scripts/configure-resource-group-newest-first.sh llm-node-vllm-integration-tests
|
|
120
|
+
- chmod +x $CI_PROJECT_DIR/ai-suite/llm-node/gitlab/scripts/run-tests-on-gcloud.sh
|
|
121
|
+
- $CI_PROJECT_DIR/ai-suite/llm-node/gitlab/scripts/run-tests-on-gcloud.sh
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# GCLOUD_PROJECT=${GCLOUD_PROJECT:?"\$GCLOUD_PROJECT must be set"}
|
|
5
|
+
GCLOUD_PROJECT=${GCLOUD_PROJECT:-"llm-node-testing-479012-f6"}
|
|
6
|
+
GCLOUD_ZONES=${GCLOUD_ZONES:-"us-central1-a us-central1-b us-central1-c us-central1-f us-east1-b us-east1-c us-east4-a us-east4-b us-east4-c us-west1-a us-west1-b us-west4-a us-west4-b europe-west1-b europe-west1-c europe-west4-a europe-west4-b europe-west4-c"}
|
|
7
|
+
GCLOUD_MACHINE_TYPE=${GCLOUD_MACHINE_TYPE:-"g2-standard-8"}
|
|
8
|
+
GCLOUD_GPU_TYPE=${GCLOUD_GPU_TYPE:-"nvidia-l4"}
|
|
9
|
+
GCLOUD_GPU_COUNT=${GCLOUD_GPU_COUNT:-1}
|
|
10
|
+
GCLOUD_DISK_SIZE_GB=${GCLOUD_DISK_SIZE_GB:-200}
|
|
11
|
+
GCLOUD_IMAGE_FAMILY=${GCLOUD_IMAGE_FAMILY:-"ubuntu-2204-lts"}
|
|
12
|
+
GCLOUD_IMAGE_PROJECT=${GCLOUD_IMAGE_PROJECT:-"ubuntu-os-cloud"}
|
|
13
|
+
|
|
14
|
+
GCLOUD_SERVICE_ACCOUNT_KEY=${GCLOUD_SERVICE_ACCOUNT_KEY:-""}
|
|
15
|
+
|
|
16
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
17
|
+
REPO_ROOT="${CI_PROJECT_DIR:-$(cd "$SCRIPT_DIR/../../../.." && pwd)}"
|
|
18
|
+
|
|
19
|
+
# Authenticate with gcloud
|
|
20
|
+
echo "=== Authenticating with gcloud ==="
|
|
21
|
+
if [[ -n "$GCLOUD_SERVICE_ACCOUNT_KEY" ]]; then
|
|
22
|
+
echo "$GCLOUD_SERVICE_ACCOUNT_KEY" > /tmp/gcloud-sa-key.json
|
|
23
|
+
gcloud auth activate-service-account --key-file=/tmp/gcloud-sa-key.json
|
|
24
|
+
rm -f /tmp/gcloud-sa-key.json
|
|
25
|
+
else
|
|
26
|
+
echo "Warning: \$GCLOUD_SERVICE_ACCOUNT_KEY not set, assuming gcloud is already authenticated"
|
|
27
|
+
fi
|
|
28
|
+
gcloud config set project "$GCLOUD_PROJECT" --quiet
|
|
29
|
+
|
|
30
|
+
instance_name=""
|
|
31
|
+
GCLOUD_ZONE=""
|
|
32
|
+
|
|
33
|
+
cleanup() {
|
|
34
|
+
echo "=== Cleaning up ==="
|
|
35
|
+
if [[ -n "$instance_name" && -n "$GCLOUD_ZONE" ]]; then
|
|
36
|
+
echo "Deleting GCP instance: $instance_name (zone: $GCLOUD_ZONE)"
|
|
37
|
+
gcloud compute instances delete "$instance_name" \
|
|
38
|
+
--project="$GCLOUD_PROJECT" \
|
|
39
|
+
--zone="$GCLOUD_ZONE" \
|
|
40
|
+
--quiet || true
|
|
41
|
+
echo "Instance deleted"
|
|
42
|
+
fi
|
|
43
|
+
if [[ -n "$gpu_instance_provision_tmp_dir" ]]; then
|
|
44
|
+
rm -rf "$gpu_instance_provision_tmp_dir" || true
|
|
45
|
+
fi
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
trap cleanup EXIT
|
|
49
|
+
|
|
50
|
+
random_unique_tmp_dir_name=$(tr -dc 'a-zA-Z' </dev/urandom | head -c 16)
|
|
51
|
+
gpu_instance_provision_tmp_dir=/tmp/vllm-integration-tests/$random_unique_tmp_dir_name
|
|
52
|
+
gpu_instance_user_private_key_path=$gpu_instance_provision_tmp_dir/gpu_instance_key
|
|
53
|
+
gpu_instance_user_public_key_path=$gpu_instance_provision_tmp_dir/gpu_instance_key.pub
|
|
54
|
+
|
|
55
|
+
rm -rf $gpu_instance_provision_tmp_dir
|
|
56
|
+
mkdir -p $gpu_instance_provision_tmp_dir
|
|
57
|
+
|
|
58
|
+
# Generate SSH key pair
|
|
59
|
+
ssh-keygen -b 2048 -t rsa -f $gpu_instance_user_private_key_path -q -N ""
|
|
60
|
+
llmnode_runner_user_public_key=$(cat $gpu_instance_user_public_key_path)
|
|
61
|
+
chmod 600 $gpu_instance_user_private_key_path
|
|
62
|
+
|
|
63
|
+
instance_name="vllm-integration-test-$(tr -dc 'a-z0-9' </dev/urandom | head -c 8)"
|
|
64
|
+
|
|
65
|
+
# Create startup script that installs NVIDIA drivers, CUDA, and sets up the user.
|
|
66
|
+
# GCP startup scripts run on every boot. After installing NVIDIA drivers, a reboot
|
|
67
|
+
# is required to load the kernel module. The script uses a marker file to track
|
|
68
|
+
# whether the driver install + reboot has already happened.
|
|
69
|
+
startup_script=$(cat <<'STARTUP'
|
|
70
|
+
#!/bin/bash
|
|
71
|
+
exec > /var/log/startup-script.log 2>&1
|
|
72
|
+
set -x
|
|
73
|
+
|
|
74
|
+
# Phase 1: Install NVIDIA drivers and reboot
|
|
75
|
+
if [[ ! -f /var/log/nvidia-driver-installed ]]; then
|
|
76
|
+
apt-get update
|
|
77
|
+
apt-get install -y build-essential linux-headers-$(uname -r) openssh-server sudo curl python3 python3-pip python3-venv
|
|
78
|
+
|
|
79
|
+
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
|
|
80
|
+
distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
|
|
81
|
+
curl -sL "https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list" | \
|
|
82
|
+
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
|
|
83
|
+
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
|
|
84
|
+
|
|
85
|
+
apt-get update
|
|
86
|
+
apt-get install -y nvidia-driver-550
|
|
87
|
+
apt-get install -y cuda-toolkit-12-8
|
|
88
|
+
|
|
89
|
+
echo 'export PATH=/usr/local/cuda/bin:$PATH' >> /etc/profile.d/cuda.sh
|
|
90
|
+
echo 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH' >> /etc/profile.d/cuda.sh
|
|
91
|
+
|
|
92
|
+
touch /var/log/nvidia-driver-installed
|
|
93
|
+
echo "NVIDIA driver installed, rebooting to load kernel module..."
|
|
94
|
+
reboot
|
|
95
|
+
exit 0
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# Phase 2: After reboot — set up user and signal readiness
|
|
99
|
+
if ! id llmnode-runner &>/dev/null; then
|
|
100
|
+
useradd -m -s /bin/bash llmnode-runner
|
|
101
|
+
fi
|
|
102
|
+
echo 'llmnode-runner ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
|
103
|
+
|
|
104
|
+
mkdir -p /home/llmnode-runner/.ssh
|
|
105
|
+
echo 'PUBLIC_KEY_PLACEHOLDER' >> /home/llmnode-runner/.ssh/authorized_keys
|
|
106
|
+
chmod 700 /home/llmnode-runner/.ssh
|
|
107
|
+
chmod 600 /home/llmnode-runner/.ssh/authorized_keys
|
|
108
|
+
chown -R llmnode-runner:llmnode-runner /home/llmnode-runner/.ssh
|
|
109
|
+
|
|
110
|
+
nvidia-smi
|
|
111
|
+
echo "GPU setup complete"
|
|
112
|
+
touch /var/log/startup-script-done
|
|
113
|
+
STARTUP
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
startup_script="${startup_script//PUBLIC_KEY_PLACEHOLDER/$llmnode_runner_user_public_key}"
|
|
117
|
+
|
|
118
|
+
echo "$startup_script" > $gpu_instance_provision_tmp_dir/startup-script.sh
|
|
119
|
+
|
|
120
|
+
# Create the instance, trying each zone until one succeeds
|
|
121
|
+
echo "=== Creating GCP GPU instance ==="
|
|
122
|
+
echo " Project: $GCLOUD_PROJECT"
|
|
123
|
+
echo " Machine type: $GCLOUD_MACHINE_TYPE"
|
|
124
|
+
echo " GPU: ${GCLOUD_GPU_COUNT}x $GCLOUD_GPU_TYPE"
|
|
125
|
+
echo " Disk size: ${GCLOUD_DISK_SIZE_GB}GB"
|
|
126
|
+
echo " Instance name: $instance_name"
|
|
127
|
+
echo " Zones to try: $GCLOUD_ZONES"
|
|
128
|
+
|
|
129
|
+
for zone in $GCLOUD_ZONES; do
|
|
130
|
+
echo "Trying zone: $zone..."
|
|
131
|
+
if gcloud compute instances create "$instance_name" \
|
|
132
|
+
--project="$GCLOUD_PROJECT" \
|
|
133
|
+
--zone="$zone" \
|
|
134
|
+
--machine-type="$GCLOUD_MACHINE_TYPE" \
|
|
135
|
+
--accelerator="type=$GCLOUD_GPU_TYPE,count=$GCLOUD_GPU_COUNT" \
|
|
136
|
+
--maintenance-policy=TERMINATE \
|
|
137
|
+
--boot-disk-size="${GCLOUD_DISK_SIZE_GB}GB" \
|
|
138
|
+
--image-family="$GCLOUD_IMAGE_FAMILY" \
|
|
139
|
+
--image-project="$GCLOUD_IMAGE_PROJECT" \
|
|
140
|
+
--metadata-from-file=startup-script=$gpu_instance_provision_tmp_dir/startup-script.sh 2>&1; then
|
|
141
|
+
GCLOUD_ZONE="$zone"
|
|
142
|
+
echo "Created instance: $instance_name in zone: $GCLOUD_ZONE"
|
|
143
|
+
break
|
|
144
|
+
else
|
|
145
|
+
echo "Zone $zone unavailable, trying next..."
|
|
146
|
+
fi
|
|
147
|
+
done
|
|
148
|
+
|
|
149
|
+
if [[ -z "$GCLOUD_ZONE" ]]; then
|
|
150
|
+
echo "Error: Could not create instance in any zone"
|
|
151
|
+
exit 1
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
# Wait for instance to be running
|
|
155
|
+
echo "=== Waiting for instance to be running ==="
|
|
156
|
+
max_attempts=60
|
|
157
|
+
attempt=0
|
|
158
|
+
while [ $attempt -lt $max_attempts ]; do
|
|
159
|
+
status=$(gcloud compute instances describe "$instance_name" \
|
|
160
|
+
--project="$GCLOUD_PROJECT" \
|
|
161
|
+
--zone="$GCLOUD_ZONE" \
|
|
162
|
+
--format="value(status)")
|
|
163
|
+
|
|
164
|
+
if [[ "$status" == "RUNNING" ]]; then
|
|
165
|
+
echo "Instance is running"
|
|
166
|
+
break
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
echo "Instance status: $status (attempt $((attempt+1))/$max_attempts)"
|
|
170
|
+
sleep 10
|
|
171
|
+
attempt=$((attempt+1))
|
|
172
|
+
done
|
|
173
|
+
|
|
174
|
+
if [[ "$status" != "RUNNING" ]]; then
|
|
175
|
+
echo "Error: Instance did not become ready"
|
|
176
|
+
exit 1
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
ssh_host=$(gcloud compute instances describe "$instance_name" \
|
|
180
|
+
--project="$GCLOUD_PROJECT" \
|
|
181
|
+
--zone="$GCLOUD_ZONE" \
|
|
182
|
+
--format="value(networkInterfaces[0].accessConfigs[0].natIP)")
|
|
183
|
+
|
|
184
|
+
echo "Instance external IP: $ssh_host"
|
|
185
|
+
|
|
186
|
+
# Wait for SSH
|
|
187
|
+
echo "=== Waiting for SSH to be available ==="
|
|
188
|
+
attempt=0
|
|
189
|
+
while [ $attempt -lt 30 ]; do
|
|
190
|
+
if ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
|
191
|
+
-o ConnectTimeout=5 -i $gpu_instance_user_private_key_path \
|
|
192
|
+
llmnode-runner@$ssh_host "echo 'SSH ready'" 2>/dev/null; then
|
|
193
|
+
echo "SSH is ready"
|
|
194
|
+
break
|
|
195
|
+
fi
|
|
196
|
+
echo "Waiting for SSH... (attempt $((attempt+1))/30)"
|
|
197
|
+
sleep 10
|
|
198
|
+
attempt=$((attempt+1))
|
|
199
|
+
done
|
|
200
|
+
|
|
201
|
+
# Wait for startup script to finish (NVIDIA drivers, CUDA)
|
|
202
|
+
echo "=== Waiting for startup script to complete ==="
|
|
203
|
+
attempt=0
|
|
204
|
+
while [ $attempt -lt 60 ]; do
|
|
205
|
+
if ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
|
206
|
+
-o ConnectTimeout=5 -i $gpu_instance_user_private_key_path \
|
|
207
|
+
llmnode-runner@$ssh_host "test -f /var/log/startup-script-done" 2>/dev/null; then
|
|
208
|
+
echo "Startup script completed"
|
|
209
|
+
break
|
|
210
|
+
fi
|
|
211
|
+
echo "Waiting for startup script to finish... (attempt $((attempt+1))/60)"
|
|
212
|
+
sleep 15
|
|
213
|
+
attempt=$((attempt+1))
|
|
214
|
+
done
|
|
215
|
+
|
|
216
|
+
if ! ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
|
217
|
+
-o ConnectTimeout=5 -i $gpu_instance_user_private_key_path \
|
|
218
|
+
llmnode-runner@$ssh_host "test -f /var/log/startup-script-done" 2>/dev/null; then
|
|
219
|
+
echo "Error: Startup script did not complete"
|
|
220
|
+
echo "=== Startup script log ==="
|
|
221
|
+
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
|
222
|
+
-i $gpu_instance_user_private_key_path \
|
|
223
|
+
llmnode-runner@$ssh_host "sudo cat /var/log/startup-script.log" 2>/dev/null || true
|
|
224
|
+
exit 1
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
# Copy test files to instance
|
|
228
|
+
echo "=== Copying test files to GPU instance ==="
|
|
229
|
+
rsync -az --progress \
|
|
230
|
+
-e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i $gpu_instance_user_private_key_path" \
|
|
231
|
+
--exclude='.venv' \
|
|
232
|
+
--exclude='__pycache__' \
|
|
233
|
+
--exclude='.pytest_cache' \
|
|
234
|
+
--exclude='.mypy_cache' \
|
|
235
|
+
--exclude='gitlab' \
|
|
236
|
+
$REPO_ROOT/ai-suite/llm-node/ \
|
|
237
|
+
llmnode-runner@$ssh_host:~/llm-node
|
|
238
|
+
|
|
239
|
+
# Run integration tests
|
|
240
|
+
echo "=== Running vLLM integration tests ==="
|
|
241
|
+
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
|
242
|
+
-i $gpu_instance_user_private_key_path \
|
|
243
|
+
llmnode-runner@$ssh_host \
|
|
244
|
+
"pip install uv && \
|
|
245
|
+
export PATH=\$HOME/.local/bin:/usr/local/cuda/bin:\$PATH && \
|
|
246
|
+
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:\$LD_LIBRARY_PATH && \
|
|
247
|
+
cd ~/llm-node && \
|
|
248
|
+
uv sync && \
|
|
249
|
+
uv pip install vllm && \
|
|
250
|
+
uv run pytest volknode/src/llm/llm_integration_test.py -v"
|
|
251
|
+
|
|
252
|
+
echo "=== vLLM integration tests completed successfully ==="
|