Fix using a URL for galaxy collection install (#65272) (#65432)

* Fix using a URL for galaxy collection install

* Update lib/ansible/galaxy/collection.py

Co-Authored-By: Sloane Hertel <shertel@redhat.com>
(cherry picked from commit 694ef5660d)
pull/65015/head^2
Jordan Borean 5 years ago committed by Matt Davis
parent 955cebdd04
commit d93f56dccb

@ -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):
@ -804,6 +806,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))

@ -813,9 +813,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…
Cancel
Save