Skip to content

Commit

Permalink
Add fallback ref & preference rules for duplicate deployment targets (#…
Browse files Browse the repository at this point in the history
…333)

* Add --prefer option, match appsre env ns based on full path

* Add concept of fallback ref env, add tests
  • Loading branch information
bsquizz authored Oct 20, 2023
1 parent 112b833 commit 9efa5e1
Show file tree
Hide file tree
Showing 7 changed files with 576 additions and 156 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ bonfire deploy advisor --set-image-tag quay.io/cloudservices/advisor-backend=my_
* `--set-template-ref <component>=<ref>` -- use this to change the git ref deployed for just a single component.
* `--set-parameter <component>/<name>=<value>` -- use this to set a parameter value on a specific component's template.
* `--optional-deps-method <hybrid|all|none>` -- change the way that bonfire processes ClowdApp optional dependencies (see "Dependency Processing" section)
* `--prefer PARAM_NAME=PARAM_VALUE` -- in cases where bonfire finds more than one deployment target, use this to set the parameter names and values that should be used to select a "preferred" deployment target. This option can be passed in multiple times. `bonfire` will select the target with the highest amount of "preferred parameters" on it. Default is currently set to `ENV=frontends` to select "stable" frontends in the consoledot environments.


# Interactions with Ephemeral Namespace Operator
Expand Down
76 changes: 65 additions & 11 deletions bonfire/bonfire.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,13 @@ def _validate_set_image_tag(ctx, param, value):
raise click.BadParameter("format must be '<image uri>=<tag>'")


def _validate_set_prefer(ctx, param, value):
try:
return split_equals(value)
except ValueError:
raise click.BadParameter("format must be '<parameter name>=<value>'")


def _validate_opposing_opts(ctx, param, value):
opposite_option = {
"remove_resources": "no_remove_resources",
Expand Down Expand Up @@ -398,6 +405,16 @@ def _validate_opposing_opts(ctx, param, value):
default=conf.EPHEMERAL_ENV_NAME,
show_default=True,
),
click.option(
"--prefer",
help=(
f"When there are multiple deployment targets found in {APP_SRE_SRC}, prefer the ones "
"that have '<parameter name>=<value>' set. Can be specified multiple times."
),
multiple=True,
default=conf.BONFIRE_DEFAULT_PREFER,
callback=_validate_set_prefer,
),
]

