Skip to content

Commit 45dd5a2

Browse files
authored
Merge pull request #2882 from fractal-analytics-platform/2875-improve-init-db-data-and-settings
Improve `init-db-data` and settings
2 parents 9e51f84 + d22d6be commit 45dd5a2

File tree

22 files changed

+222
-209
lines changed

22 files changed

+222
-209
lines changed

.github/workflows/benchmarks.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
export JWT_EXPIRE_SECONDS=84600
4545
cd benchmarks/
4646
poetry run fractalctl set-db
47-
poetry run fractalctl init-db-data --resource default --profile default
47+
poetry run fractalctl init-db-data --resource default --profile default --admin-email [email protected] --admin-pwd 1234
4848
poetry run python populate_db/populate_db_script.py
4949
poetry run sh serve.sh
5050

.github/workflows/oauth.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ jobs:
8080
FRACTAL_EMAIL_PASSWORD_KEY: lp3j2FVDkzLd0Rklnzg1pHuV9ClCuDE0aGeJfTNCaW4=
8181
run: |
8282
fractalctl set-db
83-
fractalctl init-db-data --resource default --profile default
83+
fractalctl init-db-data --resource default --profile default --admin-email [email protected] --admin-pwd 1234
8484
fractalctl start --port 8001 &
8585
sleep 2
8686

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ TBD
88
\#2870
99
\#2874
1010
\#2877
11-
\##2884
11+
\#2882
12+
\#2884
1213

1314
# 2.16.6
1415

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
JWT_SECRET_KEY=somethingverysecret
22
FRACTAL_LOGGING_LEVEL=0
33
FRACTAL_RUNNER_BACKEND=local
4-
FRACTAL_ADMIN_DEFAULT_EMAIL=[email protected]
5-
FRACTAL_ADMIN_DEFAULT_PASSWORD=1234
64
JWT_EXPIRE_SECONDS=84600
75
POSTGRES_HOST=/var/run/postgresql
86
POSTGRES_DB=fractal_test

