validate meta/main.yml dependencies and meta/requirements.yml are both lists before concatenating them together (#77821)

This commit is contained in:
Sloane Hertel 2022-05-19 15:04:30 -04:00 committed by GitHub
parent e85e8ee00a
commit 400475acc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 95 additions and 3 deletions

View File

@ -0,0 +1,2 @@
bugfixes:
- ansible-galaxy - Fix unhandled traceback if a role's dependencies in meta/main.yml or meta/requirements.yml are not lists.

View File

@ -1376,9 +1376,10 @@ class GalaxyCLI(CLI):
# install dependencies, if we want them
if not no_deps and installed:
if not role.metadata:
# NOTE: the meta file is also required for installing the role, not just dependencies
display.warning("Meta file %s is empty. Skipping dependencies." % role.path)
else:
role_dependencies = (role.metadata.get('dependencies') or []) + role.requirements
role_dependencies = role.metadata_dependencies + role.requirements
for dep in role_dependencies:
display.debug('Installing dep %s' % dep)
dep_req = RoleRequirement()

View File

@ -27,14 +27,16 @@ import datetime
import os
import tarfile
import tempfile
from ansible.module_utils.compat.version import LooseVersion
from collections.abc import MutableSequence
from shutil import rmtree
from ansible import context
from ansible.errors import AnsibleError
from ansible.errors import AnsibleError, AnsibleParserError
from ansible.galaxy.user_agent import user_agent
from ansible.module_utils._text import to_native, to_text
from ansible.module_utils.common.yaml import yaml_dump, yaml_load
from ansible.module_utils.compat.version import LooseVersion
from ansible.module_utils.urls import open_url
from ansible.playbook.role.requirement import RoleRequirement
from ansible.utils.display import Display
@ -53,6 +55,7 @@ class GalaxyRole(object):
def __init__(self, galaxy, api, name, src=None, version=None, scm=None, path=None):
self._metadata = None
self._metadata_dependencies = None
self._requirements = None
self._install_info = None
self._validate_certs = not context.CLIARGS['ignore_certs']
@ -120,6 +123,24 @@ class GalaxyRole(object):
return self._metadata
@property
def metadata_dependencies(self):
"""
Returns a list of dependencies from role metadata
"""
if self._metadata_dependencies is None:
self._metadata_dependencies = []
if self.metadata is not None:
self._metadata_dependencies = self.metadata.get('dependencies') or []
if not isinstance(self._metadata_dependencies, MutableSequence):
raise AnsibleParserError(
f"Expected role dependencies to be a list. Role {self} has meta/main.yml with dependencies {self._metadata_dependencies}"
)
return self._metadata_dependencies
@property
def install_info(self):
"""
@ -405,4 +426,7 @@ class GalaxyRole(object):
break
if not isinstance(self._requirements, MutableSequence):
raise AnsibleParserError(f"Expected role dependencies to be a list. Role {self} has meta/requirements.yml {self._requirements}")
return self._requirements

View File

@ -72,6 +72,7 @@ class RoleMetadata(Base, CollectionSearch):
raise AnsibleParserError("Expected role dependencies to be a list.", obj=self._ds)
for role_def in ds:
# FIXME: consolidate with ansible-galaxy to keep this in sync
if isinstance(role_def, string_types) or 'role' in role_def or 'name' in role_def:
roles.append(role_def)
continue

View File

@ -194,6 +194,70 @@ popd # ${galaxy_testdir}
rm -fr "${galaxy_testdir}"
rm -fr "${HOME}/.ansible/roles/${galaxy_local_test_role}"
# Galaxy install test case (expected failure)
#
# Install role with a meta/requirements.yml that is not a list of roles
mkdir -p "${role_testdir}"
pushd "${role_testdir}"
ansible-galaxy role init --init-path . unsupported_requirements_format
cat <<EOF > ./unsupported_requirements_format/meta/requirements.yml
roles:
- src: git+file:///${galaxy_local_test_role_git_repo}
EOF
tar czvf unsupported_requirements_format.tar.gz unsupported_requirements_format
set +e
ansible-galaxy role install -p ./roles unsupported_requirements_format.tar.gz 2>&1 | tee out.txt
rc="$?"
set -e
# Test that installing the role was an error
[[ ! "$rc" == 0 ]]
grep out.txt -qe 'Expected role dependencies to be a list.'
# Test that the role was not installed to the expected directory
[[ ! -d "${HOME}/.ansible/roles/unsupported_requirements_format" ]]
popd # ${role_testdir}
rm -rf "${role_testdir}"
# Galaxy install test case (expected failure)
#
# Install role with meta/main.yml dependencies that is not a list of roles
mkdir -p "${role_testdir}"
pushd "${role_testdir}"
ansible-galaxy role init --init-path . unsupported_requirements_format
cat <<EOF > ./unsupported_requirements_format/meta/main.yml
galaxy_info:
author: Ansible
description: test unknown dependency format (expected failure)
company: your company (optional)
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: 2.1
galaxy_tags: []
dependencies:
roles:
- src: git+file:///${galaxy_local_test_role_git_repo}
EOF
tar czvf unsupported_requirements_format.tar.gz unsupported_requirements_format
set +e
ansible-galaxy role install -p ./roles unsupported_requirements_format.tar.gz 2>&1 | tee out.txt
rc="$?"
set -e
# Test that installing the role was an error
[[ ! "$rc" == 0 ]]
grep out.txt -qe 'Expected role dependencies to be a list.'
# Test that the role was not installed to the expected directory
[[ ! -d "${HOME}/.ansible/roles/unsupported_requirements_format" ]]
popd # ${role_testdir}
rm -rf "${role_testdir}"
# Galaxy install test case
#
# Ensure that if both a role_file and role_path is provided, they are both