_process_options = _app_source_options + [
Expand All @@ -413,7 +430,16 @@ def _validate_opposing_opts(ctx, param, value):
"Use to set default 'ref'/'IMAGE_TAG' for apps."
),
type=str,
default=None,
default=conf.BONFIRE_DEFAULT_REF_ENV,
),
click.option(
"--fallback-ref-env",
help=(
f"Reference environment name in {APP_SRE_SRC} to be used if deployment configuration"
" not found in primary reference environment."
),
type=str,
default=conf.BONFIRE_DEFAULT_FALLBACK_REF_ENV,
),
click.option(
"--set-image-tag",
Expand Down Expand Up @@ -815,17 +841,23 @@ def _describe_namespace(namespace):
click.echo(describe_namespace(namespace))


def _get_apps_config(source, target_env, ref_env, local_config_path, local_config_method):
def _get_apps_config(
source, target_env, ref_env, fallback_ref_env, local_config_path, local_config_method, prefer
):
config = conf.load_config(local_config_path)

if source == APP_SRE_SRC:
log.info("fetching apps config using source: %s, target env: %s", source, target_env)
log.info("fetching target env apps config using source: %s", source)
if not target_env:
_error("target env must be supplied for source '{APP_SRE_SRC}'")
apps_config = get_apps_for_env(target_env)
apps_config = get_apps_for_env(target_env, preferred_params=prefer)

if target_env == conf.EPHEMERAL_ENV_NAME and not ref_env:
log.info("target env is 'ephemeral' with no ref env given, using 'master' for all apps")
if not ref_env and target_env == conf.EPHEMERAL_ENV_NAME:
# set git target to 'master' because ephemeral targets have no git ref defined
log.info(
"target env is '%s' and no ref env given, using 'master' git ref for all apps",
conf.EPHEMERAL_ENV_NAME,
)
for _, app_cfg in apps_config.items():
for component in app_cfg.get("components", []):
component["ref"] = "master"
Expand All @@ -850,9 +882,9 @@ def _get_apps_config(source, target_env, ref_env, local_config_path, local_confi
# re-raise with a bit more context
raise FatalError(f"{str(err)}, hit on app {app_name}")

# handle git ref/image substitutions if reference environment was provided
if ref_env:
log.info("subbing app template refs/image tags using environment: %s", ref_env)
apps_config = sub_refs(apps_config, ref_env)
apps_config = sub_refs(apps_config, ref_env, fallback_ref_env, preferred_params=prefer)

return apps_config

Expand All @@ -876,6 +908,7 @@ def _process(
local_config_method,
set_image_tag,
ref_env,
fallback_ref_env,
target_env,
set_template_ref,
set_parameter,
Expand All @@ -889,9 +922,16 @@ def _process(
component_filter,
local,
frontends,
prefer,
):
apps_config = _get_apps_config(
source, target_env, ref_env, local_config_path, local_config_method
source,
target_env,
ref_env,
fallback_ref_env,
local_config_path,
local_config_method,
prefer,
)

processor = TemplateProcessor(
Expand Down Expand Up @@ -937,6 +977,7 @@ def _cmd_process(
local_config_method,
set_image_tag,
ref_env,
fallback_ref_env,
target_env,
set_template_ref,
set_parameter,
Expand All @@ -951,6 +992,7 @@ def _cmd_process(
component_filter,
local,
frontends,
prefer,
):
"""Fetch and process application templates"""
clowd_env = _get_env_name(namespace, clowd_env)
Expand All @@ -963,6 +1005,7 @@ def _cmd_process(
local_config_method,
set_image_tag,
ref_env,
fallback_ref_env,
target_env,
set_template_ref,
set_parameter,
Expand All @@ -976,6 +1019,7 @@ def _cmd_process(
component_filter,
local,
frontends,
prefer,
)
print(json.dumps(processed_templates, indent=2))

Expand Down Expand Up @@ -1121,6 +1165,7 @@ def _cmd_config_deploy(
local_config_method,
set_image_tag,
ref_env,
fallback_ref_env,
target_env,
set_template_ref,
set_parameter,
Expand All @@ -1145,6 +1190,7 @@ def _cmd_config_deploy(
frontends,
pool,
force,
prefer,
):
"""Process app templates and deploy them to a cluster"""
if not has_clowder():
Expand Down Expand Up @@ -1207,6 +1253,7 @@ def _err_handler(err):
local_config_method,
set_image_tag,
ref_env,
fallback_ref_env,
target_env,
set_template_ref,
set_parameter,
Expand All @@ -1220,6 +1267,7 @@ def _err_handler(err):
component_filter,
local,
frontends,
prefer,
)
log.debug("app configs:\n%s", json.dumps(apps_config, indent=2))
if not apps_config["items"]:
Expand Down Expand Up @@ -1481,9 +1529,12 @@ def _cmd_apps_list(
local_config_method,
target_env,
list_components,
prefer,
):
"""List names of all apps that are marked for deployment in given 'target_env'"""
apps = _get_apps_config(source, target_env, None, local_config_path, local_config_method)
apps = _get_apps_config(
source, target_env, None, None, local_config_path, local_config_method, prefer
)

print("")
sorted_keys = sorted(apps.keys())
Expand All @@ -1508,9 +1559,12 @@ def _cmd_apps_what_depends_on(
local_config_method,
target_env,
component,
prefer,
):
"""Show any apps that depend on COMPONENT for deployments in given 'target_env'"""
apps = _get_apps_config(source, target_env, None, local_config_path, local_config_method)
apps = _get_apps_config(
source, target_env, None, None, local_config_path, local_config_method, prefer
)
found = find_what_depends_on(apps, component)
print("\n".join(found) or f"no apps depending on {component} found")

Expand Down
12 changes: 11 additions & 1 deletion bonfire/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@
QONTRACT_PASSWORD = os.getenv("QONTRACT_PASSWORD", APP_INTERFACE_PASSWORD or None)
QONTRACT_TOKEN = os.getenv("QONTRACT_TOKEN")

BASE_NAMESPACE_NAME = os.getenv("BASE_NAMESPACE_NAME", "ephemeral-base")
BASE_NAMESPACE_PATH = os.getenv(
"BASE_NAMESPACE_PATH",
"/services/insights/ephemeral/namespaces/ephemeral-base.yml",
)
EPHEMERAL_ENV_NAME = os.getenv("EPHEMERAL_ENV_NAME", "insights-ephemeral")
ENV_NAME_FORMAT = os.getenv("ENV_NAME_FORMAT", "env-{namespace}")

Expand All @@ -54,6 +57,13 @@
# set to true when bonfire is running via automation using a bot acct (not an end user)
BONFIRE_BOT = os.getenv("BONFIRE_BOT")

BONFIRE_DEFAULT_PREFER = str(os.getenv("BONFIRE_DEFAULT_PREFER", "ENV_NAME=frontends")).split(",")
BONFIRE_DEFAULT_REF_ENV = str(os.getenv("BONFIRE_DEFAULT_REF_ENV", "insights-stage"))
BONFIRE_DEFAULT_FALLBACK_REF_ENV = str(
os.getenv("BONFIRE_DEFAULT_FALLBACK_REF_ENV", "insights-stage")
)


DEFAULT_FRONTEND_DEPENDENCIES = (
"chrome-service",
"landing-page-frontend",
Expand Down
9 changes: 3 additions & 6 deletions bonfire/namespaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,8 @@ def describe_namespace(project_name: str):

frontends = get_json("frontend", namespace=project_name)
clowdapps = get_json("clowdapp", namespace=project_name)
num_frontends = len(frontends.get('items', []))
num_clowdapps = len(clowdapps.get('items', []))
num_frontends = len(frontends.get("items", []))
num_clowdapps = len(clowdapps.get("items", []))
fe_host, keycloak_url = parse_fe_env(project_name)
kc_creds = get_keycloak_creds(project_name)
project_url = get_console_url()
Expand All @@ -394,10 +394,7 @@ def describe_namespace(project_name: str):
output += f"Project URL: {ns_url}\n"
output += f"Keycloak admin route: {keycloak_url}\n"
output += f"Keycloak admin login: {kc_creds['username']} | {kc_creds['password']}\n"
output += (
f"{num_clowdapps} ClowdApp(s), "
f"{num_frontends} Frontend(s) deployed\n"
)
output += f"{num_clowdapps} ClowdApp(s), " f"{num_frontends} Frontend(s) deployed\n"
output += f"Gateway route: https://{fe_host}\n"
output += f"Default user login: {kc_creds['defaultUsername']} | {kc_creds['defaultPassword']}\n"

Expand Down
Loading

0 comments on commit 9efa5e1

Please sign in to comment.