Skip to content

Commit

Permalink
ansible-galaxy - add config option for the default ansible-galaxy tim…
Browse files Browse the repository at this point in the history
…eout (ansible#81108)

allow configuring the default server timeout via env/ini
  • Loading branch information
s-hertel authored Jun 26, 2023
1 parent e22fe9b commit e780b5e
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 3 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/ansible-galaxy-server-timeout.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- Add a general ``GALAXY_SERVER_TIMEOUT`` config option for distribution servers (https://github.com/ansible/ansible/issues/79833).
13 changes: 10 additions & 3 deletions lib/ansible/cli/galaxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
SERVER_ADDITIONAL = {
'api_version': {'default': None, 'choices': [2, 3]},
'validate_certs': {'cli': [{'name': 'validate_certs'}]},
'timeout': {'default': '60', 'cli': [{'name': 'timeout'}]},
'timeout': {'default': C.GALAXY_SERVER_TIMEOUT, 'cli': [{'name': 'timeout'}]},
'token': {'default': None},
}

Expand Down Expand Up @@ -246,7 +246,11 @@ def init_parser(self):
help='The Ansible Galaxy API key which can be found at '
'https://galaxy.ansible.com/me/preferences.')
common.add_argument('-c', '--ignore-certs', action='store_true', dest='ignore_certs', help='Ignore SSL certificate validation errors.', default=None)
common.add_argument('--timeout', dest='timeout', type=int, default=60,

# --timeout uses the default None to handle two different scenarios.
# * --timeout > C.GALAXY_SERVER_TIMEOUT for non-configured servers
# * --timeout > server-specific timeout > C.GALAXY_SERVER_TIMEOUT for configured servers.
common.add_argument('--timeout', dest='timeout', type=int,
help="The time to wait for operations against the galaxy server, defaults to 60s.")

opt_help.add_verbosity_options(common)
Expand Down Expand Up @@ -621,7 +625,7 @@ def server_config_def(section, key, required, option_type):
return config_def

galaxy_options = {}
for optional_key in ['clear_response_cache', 'no_cache', 'timeout']:
for optional_key in ['clear_response_cache', 'no_cache']:
if optional_key in context.CLIARGS:
galaxy_options[optional_key] = context.CLIARGS[optional_key]

Expand Down Expand Up @@ -697,6 +701,7 @@ def server_config_def(section, key, required, option_type):
cmd_token = GalaxyToken(token=context.CLIARGS['api_key'])

validate_certs = context.CLIARGS['resolved_validate_certs']
default_server_timeout = context.CLIARGS['timeout'] if context.CLIARGS['timeout'] is not None else C.GALAXY_SERVER_TIMEOUT
if cmd_server:
# Cmd args take precedence over the config entry but fist check if the arg was a name and use that config
# entry, otherwise create a new API entry for the server specified.
Expand All @@ -708,6 +713,7 @@ def server_config_def(section, key, required, option_type):
self.galaxy, 'cmd_arg', cmd_server, token=cmd_token,
priority=len(config_servers) + 1,
validate_certs=validate_certs,
timeout=default_server_timeout,
**galaxy_options
))
else:
Expand All @@ -719,6 +725,7 @@ def server_config_def(section, key, required, option_type):
self.galaxy, 'default', C.GALAXY_SERVER, token=cmd_token,
priority=0,
validate_certs=validate_certs,
timeout=default_server_timeout,
**galaxy_options
))

Expand Down
9 changes: 9 additions & 0 deletions lib/ansible/config/base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,15 @@ GALAXY_IGNORE_CERTS:
ini:
- {key: ignore_certs, section: galaxy}
type: boolean
GALAXY_SERVER_TIMEOUT:
name: Default timeout to use for API calls
description:
- The default timeout for Galaxy API calls. Galaxy servers that don't configure a specific timeout will fall back to this value.
env: [{name: ANSIBLE_GALAXY_SERVER_TIMEOUT}]
default: 60
ini:
- {key: server_timeout, section: galaxy}
type: int
GALAXY_ROLE_SKELETON:
name: Galaxy role skeleton directory
description: Role skeleton directory to use as a template for the ``init`` action in ``ansible-galaxy``/``ansible-galaxy role``, same as ``--role-skeleton``.
Expand Down
50 changes: 50 additions & 0 deletions test/units/galaxy/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import ansible.constants as C
from ansible import context
from ansible.cli import galaxy
from ansible.cli.galaxy import GalaxyCLI
from ansible.errors import AnsibleError
from ansible.galaxy import api, collection, token
Expand Down Expand Up @@ -383,6 +384,55 @@ def test_validate_certs_server_config(ignore_certs_cfg, ignore_certs_cli, expect
assert galaxy_cli.api_servers[2].validate_certs is expected_server3_validate_certs


@pytest.mark.parametrize(
["timeout_cli", "timeout_cfg", "timeout_fallback", "expected_timeout"],
[
(None, None, None, 60),
(None, None, 10, 10),
(None, 20, 10, 20),
(30, 20, 10, 30),
]
)
def test_timeout_server_config(timeout_cli, timeout_cfg, timeout_fallback, expected_timeout, monkeypatch):
cli_args = [
'ansible-galaxy',
'collection',
'install',
'namespace.collection:1.0.0',
]
if timeout_cli is not None:
cli_args.extend(["--timeout", f"{timeout_cli}"])

cfg_lines = ["[galaxy]", "server_list=server1"]
if timeout_fallback is not None:
cfg_lines.append(f"server_timeout={timeout_fallback}")

# fix default in server config since C.GALAXY_SERVER_TIMEOUT was already evaluated
server_additional = galaxy.SERVER_ADDITIONAL.copy()
server_additional['timeout']['default'] = timeout_fallback
monkeypatch.setattr(galaxy, 'SERVER_ADDITIONAL', server_additional)

cfg_lines.extend(["[galaxy_server.server1]", "url=https://galaxy.ansible.com/api/"])
if timeout_cfg is not None:
cfg_lines.append(f"timeout={timeout_cfg}")

monkeypatch.setattr(C, 'GALAXY_SERVER_LIST', ['server1'])

with tempfile.NamedTemporaryFile(suffix='.cfg') as tmp_file:
tmp_file.write(to_bytes('\n'.join(cfg_lines), errors='surrogate_or_strict'))
tmp_file.flush()

monkeypatch.setattr(C.config, '_config_file', tmp_file.name)
C.config._parse_config_file()

galaxy_cli = GalaxyCLI(args=cli_args)
mock_execute_install = MagicMock()
monkeypatch.setattr(galaxy_cli, '_execute_install_collection', mock_execute_install)
galaxy_cli.run()

assert galaxy_cli.api_servers[0].timeout == expected_timeout


def test_build_collection_no_galaxy_yaml():
fake_path = u'/fake/ÅÑŚÌβŁÈ/path'
expected = to_native("The collection galaxy.yml path '%s/galaxy.yml' does not exist." % fake_path)
Expand Down

0 comments on commit e780b5e

Please sign in to comment.