Update ansible-galaxy to handle role requirements (#68288)

* Update galaxy role object to handle requirements

Co-Authored-By: Sandra McCann <samccann@redhat.com>
pull/68975/head
Alexandre Chouinard 6 years ago committed by GitHub
parent d42151e676
commit 91bb5af688
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,2 @@
minor_changes:
- ansible-galaxy - allow role to define dependency requirements that will be only installed by defining them in ``meta/requirements.yml`` (https://github.com/ansible/proposals/issues/57)

@ -363,10 +363,30 @@ command line, as follows:
Dependencies Dependencies
------------ ------------
Roles can also be dependent on other roles, and when you install a role that has dependencies, those dependencies will automatically be installed. Roles can also be dependent on other roles, and when you install a role that has dependencies, those dependencies will automatically be installed to the ``roles_path``.
You specify role dependencies in the ``meta/main.yml`` file by providing a list of roles. If the source of a role is Galaxy, you can simply specify the role in There are two ways to define the dependencies of a role:
the format ``namespace.role_name``. You can also use the more complex format in ``requirements.yml``, allowing you to provide ``src``, ``scm``, ``version``, and ``name``.
* using ``meta/requirements.yml``
* using ``meta/main.yml``
Using ``meta/requirements.yml``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`.. versionadded:: 2.10`
You can create the file ``meta/requirements.yml`` and define dependencies in the same format used for :file:`requirements.yml` described in the `Installing multiple roles from a file`_ section.
From there, you can import or include the specified roles in your tasks.
Using ``meta/main.yml``
^^^^^^^^^^^^^^^^^^^^^^^
Alternatively, you can specify role dependencies in the ``meta/main.yml`` file by providing a list of roles under the ``dependencies`` section. If the source of a role is Galaxy, you can simply specify the role in
the format ``namespace.role_name``. You can also use the more complex format in :file:`requirements.yml`, allowing you to provide ``src``, ``scm``, ``version``, and ``name``.
Dependencies installed that way, depending on other factors described below, will also be executed **before** this role is executed during play execution.
To better understand how dependencies are handled during play execution, see :ref:`playbooks_reuse_roles`.
The following shows an example ``meta/main.yml`` file with dependent roles: The following shows an example ``meta/main.yml`` file with dependent roles:
@ -425,8 +445,6 @@ Alternately, you can specify the role dependencies in the complex form used in
src: git+https://github.com/geerlingguy/ansible-role-composer.git src: git+https://github.com/geerlingguy/ansible-role-composer.git
version: 775396299f2da1f519f0d8885022ca2d6ee80ee8 version: 775396299f2da1f519f0d8885022ca2d6ee80ee8
When dependencies are encountered by ``ansible-galaxy``, it will automatically install each dependency to the ``roles_path``. To understand how dependencies are handled during play execution, see :ref:`playbooks_reuse_roles`.
.. note:: .. note::
Galaxy expects all role dependencies to exist in Galaxy, and therefore dependencies to be specified in the Galaxy expects all role dependencies to exist in Galaxy, and therefore dependencies to be specified in the

@ -1057,7 +1057,7 @@ class GalaxyCLI(CLI):
if not role.metadata: if not role.metadata:
display.warning("Meta file %s is empty. Skipping dependencies." % role.path) display.warning("Meta file %s is empty. Skipping dependencies." % role.path)
else: else:
role_dependencies = role.metadata.get('dependencies') or [] role_dependencies = (role.metadata.get('dependencies') or []) + role.requirements
for dep in role_dependencies: for dep in role_dependencies:
display.debug('Installing dep %s' % dep) display.debug('Installing dep %s' % dep)
dep_req = RoleRequirement() dep_req = RoleRequirement()

@ -47,11 +47,13 @@ class GalaxyRole(object):
SUPPORTED_SCMS = set(['git', 'hg']) SUPPORTED_SCMS = set(['git', 'hg'])
META_MAIN = (os.path.join('meta', 'main.yml'), os.path.join('meta', 'main.yaml')) META_MAIN = (os.path.join('meta', 'main.yml'), os.path.join('meta', 'main.yaml'))
META_INSTALL = os.path.join('meta', '.galaxy_install_info') META_INSTALL = os.path.join('meta', '.galaxy_install_info')
META_REQUIREMENTS = (os.path.join('meta', 'requirements.yml'), os.path.join('meta', 'requirements.yaml'))
ROLE_DIRS = ('defaults', 'files', 'handlers', 'meta', 'tasks', 'templates', 'vars', 'tests') ROLE_DIRS = ('defaults', 'files', 'handlers', 'meta', 'tasks', 'templates', 'vars', 'tests')
def __init__(self, galaxy, api, name, src=None, version=None, scm=None, path=None): def __init__(self, galaxy, api, name, src=None, version=None, scm=None, path=None):
self._metadata = None self._metadata = None
self._requirements = None
self._install_info = None self._install_info = None
self._validate_certs = not context.CLIARGS['ignore_certs'] self._validate_certs = not context.CLIARGS['ignore_certs']
@ -371,3 +373,25 @@ class GalaxyRole(object):
} }
""" """
return dict(scm=self.scm, src=self.src, version=self.version, name=self.name) return dict(scm=self.scm, src=self.src, version=self.version, name=self.name)
@property
def requirements(self):
"""
Returns role requirements
"""
if self._requirements is None:
self._requirements = []
for meta_requirements in self.META_REQUIREMENTS:
meta_path = os.path.join(self.path, meta_requirements)
if os.path.isfile(meta_path):
try:
f = open(meta_path, 'r')
self._requirements = yaml.safe_load(f)
except Exception:
display.vvvvv("Unable to load requirements for %s" % self.name)
finally:
f.close()
break
return self._requirements

