in airflow-core/src/airflow/cli/commands/config_command.py [0:0]
def update_config(args) -> None:
"""
Update the airflow.cfg file to migrate configuration changes from Airflow 2.x to Airflow 3.
By default, this command will perform a dry-run (showing the changes only) and list only
the breaking configuration changes by scanning the current configuration file for parameters that have
been renamed, removed, or had their default values changed in Airflow 3.0. To see or fix all recommended
changes, use the --all-recommendations argument. To automatically update your airflow.cfg file, use
the --fix argument. This command cleans up the existing comments in airflow.cfg but creates a backup of
the old airflow.cfg file.
CLI Arguments:
--fix: flag (optional)
Automatically fix/apply the breaking changes (or all changes if --all-recommendations is also
specified)
Example: --fix
--all-recommendations: flag (optional)
Include non-breaking (recommended) changes as well as breaking ones.
Can be used with --fix.
Example: --all-recommendations
--section: str (optional)
Comma-separated list of configuration sections to update.
Example: --section core,database
--option: str (optional)
Comma-separated list of configuration options to update.
Example: --option sql_alchemy_conn,dag_concurrency
--ignore-section: str (optional)
Comma-separated list of configuration sections to ignore during update.
Example: --ignore-section webserver
--ignore-option: str (optional)
Comma-separated list of configuration options to ignore during update.
Example: --ignore-option check_slas
Examples:
1. Dry-run mode (print the changes in modified airflow.cfg) showing only breaking changes:
airflow config update
2. Dry-run mode showing all recommendations:
airflow config update --all-recommendations
3. Apply (fix) only breaking changes:
airflow config update --fix
4. Apply (fix) all recommended changes:
airflow config update --fix --all-recommendations
5. Show changes only the specific sections:
airflow config update --section core,database
6.Show changes only the specific options:
airflow config update --option sql_alchemy_conn,dag_concurrency
7. Ignores the specific section:
airflow config update --ignore-section webserver
:param args: The CLI arguments for updating configuration.
"""
console = AirflowConsole()
changes_applied: list[str] = []
modifications = ConfigModifications()
include_all = args.all_recommendations if args.all_recommendations else False
apply_fix = args.fix if args.fix else False
dry_run = not apply_fix
update_sections = args.section if args.section else None
update_options = args.option if args.option else None
ignore_sections = args.ignore_section if args.ignore_section else []
ignore_options = args.ignore_option if args.ignore_option else []
config_dict = conf.as_dict(
display_source=True,
include_env=False,
include_cmds=False,
include_secret=True,
display_sensitive=True,
)
for change in CONFIGS_CHANGES:
if not include_all and not change.breaking:
continue
conf_section = change.config.section.lower()
conf_option = change.config.option.lower()
full_key = f"{conf_section}.{conf_option}"
if update_sections is not None and conf_section not in [s.lower() for s in update_sections]:
continue
if update_options is not None and full_key not in [opt.lower() for opt in update_options]:
continue
if conf_section in [s.lower() for s in ignore_sections] or full_key in [
opt.lower() for opt in ignore_options
]:
continue
if conf_section not in config_dict or conf_option not in config_dict[conf_section]:
continue
value_data = config_dict[conf_section][conf_option]
if not (isinstance(value_data, tuple) and value_data[1] == "airflow.cfg"):
continue
current_value = value_data[0]
prefix = "[[red]BREAKING[/red]]" if change.breaking else "[[yellow]Recommended[/yellow]]"
if change.default_change:
if str(current_value) != str(change.new_default):
modifications.add_default_update(conf_section, conf_option, str(change.new_default))
changes_applied.append(
f"{prefix} Updated default value of '{conf_section}/{conf_option}' from "
f"'{current_value}' to '{change.new_default}'."
)
if change.renamed_to:
modifications.add_rename(
conf_section, conf_option, change.renamed_to.section, change.renamed_to.option
)
changes_applied.append(
f"{prefix} Renamed '{conf_section}/{conf_option}' to "
f"'{change.renamed_to.section.lower()}/{change.renamed_to.option.lower()}'."
)
elif change.was_removed:
if change.remove_if_equals is not None:
if str(current_value) == str(change.remove_if_equals):
modifications.add_remove(conf_section, conf_option)
changes_applied.append(
f"{prefix} Removed '{conf_section}/{conf_option}' from configuration."
)
else:
modifications.add_remove(conf_section, conf_option)
changes_applied.append(f"{prefix} Removed '{conf_section}/{conf_option}' from configuration.")
backup_path = f"{AIRFLOW_CONFIG}.bak"
try:
shutil.copy2(AIRFLOW_CONFIG, backup_path)
console.print(f"Backup saved as '{backup_path}'.")
except Exception as e:
console.print(f"Failed to create backup: {e}")
raise AirflowConfigException("Backup creation failed. Aborting update_config operation.")
if dry_run:
console.print("[blue]Dry-run mode enabled. No changes will be written to airflow.cfg.[/blue]")
with StringIO() as config_output:
conf.write_custom_config(
file=config_output,
comment_out_defaults=True,
include_descriptions=True,
modifications=modifications,
)
new_config = config_output.getvalue()
console.print(new_config)
else:
with open(AIRFLOW_CONFIG, "w") as config_file:
conf.write_custom_config(
file=config_file,
comment_out_defaults=True,
include_descriptions=True,
modifications=modifications,
)
if changes_applied:
console.print("[green]The following are the changes in airflow config:[/green]")
for change_msg in changes_applied:
console.print(f" - {change_msg}")
if dry_run:
console.print(
"[blue]Dry-run is mode enabled. To apply above airflow.cfg run the command "
"with `--fix`.[/blue]"
)
else:
console.print("[green]No updates needed. Your configuration is already up-to-date.[/green]")
if args.verbose:
console.print("[blue]Configuration update completed with verbose output enabled.[/blue]")