Skip to content

Commit

Permalink
Use new API to validate env var config
Browse files Browse the repository at this point in the history
  • Loading branch information
fantix committed Dec 11, 2024
1 parent 0596951 commit d8b875e
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 101 deletions.
18 changes: 9 additions & 9 deletions edb/server/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -2436,7 +2436,7 @@ async def _pg_ensure_database_not_connected(
f'database {dbname!r} is being accessed by other users')


async def _start(ctx: BootstrapContext) -> edbcompiler.CompilerState:
async def _start(ctx: BootstrapContext) -> edbcompiler.Compiler:
conn = await _check_catalog_compatibility(ctx)

try:
Expand All @@ -2445,7 +2445,7 @@ async def _start(ctx: BootstrapContext) -> edbcompiler.CompilerState:
ctx.cluster.overwrite_capabilities(struct.Struct('!Q').unpack(caps)[0])
_check_capabilities(ctx)

return (await edbcompiler.new_compiler_from_pg(conn)).state
return await edbcompiler.new_compiler_from_pg(conn)

finally:
conn.terminate()
Expand Down Expand Up @@ -2473,7 +2473,7 @@ async def _bootstrap_edgedb_super_roles(ctx: BootstrapContext) -> uuid.UUID:
async def _bootstrap(
ctx: BootstrapContext,
no_template: bool=False,
) -> edbcompiler.CompilerState:
) -> edbcompiler.Compiler:
args = ctx.args
cluster = ctx.cluster
backend_params = cluster.get_runtime_params()
Expand Down Expand Up @@ -2690,13 +2690,13 @@ async def _bootstrap(
args.default_database_user or edbdef.EDGEDB_SUPERUSER,
)

return compiler.state
return compiler


