Fix using a URL for galaxy collection install (#65272)
* Fix using a URL for galaxy collection install * Update lib/ansible/galaxy/collection.py Co-Authored-By: Sloane Hertel <shertel@redhat.com>
This commit is contained in:
parent
41472ee387
commit
694ef5660d
4 changed files with 40 additions and 3 deletions
2
changelogs/fragments/collection-install-url.yaml
Normal file
2
changelogs/fragments/collection-install-url.yaml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
bugfixes:
|
||||||
|
- ansible-galaxy - Fix ``collection install`` when installing from a URL or a file - https://github.com/ansible/ansible/issues/65109
|
|
@ -29,12 +29,14 @@ from ansible.galaxy.role import GalaxyRole
|
||||||
from ansible.galaxy.token import BasicAuthToken, GalaxyToken, KeycloakToken, NoTokenSentinel
|
from ansible.galaxy.token import BasicAuthToken, GalaxyToken, KeycloakToken, NoTokenSentinel
|
||||||
from ansible.module_utils.ansible_release import __version__ as ansible_version
|
from ansible.module_utils.ansible_release import __version__ as ansible_version
|
||||||
from ansible.module_utils._text import to_bytes, to_native, to_text
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
|
from ansible.module_utils import six
|
||||||
from ansible.parsing.yaml.loader import AnsibleLoader
|
from ansible.parsing.yaml.loader import AnsibleLoader
|
||||||
from ansible.playbook.role.requirement import RoleRequirement
|
from ansible.playbook.role.requirement import RoleRequirement
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
from ansible.utils.plugin_docs import get_versioned_doclink
|
from ansible.utils.plugin_docs import get_versioned_doclink
|
||||||
|
|
||||||
display = Display()
|
display = Display()
|
||||||
|
urlparse = six.moves.urllib.parse.urlparse
|
||||||
|
|
||||||
|
|
||||||
class GalaxyCLI(CLI):
|
class GalaxyCLI(CLI):
|
||||||
|
@ -805,6 +807,12 @@ class GalaxyCLI(CLI):
|
||||||
else:
|
else:
|
||||||
requirements = []
|
requirements = []
|
||||||
for collection_input in collections:
|
for collection_input in collections:
|
||||||
|
requirement = None
|
||||||
|
if os.path.isfile(to_bytes(collection_input, errors='surrogate_or_strict')) or \
|
||||||
|
urlparse(collection_input).scheme.lower() in ['http', 'https']:
|
||||||
|
# Arg is a file path or URL to a collection
|
||||||
|
name = collection_input
|
||||||
|
else:
|
||||||
name, dummy, requirement = collection_input.partition(':')
|
name, dummy, requirement = collection_input.partition(':')
|
||||||
requirements.append((name, requirement or '*', None))
|
requirements.append((name, requirement or '*', None))
|
||||||
|
|
||||||
|
|
|
@ -827,9 +827,13 @@ def _get_collection_info(dep_map, existing_collections, collection, requirement,
|
||||||
if os.path.isfile(to_bytes(collection, errors='surrogate_or_strict')):
|
if os.path.isfile(to_bytes(collection, errors='surrogate_or_strict')):
|
||||||
display.vvvv("Collection requirement '%s' is a tar artifact" % to_text(collection))
|
display.vvvv("Collection requirement '%s' is a tar artifact" % to_text(collection))
|
||||||
b_tar_path = to_bytes(collection, errors='surrogate_or_strict')
|
b_tar_path = to_bytes(collection, errors='surrogate_or_strict')
|
||||||
elif urlparse(collection).scheme:
|
elif urlparse(collection).scheme.lower() in ['http', 'https']:
|
||||||
display.vvvv("Collection requirement '%s' is a URL to a tar artifact" % collection)
|
display.vvvv("Collection requirement '%s' is a URL to a tar artifact" % collection)
|
||||||
|
try:
|
||||||
b_tar_path = _download_file(collection, b_temp_path, None, validate_certs)
|
b_tar_path = _download_file(collection, b_temp_path, None, validate_certs)
|
||||||
|
except urllib_error.URLError as err:
|
||||||
|
raise AnsibleError("Failed to download collection tar from '%s': %s"
|
||||||
|
% (to_native(collection), to_native(err)))
|
||||||
|
|
||||||
if b_tar_path:
|
if b_tar_path:
|
||||||
req = CollectionRequirement.from_tar(b_tar_path, force, parent=parent)
|
req = CollectionRequirement.from_tar(b_tar_path, force, parent=parent)
|
||||||
|
|
|
@ -890,6 +890,29 @@ def test_collection_install_in_collection_dir(collection_install, monkeypatch):
|
||||||
assert mock_install.call_args[0][7] is False
|
assert mock_install.call_args[0][7] is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_collection_install_with_url(collection_install):
|
||||||
|
mock_install, dummy, output_dir = collection_install
|
||||||
|
|
||||||
|
galaxy_args = ['ansible-galaxy', 'collection', 'install', 'https://foo/bar/foo-bar-v1.0.0.tar.gz',
|
||||||
|
'--collections-path', output_dir]
|
||||||
|
GalaxyCLI(args=galaxy_args).run()
|
||||||
|
|
||||||
|
collection_path = os.path.join(output_dir, 'ansible_collections')
|
||||||
|
assert os.path.isdir(collection_path)
|
||||||
|
|
||||||
|
assert mock_install.call_count == 1
|
||||||
|
assert mock_install.call_args[0][0] == [('https://foo/bar/foo-bar-v1.0.0.tar.gz', '*', None)]
|
||||||
|
assert mock_install.call_args[0][1] == collection_path
|
||||||
|
assert len(mock_install.call_args[0][2]) == 1
|
||||||
|
assert mock_install.call_args[0][2][0].api_server == 'https://galaxy.ansible.com'
|
||||||
|
assert mock_install.call_args[0][2][0].validate_certs is True
|
||||||
|
assert mock_install.call_args[0][3] is True
|
||||||
|
assert mock_install.call_args[0][4] is False
|
||||||
|
assert mock_install.call_args[0][5] is False
|
||||||
|
assert mock_install.call_args[0][6] is False
|
||||||
|
assert mock_install.call_args[0][7] is False
|
||||||
|
|
||||||
|
|
||||||
def test_collection_install_name_and_requirements_fail(collection_install):
|
def test_collection_install_name_and_requirements_fail(collection_install):
|
||||||
test_path = collection_install[2]
|
test_path = collection_install[2]
|
||||||
expected = 'The positional collection_name arg and --requirements-file are mutually exclusive.'
|
expected = 'The positional collection_name arg and --requirements-file are mutually exclusive.'
|
||||||
|
|
Loading…
Reference in a new issue