Skip to content

Commit

Permalink
Support limit on init; option to require limit on check/run (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
m4wh6k authored Nov 7, 2022
1 parent 5cf4cc3 commit 7fb5463
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 14 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.7.4
0.7.5
27 changes: 24 additions & 3 deletions src/boardwalk/cli_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from boardwalk.ansible import (
ansible_runner_run_tasks,
AnsibleRunError,
AnsibleRunnerFailedHost,
AnsibleRunnerGeneralError,
AnsibleRunnerUnreachableHost,
Expand All @@ -34,6 +35,12 @@ class runnerKwargs(TypedDict, total=False):


@click.command(short_help="Inits local workspace state by getting host facts")
@click.option(
"--limit",
"-l",
help="An Ansible pattern to limit hosts by. Defaults to no limit",
default="all",
)
@click.option(
"--retry/--no-retry",
"-r/-nr",
Expand All @@ -42,13 +49,17 @@ class runnerKwargs(TypedDict, total=False):
show_default=True,
)
@click.pass_context
def init(ctx: click.Context, retry: bool):
def init(ctx: click.Context, limit: str, retry: bool):
"""
Inits the workspace state with host data. Gathers Ansible facts for hosts
matching the workspaces host pattern. OK to run multiple times; hosts are
only added or updated, never removed by this operation. Use
`boardwalk workspace reset` to clear existing state if needed
"""
if retry and limit != "all":
# We don't allow limit and retry to be specified together at the moment
raise ClickException("--limit and --retry cannot be supplied together")

try:
ws = get_ws()
except NoActiveWorkspace as e:
Expand All @@ -67,19 +78,20 @@ def init(ctx: click.Context, retry: bool):
"gather_facts": False,
"hosts": ws.cfg.host_pattern,
"invocation_msg": "Gathering facts",
"limit": limit,
"tasks": [{"name": "setup", "ansible.builtin.setup": {"gather_timeout": 30}}],
"timeout": 300,
}
if retry:
if not retry_file_path.exists():
raise ClickException("No retry file exists")
runner_kwargs["limit"] = "@" + str(retry_file_path)
runner_kwargs["limit"] = f"@{str(retry_file_path)}"

# Save the host pattern we are initializing with. If the pattern changes after
# this point, other operations will need the state reset and init to be re-done
ws.state.host_pattern = ws.cfg.host_pattern

# Run Ansible.
# Run Ansible
hosts_were_unreachable = False
try:
runner = ansible_runner_run_tasks(**runner_kwargs)
Expand All @@ -92,6 +104,15 @@ def init(ctx: click.Context, retry: bool):
# We note to the user later on if hosts were unreachable
hosts_were_unreachable = True
runner = e.runner
except AnsibleRunError as e:
# If we encounter this error type, there is likely some local error, so
# we try to print out some debug info and bail
for event in e.runner.events:
try:
click.echo(event["stdout"])
except KeyError:
pass
raise ClickException("Failed to start fact gathering")

# Clear the retry file after we use it to start fresh before we build a new one
retry_file_path.unlink(missing_ok=True)
Expand Down
21 changes: 16 additions & 5 deletions src/boardwalk/cli_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"--limit",
"-l",
help="An Ansible pattern to limit hosts by. Defaults to no limit",
default="all",
default="",
)
@click.option(
"--server-connect/--no-server-connect",
Expand Down Expand Up @@ -127,6 +127,16 @@ def run(
if len(ws.state.hosts) == 0:
raise ClickException("No hosts found in state. Have you run `boardwalk init`?")

# Check if a --limit is required for this Workspace
if ws.cfg.require_limit and not limit:
raise ClickException("Workspace requires the --limit option be supplied")

# If no limit is supplied, then the limit is effectively "all"
if limit:
effective_limit = limit
else:
effective_limit = "all"

ws.assert_host_pattern_unchanged()

# Setup boardwalkd client if configured
Expand All @@ -150,7 +160,7 @@ def run(
with concurrent.futures.ThreadPoolExecutor() as executor:
# Process --limit
filter_hosts_by_limit_future = executor.submit(
filter_hosts_by_limit, ws, ws.state.hosts.items(), limit
filter_hosts_by_limit, ws, ws.state.hosts.items(), effective_limit
)
# Get data for inventory_vars used in Jobs
inventory_data_future = executor.submit(ansible_inventory)
Expand All @@ -159,8 +169,9 @@ def run(
except NoHostsMatched:
raise ClickException(
(
"No host matched the given limit pattern. Ensure the host exists"
" in the Ansible inventory and was reachable during `boardwalk init`"
"No host matched the given limit pattern. Ensure the expected"
" hosts exist in the Ansible inventory and confirm they were"
" reachable during `boardwalk init`"
)
)
inventory_vars = inventory_data_future.result()["_meta"]["hostvars"]
Expand Down Expand Up @@ -208,7 +219,7 @@ def run(
"--limit",
"-l",
help="An Ansible pattern to limit hosts by. Defaults to no limit",
default="all",
default="",
)
@click.option(
"--server-connect/--no-server-connect",
Expand Down
21 changes: 16 additions & 5 deletions src/boardwalk/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,20 @@ def exit_jobs(self) -> Job | tuple[Job, ...]:


class WorkspaceConfig:
"""Configuration block for workspaces with defaults validation"""
"""
Configuration block for workspaces
:param default_sort_order: The default order hosts will be walked through
(by hostname). Valid sort orders are specified in the valid_sort_orders
attribute
:param host_pattern: The Ansible host pattern the workspace targets. If this
changes after initialization, the workspace needs to be re-initialized
:param require_limit: `check` and `run` subcommands will require the --limit
option to be passed. This is useful for workspaces configured with a broad
host pattern but workflows should be intentionally down-scoped to a specific
pattern
:param workflow: The workflow the workspace uses
"""

valid_sort_orders = ["ascending", "descending", "shuffle"]

Expand All @@ -190,14 +203,12 @@ def __init__(
host_pattern: str,
workflow: Workflow,
default_sort_order: str = "shuffle",
require_limit: bool = False,
):
self.default_sort_order = default_sort_order
"""The default order hosts will be walked through (by hostname)"""
self.host_pattern = host_pattern
"""The Ansible host pattern the workspace targets. If this changes after
initialization, the workspace needs to be re-initialized"""
self.require_limit = require_limit
self.workflow = workflow
"""The workflow the workspace uses"""

@property
def default_sort_order(self) -> str:
Expand Down

0 comments on commit 7fb5463

Please sign in to comment.