Skip to content
This repository was archived by the owner on Jun 5, 2025. It is now read-only.

Commit 2858038

Browse files
Merge pull request #284 from stacklok/mount-codegate-volume
Create a `codegate_volume` directory.
2 parents ce9d8dd + 2567a61 commit 2858038

File tree

10 files changed

+44
-32
lines changed

10 files changed

+44
-32
lines changed

Dockerfile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,17 @@ ENV CODEGATE_APP_LOG_LEVEL=WARNING
107107
ENV CODEGATE_LOG_FORMAT=TEXT
108108

109109
# Copy the initial models in the image to default models
110-
RUN mkdir -p /app/default_models && cp /app/models/* /app/default_models/
110+
RUN mkdir -p /app/default_models && cp /app/codegate_volume/models/* /app/default_models/
111111

112112
# Define volume for persistent data
113-
VOLUME ["/app/models"]
113+
VOLUME ["/app/codegate_volume/"]
114114

115-
# give the right permissions
115+
# This has to be performed after copying from the builder stages.
116+
# Otherwise, the permissions will be reset to root.
116117
USER root
117-
RUN chown -R codegate /app/models
118+
RUN mkdir -p /app/codegate_volume/db
119+
# Make codegate user the owner of codegate_volume directory to allow writing to it
120+
RUN chown -R codegate /app/codegate_volume
118121
USER codegate
119122

120123
# Set the container's default entrypoint

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ Unlike E.T., your code never phones home! 🛸 Codegate is designed with privacy
5151
Make sure you have these tools installed:
5252

5353
- 🐳 [Docker](https://docs.docker.com/get-docker/)
54-
- 🔧 [Docker Compose](https://docs.docker.com/compose/install/)
5554
- 🛠️ [jq](https://stedolan.github.io/jq/download/)
5655
- 💻 [VSCode](https://code.visualstudio.com/download)
5756

@@ -155,10 +154,12 @@ docker run -p 8989:8989 -p 8990:80 codegate:latest
155154

156155
# With pre-built pulled image
157156
docker pull ghcr.io/stacklok/codegate/codegate:latest
158-
docker run -p 8989:8989 -p 8990:80 ghcr.io/stacklok/codegate/codegate:latest
157+
docker run --name codegate -d -p 8989:8989 -p 8990:80 ghcr.io/stacklok/codegate/codegate:latest
159158

160-
# With persistent models
161-
docker run -p 8989:8989 -p 8990:80 -v /path/to/volume:/app/models ghcr.io/stacklok/codegate/codegate:latest
159+
# It will mount a volume to /app/codegate_volume
160+
# The directory supports storing Llama CPP models under subidrectoy /models
161+
# A sqlite DB with the messages and alerts is stored under the subdirectory /db
162+
docker run --name codegate -d -v /path/to/volume:/app/codegate_volume -p 8989:8989 -p 8990:80 ghcr.io/stacklok/codegate/codegate:latest
162163
```
163164

164165
### Exposed parameters

config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ log_level: "INFO" # One of: ERROR, WARNING, INFO, DEBUG
1919
##
2020

2121
# Model to use for chatting
22-
model_base_path: "./models"
22+
model_base_path: "./codegate_volume/models"
2323

2424
# Context length of the model
2525
chat_model_n_ctx: 32768

config.yaml.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ provider_urls:
3333
##
3434

3535
# Model to use for chatting
36-
chat_model_path: "./models/qwen2.5-coder-1.5b-instruct-q5_k_m.gguf"
36+
chat_model_path: "./codegate_volume/models/qwen2.5-coder-1.5b-instruct-q5_k_m.gguf"
3737

3838
# Context length of the model
3939
chat_model_n_ctx: 32768

scripts/entrypoint.sh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ CODEGATE_VLLM_URL=${CODEGATE_VLLM_URL:-$DEFAULT_CODEGATE_VLLM_URL}
55
# those are hardcoded on the image, will not change
66
BACKUP_PATH="/tmp/weaviate_backup"
77
BACKUP_NAME="backup"
8-
MODEL_BASE_PATH="/app/models"
8+
MODEL_BASE_PATH="/app/codegate_volume/models"
9+
CODEGATE_DB_FILE="/app/codegate_volume/db/codegate.db"
910

1011
# Function to restore backup if paths are provided
1112
restore_backup() {
@@ -30,8 +31,8 @@ start_dashboard() {
3031
# Function to start the main application
3132
start_application() {
3233
# first restore the models
33-
cp /app/default_models/* /app/models/
34-
CMD_ARGS="--port 8989 --host 0.0.0.0 --vllm-url $CODEGATE_VLLM_URL --model-base-path $MODEL_BASE_PATH"
34+
cp /app/default_models/* /app/codegate_volume/models
35+
CMD_ARGS="--port 8989 --host 0.0.0.0 --vllm-url $CODEGATE_VLLM_URL --model-base-path $MODEL_BASE_PATH --db-path $CODEGATE_DB_FILE"
3536

3637
# Check and append additional URLs if they are set
3738
[ -n "$CODEGATE_OPENAI_URL" ] && CMD_ARGS+=" --openai-url $CODEGATE_OPENAI_URL"

scripts/import_packages.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def __init__(self, jsonl_dir='data', take_backup=True, restore_backup=True):
3535
]
3636
self.client.connect()
3737
self.inference_engine = LlamaCppInferenceEngine()
38-
self.model_path = "./models/all-minilm-L6-v2-q5_k_m.gguf"
38+
self.model_path = "./codegate_volume/models/all-minilm-L6-v2-q5_k_m.gguf"
3939

4040
def restore_backup(self):
4141
if os.getenv("BACKUP_FOLDER"):

src/codegate/cli.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def show_prompts(prompts: Optional[Path]) -> None:
118118
@click.option(
119119
"--model-base-path",
120120
type=str,
121-
default="./models",
121+
default="./codegate_volume/models",
122122
help="Path to the model base directory",
123123
)
124124
@click.option(
@@ -127,6 +127,12 @@ def show_prompts(prompts: Optional[Path]) -> None:
127127
default="all-minilm-L6-v2-q5_k_m.gguf",
128128
help="Name of the model to use for embeddings",
129129
)
130+
@click.option(
131+
"--db-path",
132+
type=str,
133+
default=None,
134+
help="Path to the SQLite database file",
135+
)
130136
def serve(
131137
port: Optional[int],
132138
host: Optional[str],
@@ -140,6 +146,7 @@ def serve(
140146
ollama_url: Optional[str],
141147
model_base_path: Optional[str],
142148
embedding_model: Optional[str],
149+
db_path: Optional[str],
143150
) -> None:
144151
"""Start the codegate server."""
145152
logger = None
@@ -166,6 +173,7 @@ def serve(
166173
cli_provider_urls=cli_provider_urls,
167174
model_base_path=model_base_path,
168175
embedding_model=embedding_model,
176+
db_path=db_path,
169177
)
170178

171179
setup_logging(cfg.log_level, cfg.log_format)
@@ -181,10 +189,11 @@ def serve(
181189
"provider_urls": cfg.provider_urls,
182190
"model_base_path": cfg.model_base_path,
183191
"embedding_model": cfg.embedding_model,
192+
"db_path": cfg.db_path,
184193
},
185194
)
186195

187-
init_db_sync()
196+
init_db_sync(cfg.db_path)
188197
app = init_app()
189198

190199
import uvicorn

src/codegate/config.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ class Config:
3737
log_format: LogFormat = LogFormat.JSON
3838
prompts: PromptConfig = field(default_factory=PromptConfig)
3939

40-
model_base_path: str = "./models"
40+
model_base_path: str = "./codegate_volume/models"
4141
chat_model_n_ctx: int = 32768
4242
chat_model_n_gpu_layers: int = -1
4343
embedding_model: str = "all-minilm-L6-v2-q5_k_m.gguf"
44+
db_path: Optional[str] = None
4445

4546
# Provider URLs with defaults
4647
provider_urls: Dict[str, str] = field(default_factory=lambda: DEFAULT_PROVIDER_URLS.copy())
@@ -178,6 +179,7 @@ def load(
178179
cli_provider_urls: Optional[Dict[str, str]] = None,
179180
model_base_path: Optional[str] = None,
180181
embedding_model: Optional[str] = None,
182+
db_path: Optional[str] = None,
181183
) -> "Config":
182184
"""Load configuration with priority resolution.
183185
@@ -197,6 +199,7 @@ def load(
197199
cli_provider_urls: Optional dict of provider URLs from CLI
198200
model_base_path: Optional path to model base directory
199201
embedding_model: Optional name of the model to use for embeddings
202+
db_path: Optional path to the SQLite database file
200203
201204
Returns:
202205
Config: Resolved configuration
@@ -253,6 +256,8 @@ def load(
253256
config.model_base_path = model_base_path
254257
if embedding_model is not None:
255258
config.embedding_model = embedding_model
259+
if db_path is not None:
260+
config.db_path = db_path
256261

257262
# Set the __config class attribute
258263
Config.__config = config

src/codegate/db/connection.py

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import structlog
1010
from litellm import ChatCompletionRequest, ModelResponse
1111
from pydantic import BaseModel
12-
from sqlalchemy import create_engine, text
12+
from sqlalchemy import text
1313
from sqlalchemy.ext.asyncio import create_async_engine
1414

1515
from codegate.db.models import Alert, Output, Prompt
@@ -29,21 +29,18 @@ def __init__(self, sqlite_path: Optional[str] = None):
2929
# Initialize SQLite database engine with proper async URL
3030
if not sqlite_path:
3131
current_dir = Path(__file__).parent
32-
self._db_path = (current_dir.parent.parent.parent / "codegate.db").absolute()
33-
else:
34-
self._db_path = Path(sqlite_path).absolute()
35-
36-
# Initialize SQLite database engine with proper async URL
37-
current_dir = Path(__file__).parent
38-
self._db_path = (current_dir.parent.parent.parent / "codegate.db").absolute()
32+
sqlite_path = (
33+
current_dir.parent.parent.parent / "codegate_volume" / "db" / "codegate.db"
34+
)
35+
self._db_path = Path(sqlite_path).absolute()
36+
self._db_path.parent.mkdir(parents=True, exist_ok=True)
3937
logger.debug(f"Initializing DB from path: {self._db_path}")
4038
engine_dict = {
4139
"url": f"sqlite+aiosqlite:///{self._db_path}",
4240
"echo": False, # Set to False in production
4341
"isolation_level": "AUTOCOMMIT", # Required for SQLite
4442
}
4543
self._async_db_engine = create_async_engine(**engine_dict)
46-
self._db_engine = create_engine(**engine_dict)
4744

4845
def does_db_exist(self):
4946
return self._db_path.is_file()
@@ -242,13 +239,9 @@ async def get_alerts_with_prompt_and_output(self) -> List[GetAlertsWithPromptAnd
242239
return prompts
243240

244241

245-
def init_db_sync():
242+
def init_db_sync(db_path: Optional[str] = None):
246243
"""DB will be initialized in the constructor in case it doesn't exist."""
247-
db = DbRecorder()
248-
# Remove the DB file if exists for the moment to not cause issues at schema change.
249-
# We can replace this in the future with migrations or something similar.
250-
if db.does_db_exist():
251-
db._db_path.unlink()
244+
db = DbRecorder(db_path)
252245
asyncio.run(db.init_db())
253246

254247

0 commit comments

Comments
 (0)