async def ensure_bootstrapped(
cluster: pgcluster.BaseCluster,
args: edbargs.ServerConfig,
) -> tuple[bool, edbcompiler.CompilerState]:
) -> tuple[bool, edbcompiler.Compiler]:
"""Bootstraps Gel instance if it hasn't been bootstrapped already.
Returns True if bootstrap happened and False if the instance was already
Expand All @@ -2712,10 +2712,10 @@ async def ensure_bootstrapped(
mode = await _get_cluster_mode(ctx)
ctx = dataclasses.replace(ctx, mode=mode)
if mode == ClusterMode.pristine:
state = await _bootstrap(ctx)
return True, state
compiler = await _bootstrap(ctx)
return True, compiler
else:
state = await _start(ctx)
return False, state
compiler = await _start(ctx)
return False, compiler
finally:
pgconn.terminate()
3 changes: 1 addition & 2 deletions edb/server/compiler/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import immutables

from edb import errors
from edb.common import typeutils, debug
from edb.common import typeutils
from edb.edgeql import ast as qlast
from edb.edgeql import parser as qlparser
from edb.edgeql import qltypes
Expand Down Expand Up @@ -220,7 +220,6 @@ def compile_ast_to_operation(
scope=qltypes.ConfigScope.INSTANCE,
expr=expr,
)
debug.dump_edgeql(cmd)
ir = qlcompiler.compile_ast_to_ir(cmd, schema=schema, options=options)
if (
isinstance(ir, irast.ConfigSet)
Expand Down
2 changes: 1 addition & 1 deletion edb/server/inplace_upgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ async def _upgrade_all(
) -> None:
cluster = ctx.cluster

state = await bootstrap._bootstrap(ctx)
state = (await bootstrap._bootstrap(ctx)).state
databases = await _get_databases(ctx)

assert ctx.args.inplace_upgrade_prepare
Expand Down
156 changes: 67 additions & 89 deletions edb/server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
Tuple,
Union,
Iterator,
Literal,
Mapping,
Dict,
NoReturn,
Expand Down Expand Up @@ -171,7 +172,7 @@ def _internal_state_dir(

async def _init_cluster(
cluster, args: srvargs.ServerConfig
) -> tuple[bool, edbcompiler.CompilerState]:
) -> tuple[bool, edbcompiler.Compiler]:
from edb.server import bootstrap

new_instance = await bootstrap.ensure_bootstrapped(cluster, args)
Expand Down Expand Up @@ -494,6 +495,7 @@ async def run_server(
reflection = s_refl.generate_structure(
stdlib.reflschema, make_funcs=False,
)
del reflection
(
local_intro_sql, global_intro_sql
) = bootstrap.compile_intro_queries_stdlib(
Expand All @@ -512,6 +514,7 @@ async def run_server(
local_intro_query=local_intro_sql,
global_intro_query=global_intro_sql,
)
del local_intro_sql, global_intro_sql
(
sys_queries,
report_configs_typedesc_1_0,
Expand All @@ -525,8 +528,9 @@ async def run_server(
sys_config, backend_settings = initialize_static_cfg(
args,
is_remote_cluster=True,
config_spec=compiler_state.config_spec,
compiler=compiler,
)
del compiler
with _internal_state_dir(runstate_dir, args) as (
int_runstate_dir,
args,
Expand Down Expand Up @@ -604,12 +608,12 @@ async def run_server(
await inplace_upgrade.inplace_upgrade(cluster, args)
return

new_instance, compiler_state = await _init_cluster(cluster, args)
new_instance, compiler = await _init_cluster(cluster, args)

_, backend_settings = initialize_static_cfg(
args,
is_remote_cluster=not is_local_cluster,
config_spec=compiler_state.config_spec,
compiler=compiler,
)

if is_local_cluster and (new_instance or backend_settings):
Expand Down Expand Up @@ -662,7 +666,7 @@ async def run_server(
int_runstate_dir,
do_setproctitle=do_setproctitle,
new_instance=new_instance,
compiler_state=compiler_state,
compiler_state=compiler.state,
)

except server.StartupError as e:
Expand Down Expand Up @@ -797,19 +801,10 @@ def main_dev():
main()


def _coerce_cfg_value(setting: config.Setting, value):
if setting.set_of:
return frozenset(
config.coerce_single_value(setting, v) for v in value
)
else:
return config.coerce_single_value(setting, value)


def initialize_static_cfg(
args: srvargs.ServerConfig,
is_remote_cluster: bool,
config_spec: config.Spec
compiler: edbcompiler.Compiler,
) -> Tuple[Mapping[str, config.SettingValue], Dict[str, str]]:
result = {}
init_con_script_data = []
Expand All @@ -820,85 +815,68 @@ def initialize_static_cfg(
command_line_argument: "command line argument",
environment_variable: "environment variable",
}

def add_config(name, value, type_):
setting = config_spec[name]
if is_remote_cluster:
if setting.backend_setting and setting.requires_restart:
if type_ == command_line_argument:
where = "on command line"
else:
where = "as an environment variable"
raise server.StartupError(
f"Can't set config {name!r} {where} when using "
f"a remote Postgres cluster"
)
value = _coerce_cfg_value(setting, value)
init_con_script_data.append({
"name": name,
"value": config.value_to_json_value(setting, value),
"type": type_,
})
result[name] = config.SettingValue(
name=name,
value=value,
source=sources[type_],
scope=config.ConfigScope.INSTANCE,
)
if setting.backend_setting:
if isinstance(value, statypes.ScalarType):
value = value.to_backend_str()
backend_settings[setting.backend_setting] = str(value)

def iter_environ():
translate_env = {
"EDGEDB_SERVER_BIND_ADDRESS": "listen_addresses",
"EDGEDB_SERVER_PORT": "listen_port",
"GEL_SERVER_BIND_ADDRESS": "listen_addresses",
"GEL_SERVER_PORT": "listen_port",
}
for name, value in os.environ.items():
if cfg := translate_env.get(name):
yield name, value, cfg
config_spec = compiler.state.config_spec

def add_config_values(
obj: dict[str, Any],
source: Literal[command_line_argument, environment_variable],
):
settings = compiler.compile_structured_config(
{"cfg::Config": obj}, source=sources[source]
)["cfg::Config"]
for name, value in settings.items():
setting = config_spec[name]

if is_remote_cluster:
if setting.backend_setting and setting.requires_restart:
if source == command_line_argument:
where = "on command line"
else:
where = "as an environment variable"
raise server.StartupError(
f"Can't set config {name!r} {where} when using "
f"a remote Postgres cluster"
)
init_con_script_data.append({
"name": name,
"value": config.value_to_json_value(setting, value.value),
"type": source,
})
result[name] = value
if setting.backend_setting:
backend_val = value.value
if isinstance(backend_val, statypes.ScalarType):
backend_val = backend_val.to_backend_str()
backend_settings[setting.backend_setting] = str(backend_val)

values = {}
translate_env = {
"EDGEDB_SERVER_BIND_ADDRESS": "listen_addresses",
"EDGEDB_SERVER_PORT": "listen_port",
"GEL_SERVER_BIND_ADDRESS": "listen_addresses",
"GEL_SERVER_PORT": "listen_port",
}
for name, value in os.environ.items():
if cfg := translate_env.get(name):
values[cfg] = value
else:
cfg = name.removeprefix("EDGEDB_SERVER_CONFIG_cfg::")
if cfg != name:
values[cfg] = value
else:
cfg = name.removeprefix("EDGEDB_SERVER_CONFIG_cfg::")
cfg = name.removeprefix("GEL_SERVER_CONFIG_cfg::")
if cfg != name:
yield name, value, cfg
else:
cfg = name.removeprefix("GEL_SERVER_CONFIG_cfg::")
if cfg != name:
yield name, value, cfg

env_value: Any
setting: config.Setting
for env_name, env_value, cfg_name in iter_environ():
try:
setting = config_spec[cfg_name]
except KeyError:
continue
choices = setting.enum_values
if setting.type is bool:
choices = ['true', 'false']
env_value = env_value.lower()
if choices is not None and env_value not in choices:
raise server.StartupError(
f"Environment variable {env_name!r} can only be one of: " +
", ".join(choices)
)
if setting.type is bool:
env_value = env_value == 'true'
elif not issubclass(setting.type, statypes.ScalarType): # type: ignore
env_value = setting.type(env_value) # type: ignore
if setting.set_of:
env_value = (env_value,)
add_config(cfg_name, env_value, environment_variable)
values[cfg] = value
if values:
add_config_values(values, environment_variable)

values = {}
if args.bind_addresses:
add_config(
"listen_addresses", args.bind_addresses, command_line_argument
)
values["listen_addresses"] = args.bind_addresses
if args.port:
add_config("listen_port", args.port, command_line_argument)
values["listen_port"] = args.port
if values:
add_config_values(values, command_line_argument)

if init_con_script_data:
from . import pgcon
Expand Down

0 comments on commit d8b875e

Please sign in to comment.