@ -12,36 +12,72 @@ ansible-galaxy --version
# Need a relative custom roles path for testing various scenarios of -p # Need a relative custom roles path for testing various scenarios of -p
galaxy_relative_rolespath="my/custom/roles/path" galaxy_relative_rolespath="my/custom/roles/path"
# Prep the local git repo with a role and make a tar archive so we can test # Status message function (f_ to designate that it's a function)
# different things f_ansible_galaxy_status()
galaxy_local_test_role="test-role" {
galaxy_local_test_role_dir=$(mktemp -d) printf "\n\n\n### Testing ansible-galaxy: %s\n" "${@}"
galaxy_local_test_role_git_repo="${galaxy_local_test_role_dir}/${galaxy_local_test_role}" }
galaxy_local_test_role_tar="${galaxy_local_test_role_dir}/${galaxy_local_test_role}.tar"
pushd "${galaxy_local_test_role_dir}" # Use to initialize a repository. Must call the post function too.
ansible-galaxy init "${galaxy_local_test_role}" f_ansible_galaxy_create_role_repo_pre()
pushd "${galaxy_local_test_role}" {
repo_name=$1
repo_dir=$2
pushd "${repo_dir}"
ansible-galaxy init "${repo_name}"
pushd "${repo_name}"
git init . git init .
# Prep git, becuase it doesn't work inside a docker container without it # Prep git, because it doesn't work inside a docker container without it
git config user.email "tester@ansible.com" git config user.email "tester@ansible.com"
git config user.name "Ansible Tester" git config user.name "Ansible Tester"
# f_ansible_galaxy_create_role_repo_post
}
# Call after f_ansible_galaxy_create_repo_pre.
f_ansible_galaxy_create_role_repo_post()
{
repo_name=$1
repo_tar=$2
# f_ansible_galaxy_create_role_repo_pre
git add . git add .
git commit -m "local testing ansible galaxy role" git commit -m "local testing ansible galaxy role"
git archive \ git archive \
--format=tar \ --format=tar \
--prefix="${galaxy_local_test_role}/" \ --prefix="${repo_name}/" \
master > "${galaxy_local_test_role_tar}" master > "${repo_tar}"
popd # "${galaxy_local_test_role}" popd # "${repo_name}"
popd # "${galaxy_local_test_role_dir}" popd # "${repo_dir}"
# Status message function (f_ to designate that it's a function)
f_ansible_galaxy_status()
{
printf "\n\n\n### Testing ansible-galaxy: %s\n" "${@}"
} }
# Prep the local git repos with role and make a tar archive so we can test
# different things
galaxy_local_test_role="test-role"
galaxy_local_test_role_dir=$(mktemp -d)
galaxy_local_test_role_git_repo="${galaxy_local_test_role_dir}/${galaxy_local_test_role}"
galaxy_local_test_role_tar="${galaxy_local_test_role_dir}/${galaxy_local_test_role}.tar"
f_ansible_galaxy_create_role_repo_pre "${galaxy_local_test_role}" "${galaxy_local_test_role_dir}"
f_ansible_galaxy_create_role_repo_post "${galaxy_local_test_role}" "${galaxy_local_test_role_tar}"
galaxy_local_parent_role="parent-role"
galaxy_local_parent_role_dir=$(mktemp -d)
galaxy_local_parent_role_git_repo="${galaxy_local_parent_role_dir}/${galaxy_local_parent_role}"
galaxy_local_parent_role_tar="${galaxy_local_parent_role_dir}/${galaxy_local_parent_role}.tar"
# Create parent-role repository
f_ansible_galaxy_create_role_repo_pre "${galaxy_local_parent_role}" "${galaxy_local_parent_role_dir}"
cat <<EOF > meta/requirements.yml
- src: git+file:///${galaxy_local_test_role_git_repo}
EOF
f_ansible_galaxy_create_role_repo_post "${galaxy_local_parent_role}" "${galaxy_local_parent_role_tar}"
# Galaxy install test case # Galaxy install test case
# #
# Install local git repo # Install local git repo
@ -55,6 +91,7 @@ pushd "${galaxy_testdir}"
[[ -d "${HOME}/.ansible/roles/${galaxy_local_test_role}" ]] [[ -d "${HOME}/.ansible/roles/${galaxy_local_test_role}" ]]
popd # ${galaxy_testdir} popd # ${galaxy_testdir}
rm -fr "${galaxy_testdir}" rm -fr "${galaxy_testdir}"
rm -fr "${HOME}/.ansible/roles/${galaxy_local_test_role}"
# Galaxy install test case # Galaxy install test case
# #
@ -71,6 +108,45 @@ pushd "${galaxy_testdir}"
popd # ${galaxy_testdir} popd # ${galaxy_testdir}
rm -fr "${galaxy_testdir}" rm -fr "${galaxy_testdir}"
# Galaxy install test case
#
# Install local git repo with a meta/requirements.yml
f_ansible_galaxy_status "install of local git repo with meta/requirements.yml"
galaxy_testdir=$(mktemp -d)
pushd "${galaxy_testdir}"
ansible-galaxy install git+file:///"${galaxy_local_parent_role_git_repo}" "$@"
# Test that the role was installed to the expected directory
[[ -d "${HOME}/.ansible/roles/${galaxy_local_parent_role}" ]]
# Test that the dependency was also installed
[[ -d "${HOME}/.ansible/roles/${galaxy_local_test_role}" ]]
popd # ${galaxy_testdir}
rm -fr "${galaxy_testdir}"
rm -fr "${HOME}/.ansible/roles/${galaxy_local_parent_role}"
rm -fr "${HOME}/.ansible/roles/${galaxy_local_test_role}"
# Galaxy install test case
#
# Install local git repo with a meta/requirements.yml + --no-deps argument
f_ansible_galaxy_status "install of local git repo with meta/requirements.yml + --no-deps argument"
galaxy_testdir=$(mktemp -d)
pushd "${galaxy_testdir}"
ansible-galaxy install git+file:///"${galaxy_local_parent_role_git_repo}" --no-deps "$@"
# Test that the role was installed to the expected directory
[[ -d "${HOME}/.ansible/roles/${galaxy_local_parent_role}" ]]
# Test that the dependency was not installed
[[ ! -d "${HOME}/.ansible/roles/${galaxy_local_test_role}" ]]
popd # ${galaxy_testdir}
rm -fr "${galaxy_testdir}"
rm -fr "${HOME}/.ansible/roles/${galaxy_local_test_role}"
# Galaxy install test case # Galaxy install test case
# #
# Ensure that if both a role_file and role_path is provided, they are both # Ensure that if both a role_file and role_path is provided, they are both
@ -112,13 +188,16 @@ rm -fr "${galaxy_testdir}"
# #
# Basic tests to ensure listing roles works # Basic tests to ensure listing roles works
f_ansible_galaxy_status \ f_ansible_galaxy_status "role list"
"role list" galaxy_testdir=$(mktemp -d)
pushd "${galaxy_testdir}"
ansible-galaxy install git+file:///"${galaxy_local_test_role_git_repo}" "$@"
ansible-galaxy role list | tee out.txt ansible-galaxy role list | tee out.txt
ansible-galaxy role list test-role | tee -a out.txt ansible-galaxy role list test-role | tee -a out.txt
[[ $(grep -c '^- test-role' out.txt ) -eq 2 ]] [[ $(grep -c '^- test-role' out.txt ) -eq 2 ]]
popd # ${galaxy_testdir}
# Galaxy role test case # Galaxy role test case
# #
@ -185,7 +264,6 @@ f_ansible_galaxy_status \
popd # ${role_testdir} popd # ${role_testdir}
rm -fr "${role_testdir}" rm -fr "${role_testdir}"
# Properly list roles when the role name is a subset of the path, or the role # Properly list roles when the role name is a subset of the path, or the role
# name is the same name as the parent directory of the role. Issue #67365 # name is the same name as the parent directory of the role. Issue #67365
# #

Loading…
Cancel
Save