docs/internals/users.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Most attributes are [the default ones from `fastapi-users`](https://fastapi-user
2121

2222
In the startup phase, `fractal-server` creates a default user, who also has the superuser privileges that are necessary for managing other users.
2323
The credentials for this user are defined via the environment variables
24-
[`FRACTAL_ADMIN_DEFAULT_EMAIL`](../configuration.md/#fractal_server.config.Settings.FRACTAL_DEFAULT_ADMIN_EMAIL) (default: `admin@fractal.xy`)
24+
[`FRACTAL_ADMIN_DEFAULT_EMAIL`](../configuration.md/#fractal_server.config.Settings.FRACTAL_DEFAULT_ADMIN_EMAIL) (default: `admin@example.org`)
2525
and
2626
[`FRACTAL_ADMIN_DEFAULT_PASSWORD`](../configuration.md/#fractal_server.config.Settings.FRACTAL_DEFAULT_ADMIN_PASSWORD) (default: `1234`).
2727

@@ -58,7 +58,7 @@ The [Bearer](https://fastapi-users.github.io/fastapi-users/latest/configuration/
5858
$ curl \
5959
-X POST \
6060
-H "Content-Type: application/x-www-form-urlencoded" \
61-
-d "username=admin@fractal.xy&password=1234" \
61+
-d "username=admin@example.org&password=1234" \
6262
http://127.0.0.1:8000/auth/token/login/
6363

6464
{
@@ -75,7 +75,7 @@ The [Cookie](https://fastapi-users.github.io/fastapi-users/latest/configuration/
7575
$ curl \
7676
-X POST \
7777
-H "Content-Type: application/x-www-form-urlencoded" \
78-
-d "username=admin@fractal.xy&password=1234" \
78+
-d "username=admin@example.org&password=1234" \
7979
--cookie-jar - \
8080
http://127.0.0.1:8000/auth/login/
8181

@@ -94,7 +94,7 @@ $ curl \
9494

9595
{
9696
"id":1,
97-
"email":"admin@fractal.xy",
97+
"email":"admin@example.org",
9898
"is_active":true,
9999
"is_superuser":true,
100100
"is_verified":false,
@@ -388,7 +388,7 @@ $ curl \
388388
[
389389
{
390390
"id":1,
391-
"email":"admin@fractal.xy",
391+
"email":"admin@example.org",
392392
"is_active":true,
393393
"is_superuser":true,
394394
"is_verified":false,

example/run_fractal_server.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ set -e
55
# Create and init db
66
createdb fractal-example-test
77
poetry run fractalctl set-db
8-
poetry run fractalctl init-db-data --resource default --profile default
8+
poetry run fractalctl init-db-data --resource default --profile default --admin-email [email protected] --admin-pwd 1234
99

1010
# Start the server
1111
poetry run gunicorn fractal_server.main:app \

fractal_server/__main__.py

Lines changed: 120 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,26 @@
6262
init_db_data_parser.add_argument(
6363
"--resource",
6464
type=str,
65-
help=("Either `default` or path to the JSON file of the first resource."),
66-
required=True,
65+
help="Either `default` or path to the JSON file of the first resource.",
66+
required=False,
6767
)
6868
init_db_data_parser.add_argument(
6969
"--profile",
7070
type=str,
71-
help=("Either `default` or path to the JSON file of the first profile."),
72-
required=True,
71+
help="Either `default` or path to the JSON file of the first profile.",
72+
required=False,
73+
)
74+
init_db_data_parser.add_argument(
75+
"--admin-email",
76+
type=str,
77+
help="Email of the first admin user to create.",
78+
required=False,
79+
)
80+
init_db_data_parser.add_argument(
81+
"--admin-pwd",
82+
type=str,
83+
help="Password of the first admin user to create.",
84+
required=False,
7385
)
7486

7587
# fractalctl update-db-data
@@ -124,119 +136,126 @@ def set_db():
124136

125137

126138
def init_db_data(
127-
*,
128-
resource: str,
129-
profile: str,
139+
resource: str | None = None,
140+
profile: str | None = None,
141+
admin_email: str | None = None,
142+
admin_password: str | None = None,
130143
) -> None:
131144
from fractal_server.app.security import _create_first_user
132145
from fractal_server.app.security import _create_first_group
133-
from fractal_server.syringe import Inject
134-
from fractal_server.config import get_init_data_settings
135146
from fractal_server.app.db import get_sync_db
136147
from sqlalchemy import select, func
137148
from fractal_server.app.models.security import UserOAuth
138149
from fractal_server.app.models import Resource, Profile
139150
from fractal_server.app.schemas.v2.resource import cast_serialize_resource
140151
from fractal_server.app.schemas.v2.profile import cast_serialize_profile
141152

142-
init_data_settings = Inject(get_init_data_settings)
143-
144153
# Create default group and user
145154
print()
146155
_create_first_group()
147156
print()
148-
asyncio.run(
149-
_create_first_user(
150-
email=init_data_settings.FRACTAL_DEFAULT_ADMIN_EMAIL,
151-
password=(
152-
init_data_settings.FRACTAL_DEFAULT_ADMIN_PASSWORD.get_secret_value() # noqa E501
153-
),
154-
is_superuser=True,
155-
is_verified=True,
156-
)
157-
)
158-
print()
159157

160-
# Create resource and profile
161-
with next(get_sync_db()) as db:
162-
# Preliminary check
163-
num_resources = db.execute(select(func.count(Resource.id))).scalar()
164-
if num_resources != 0:
165-
print(f"There exist already {num_resources=} resources. Exit.")
166-
sys.exit(1)
167-
168-
# Get resource/profile data
169-
if resource == "default":
170-
_python_version = (
171-
f"{sys.version_info.major}.{sys.version_info.minor}"
172-
)
173-
resource_data = {
174-
"name": "Local resource",
175-
"type": ResourceType.LOCAL,
176-
"jobs_local_dir": (Path.cwd() / "data-jobs").as_posix(),
177-
"tasks_local_dir": (Path.cwd() / "data-tasks").as_posix(),
178-
"tasks_python_config": {
179-
"default_version": _python_version,
180-
"versions": {
181-
_python_version: sys.executable,
182-
},
183-
},
184-
"jobs_poll_interval": 0,
185-
"jobs_runner_config": {},
186-
"tasks_pixi_config": {},
187-
}
188-
print("Prepared default resource data.")
189-
else:
190-
with open(resource) as f:
191-
resource_data = json.load(f)
192-
print(f"Read resource data from {resource}.")
193-
if profile == "default":
194-
profile_data = {
195-
"resource_type": "local",
196-
"name": "Local profile",
197-
}
198-
print("Prepared default profile data.")
199-
else:
200-
with open(profile) as f:
201-
profile_data = json.load(f)
202-
print(f"Read profile data from {profile}.")
203-
204-
# Validate resource/profile data
205-
try:
206-
resource_data = cast_serialize_resource(resource_data)
207-
except ValidationError as e:
208-
sys.exit(
209-
f"ERROR: Invalid resource data.\nOriginal error:\n{str(e)}"
210-
)
211-
try:
212-
profile_data = cast_serialize_profile(profile_data)
213-
except ValidationError as e:
214-
sys.exit(
215-
f"ERROR: Invalid profile data.\nOriginal error:\n{str(e)}"
158+
# Create admin user if requested
159+
if (admin_email is None) != (admin_password is None):
160+
print("You must provide both --admin-email and --admin-pwd. Exit.")
161+
sys.exit(1)
162+
if admin_password and admin_email:
163+
asyncio.run(
164+
_create_first_user(
165+
email=admin_email,
166+
password=admin_password,
167+
is_superuser=True,
168+
is_verified=True,
216169
)
217-
218-
# Create resource/profile db objects
219-
resource_obj = Resource(**resource_data)
220-
db.add(resource_obj)
221-
db.commit()
222-
db.refresh(resource_obj)
223-
profile_data["resource_id"] = resource_obj.id
224-
profile_obj = Profile(**profile_data)
225-
db.add(profile_obj)
226-
db.commit()
227-
db.refresh(profile_obj)
228-
229-
# Associate profile to users
230-
res = db.execute(select(UserOAuth))
231-
users = res.unique().scalars().all()
232-
for user in users:
233-
print(f"Now set profile_id={profile_obj.id} for {user.email}.")
234-
user.profile_id = profile_obj.id
235-
db.add(user)
236-
db.commit()
237-
db.expunge_all()
170+
)
238171
print()
239172

173+
# Create resource and profile if requested
174+
if (resource is None) != (profile is None):
175+
print("You must provide both --resource and --profile. Exit.")
176+
sys.exit(1)
177+
if resource and profile:
178+
with next(get_sync_db()) as db:
179+
# Preliminary check
180+
num_resources = db.execute(
181+
select(func.count(Resource.id))
182+
).scalar()
183+
if num_resources != 0:
184+
print(f"There exist already {num_resources=} resources. Exit.")
185+
sys.exit(1)
186+
187+
# Get resource/profile data
188+
if resource == "default":
189+
_python_version = (
190+
f"{sys.version_info.major}.{sys.version_info.minor}"
191+
)
192+
resource_data = {
193+
"name": "Local resource",
194+
"type": ResourceType.LOCAL,
195+
"jobs_local_dir": (Path.cwd() / "data-jobs").as_posix(),
196+
"tasks_local_dir": (Path.cwd() / "data-tasks").as_posix(),
197+
"tasks_python_config": {
198+
"default_version": _python_version,
199+
"versions": {
200+
_python_version: sys.executable,
201+
},
202+
},
203+
"jobs_poll_interval": 0,
204+
"jobs_runner_config": {},
205+
"tasks_pixi_config": {},
206+
}
207+
print("Prepared default resource data.")
208+
else:
209+
with open(resource) as f:
210+
resource_data = json.load(f)
211+
print(f"Read resource data from {resource}.")
212+
if profile == "default":
213+
profile_data = {
214+
"resource_type": "local",
215+
"name": "Local profile",
216+
}
217+
print("Prepared default profile data.")
218+
else:
219+
with open(profile) as f:
220+
profile_data = json.load(f)
221+
print(f"Read profile data from {profile}.")
222+
223+
# Validate resource/profile data
224+
try:
225+
resource_data = cast_serialize_resource(resource_data)
226+
except ValidationError as e:
227+
sys.exit(
228+
f"ERROR: Invalid resource data.\nOriginal error:\n{str(e)}"
229+
)
230+
try:
231+
profile_data = cast_serialize_profile(profile_data)
232+
except ValidationError as e:
233+
sys.exit(
234+
f"ERROR: Invalid profile data.\nOriginal error:\n{str(e)}"
235+
)
236+
237+
# Create resource/profile db objects
238+
resource_obj = Resource(**resource_data)
239+
db.add(resource_obj)
240+
db.commit()
241+
db.refresh(resource_obj)
242+
profile_data["resource_id"] = resource_obj.id
243+
profile_obj = Profile(**profile_data)
244+
db.add(profile_obj)
245+
db.commit()
246+
db.refresh(profile_obj)
247+
248+
# Associate profile to users
249+
res = db.execute(select(UserOAuth))
250+
users = res.unique().scalars().all()
251+
for user in users:
252+
print(f"Now set profile_id={profile_obj.id} for {user.email}.")
253+
user.profile_id = profile_obj.id
254+
db.add(user)
255+
db.commit()
256+
db.expunge_all()
257+
print()
258+
240259

241260
def update_db_data():
242261
"""
@@ -328,6 +347,8 @@ def run():
328347
init_db_data(
329348
resource=args.resource,
330349
profile=args.profile,
350+
admin_email=args.admin_email,
351+
admin_password=args.admin_pwd,
331352
)
332353
elif args.cmd == "update-db-data":
333354
update_db_data()

fractal_server/config/__init__.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from ._database import DatabaseSettings
22
from ._email import EmailSettings
33
from ._email import PublicEmailSettings # noqa F401
4-
from ._init_data import InitDataSettings
54
from ._main import Settings
65
from ._oauth import OAuthSettings
76

@@ -18,11 +17,5 @@ def get_email_settings(email_settings=EmailSettings()) -> EmailSettings:
1817
return email_settings
1918

2019

21-
def get_init_data_settings(
22-
init_data_settings=InitDataSettings(),
23-
) -> InitDataSettings:
24-
return init_data_settings
25-
26-
2720
def get_oauth_settings(oauth_settings=OAuthSettings()) -> OAuthSettings:
2821
return oauth_settings

0 commit comments

Comments
 (0)