dbos 0.26.0a8__py3-none-any.whl → 0.26.0a10__py3-none-any.whl
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.
- dbos/_client.py +123 -2
- dbos/_dbos_config.py +4 -54
- dbos/_docker_pg_helper.py +191 -0
- dbos/cli/cli.py +17 -1
- dbos/dbos-config.schema.json +0 -4
- {dbos-0.26.0a8.dist-info → dbos-0.26.0a10.dist-info}/METADATA +1 -1
- {dbos-0.26.0a8.dist-info → dbos-0.26.0a10.dist-info}/RECORD +10 -13
- dbos/_cloudutils/authentication.py +0 -163
- dbos/_cloudutils/cloudutils.py +0 -254
- dbos/_cloudutils/databases.py +0 -241
- dbos/_db_wizard.py +0 -220
- {dbos-0.26.0a8.dist-info → dbos-0.26.0a10.dist-info}/WHEEL +0 -0
- {dbos-0.26.0a8.dist-info → dbos-0.26.0a10.dist-info}/entry_points.txt +0 -0
- {dbos-0.26.0a8.dist-info → dbos-0.26.0a10.dist-info}/licenses/LICENSE +0 -0
dbos/_db_wizard.py
DELETED
@@ -1,220 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
import os
|
3
|
-
import time
|
4
|
-
from typing import TYPE_CHECKING, Optional, TypedDict, cast
|
5
|
-
|
6
|
-
import docker # type: ignore
|
7
|
-
import typer
|
8
|
-
import yaml
|
9
|
-
from rich import print
|
10
|
-
from sqlalchemy import URL, create_engine, text
|
11
|
-
|
12
|
-
if TYPE_CHECKING:
|
13
|
-
from ._dbos_config import ConfigFile
|
14
|
-
|
15
|
-
from ._cloudutils.cloudutils import get_cloud_credentials
|
16
|
-
from ._cloudutils.databases import choose_database, get_user_db_credentials
|
17
|
-
from ._error import DBOSInitializationError
|
18
|
-
from ._logger import dbos_logger
|
19
|
-
|
20
|
-
DB_CONNECTION_PATH = os.path.join(".dbos", "db_connection")
|
21
|
-
|
22
|
-
|
23
|
-
class DatabaseConnection(TypedDict):
|
24
|
-
hostname: Optional[str]
|
25
|
-
port: Optional[int]
|
26
|
-
username: Optional[str]
|
27
|
-
password: Optional[str]
|
28
|
-
local_suffix: Optional[bool]
|
29
|
-
|
30
|
-
|
31
|
-
def db_wizard(config: "ConfigFile") -> "ConfigFile":
|
32
|
-
"""Checks database connectivity and helps the user start a database if needed
|
33
|
-
|
34
|
-
First, check connectivity to the database configured in the provided `config` object.
|
35
|
-
If it fails:
|
36
|
-
- Return an error if the connection failed due to incorrect credentials.
|
37
|
-
- Return an error if it detects a non-default configuration.
|
38
|
-
- Otherwise assume the configured database is not running and guide the user through setting it up.
|
39
|
-
|
40
|
-
The wizard will first attempt to start a local Postgres instance using Docker.
|
41
|
-
If Docker is not available, it will prompt the user to connect to a DBOS Cloud database.
|
42
|
-
|
43
|
-
Finally, if a database was configured, its connection details will be saved in the local `.dbos/db_connection` file.
|
44
|
-
"""
|
45
|
-
# 1. Check the connectivity to the database. Return if successful. If cannot connect, continue to the following steps.
|
46
|
-
db_connection_error = _check_db_connectivity(config)
|
47
|
-
if db_connection_error is None:
|
48
|
-
return config
|
49
|
-
|
50
|
-
# 2. If the error is due to password authentication or the configuration is non-default, surface the error and exit.
|
51
|
-
error_str = str(db_connection_error)
|
52
|
-
dbos_logger.debug(f"Error connecting to Postgres: {error_str}")
|
53
|
-
if (
|
54
|
-
"password authentication failed" in error_str
|
55
|
-
or "28P01" in error_str
|
56
|
-
or "no password supplied" in error_str
|
57
|
-
):
|
58
|
-
raise DBOSInitializationError(
|
59
|
-
f"Could not connect to Postgres: password authentication failed: {db_connection_error}"
|
60
|
-
)
|
61
|
-
|
62
|
-
# If the database config is not the default one, surface the error and exit.
|
63
|
-
db_config = config["database"] # FIXME: what if database is not in config?
|
64
|
-
if (
|
65
|
-
db_config["hostname"] != "localhost"
|
66
|
-
or db_config["port"] != 5432
|
67
|
-
or db_config["username"] != "postgres"
|
68
|
-
):
|
69
|
-
raise DBOSInitializationError(
|
70
|
-
f"Could not connect to the database. Exception: {db_connection_error}"
|
71
|
-
)
|
72
|
-
|
73
|
-
print("[yellow]Postgres not detected locally[/yellow]")
|
74
|
-
|
75
|
-
# 3. If the database config is the default one, check if the user has Docker properly installed.
|
76
|
-
print("Attempting to start Postgres via Docker")
|
77
|
-
has_docker = _check_docker_installed()
|
78
|
-
|
79
|
-
# 4. If Docker is installed, prompt the user to start a local Docker based Postgres, and then set the PGPASSWORD to 'dbos' and try to connect to the database.
|
80
|
-
docker_started = False
|
81
|
-
if has_docker:
|
82
|
-
docker_started = _start_docker_postgres(config)
|
83
|
-
else:
|
84
|
-
print("[yellow]Docker not detected locally[/yellow]")
|
85
|
-
|
86
|
-
# 5. If no Docker, then prompt the user to log in to DBOS Cloud and provision a DB there. Wait for the remote DB to be ready, and then create a copy of the original config file, and then load the remote connection string to the local config file.
|
87
|
-
if not docker_started:
|
88
|
-
print("Attempting to connect to Postgres via DBOS Cloud")
|
89
|
-
cred = get_cloud_credentials()
|
90
|
-
db = choose_database(cred)
|
91
|
-
if db is None:
|
92
|
-
raise DBOSInitializationError("Error connecting to cloud database")
|
93
|
-
config["database"]["hostname"] = db.HostName
|
94
|
-
config["database"]["port"] = db.Port
|
95
|
-
if db.SupabaseReference is not None:
|
96
|
-
config["database"]["username"] = f"postgres.{db.SupabaseReference}"
|
97
|
-
supabase_password = typer.prompt(
|
98
|
-
"Enter your Supabase database password", hide_input=True
|
99
|
-
)
|
100
|
-
config["database"]["password"] = supabase_password
|
101
|
-
else:
|
102
|
-
config["database"]["username"] = db.DatabaseUsername
|
103
|
-
db_credentials = get_user_db_credentials(cred, db.PostgresInstanceName)
|
104
|
-
config["database"]["password"] = db_credentials.Password
|
105
|
-
config["database"]["local_suffix"] = True
|
106
|
-
|
107
|
-
# Verify these new credentials work
|
108
|
-
db_connection_error = _check_db_connectivity(config)
|
109
|
-
if db_connection_error is not None:
|
110
|
-
raise DBOSInitializationError(
|
111
|
-
f"Could not connect to the database. Exception: {db_connection_error}"
|
112
|
-
)
|
113
|
-
|
114
|
-
# 6. Save the config to the database connection file
|
115
|
-
updated_connection = DatabaseConnection(
|
116
|
-
hostname=config["database"]["hostname"],
|
117
|
-
port=config["database"]["port"],
|
118
|
-
username=config["database"]["username"],
|
119
|
-
password=config["database"]["password"],
|
120
|
-
local_suffix=config["database"]["local_suffix"],
|
121
|
-
)
|
122
|
-
save_db_connection(updated_connection)
|
123
|
-
return config
|
124
|
-
|
125
|
-
|
126
|
-
def _start_docker_postgres(config: "ConfigFile") -> bool:
|
127
|
-
print("Starting a Postgres Docker container...")
|
128
|
-
client = docker.from_env()
|
129
|
-
pg_data = "/var/lib/postgresql/data"
|
130
|
-
container_name = "dbos-db"
|
131
|
-
client.containers.run(
|
132
|
-
image="pgvector/pgvector:pg16",
|
133
|
-
detach=True,
|
134
|
-
environment={
|
135
|
-
"POSTGRES_PASSWORD": config["database"]["password"],
|
136
|
-
"PGDATA": pg_data,
|
137
|
-
},
|
138
|
-
volumes={pg_data: {"bind": pg_data, "mode": "rw"}},
|
139
|
-
ports={"5432/tcp": config["database"]["port"]},
|
140
|
-
name=container_name,
|
141
|
-
remove=True,
|
142
|
-
)
|
143
|
-
|
144
|
-
container = client.containers.get(container_name)
|
145
|
-
attempts = 30
|
146
|
-
while attempts > 0:
|
147
|
-
if attempts % 5 == 0:
|
148
|
-
print("Waiting for Postgres Docker container to start...")
|
149
|
-
try:
|
150
|
-
res = container.exec_run("psql -U postgres -c 'SELECT 1;'")
|
151
|
-
if res.exit_code != 0:
|
152
|
-
attempts -= 1
|
153
|
-
time.sleep(1)
|
154
|
-
continue
|
155
|
-
print("[green]Postgres Docker container started successfully![/green]")
|
156
|
-
break
|
157
|
-
except:
|
158
|
-
attempts -= 1
|
159
|
-
time.sleep(1)
|
160
|
-
|
161
|
-
if attempts == 0:
|
162
|
-
print("[yellow]Failed to start Postgres Docker container.[/yellow]")
|
163
|
-
return False
|
164
|
-
|
165
|
-
return True
|
166
|
-
|
167
|
-
|
168
|
-
def _check_docker_installed() -> bool:
|
169
|
-
# Check if Docker is installed
|
170
|
-
try:
|
171
|
-
client = docker.from_env()
|
172
|
-
client.ping()
|
173
|
-
except Exception:
|
174
|
-
return False
|
175
|
-
return True
|
176
|
-
|
177
|
-
|
178
|
-
def _check_db_connectivity(config: "ConfigFile") -> Optional[Exception]:
|
179
|
-
postgres_db_url = URL.create(
|
180
|
-
"postgresql+psycopg",
|
181
|
-
username=config["database"]["username"],
|
182
|
-
password=config["database"]["password"],
|
183
|
-
host=config["database"]["hostname"],
|
184
|
-
port=config["database"]["port"],
|
185
|
-
database="postgres",
|
186
|
-
query={"connect_timeout": "2"},
|
187
|
-
)
|
188
|
-
postgres_db_engine = create_engine(postgres_db_url)
|
189
|
-
try:
|
190
|
-
with postgres_db_engine.connect() as conn:
|
191
|
-
conn.execute(text("SELECT 1")).scalar()
|
192
|
-
except Exception as e:
|
193
|
-
return e
|
194
|
-
finally:
|
195
|
-
postgres_db_engine.dispose()
|
196
|
-
|
197
|
-
return None
|
198
|
-
|
199
|
-
|
200
|
-
def load_db_connection() -> DatabaseConnection:
|
201
|
-
try:
|
202
|
-
with open(DB_CONNECTION_PATH, "r") as f:
|
203
|
-
data = json.load(f)
|
204
|
-
return DatabaseConnection(
|
205
|
-
hostname=data.get("hostname", None),
|
206
|
-
port=data.get("port", None),
|
207
|
-
username=data.get("username", None),
|
208
|
-
password=data.get("password", None),
|
209
|
-
local_suffix=data.get("local_suffix", None),
|
210
|
-
)
|
211
|
-
except:
|
212
|
-
return DatabaseConnection(
|
213
|
-
hostname=None, port=None, username=None, password=None, local_suffix=None
|
214
|
-
)
|
215
|
-
|
216
|
-
|
217
|
-
def save_db_connection(connection: DatabaseConnection) -> None:
|
218
|
-
os.makedirs(".dbos", exist_ok=True)
|
219
|
-
with open(DB_CONNECTION_PATH, "w") as f:
|
220
|
-
json.dump(connection, f)
|
File without changes
|
File without changes
|
File without changes
|