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 5 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
------------
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
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``.
There are two ways to define the dependencies of a role:
* 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:
@ -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
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::
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:
display.warning("Meta file %s is empty. Skipping dependencies." % role.path)
else:
role_dependencies = role.metadata.get('dependencies') or []
role_dependencies = (role.metadata.get('dependencies') or []) + role.requirements
for dep in role_dependencies:
display.debug('Installing dep %s' % dep)
dep_req = RoleRequirement()

@ -47,11 +47,13 @@ class GalaxyRole(object):
SUPPORTED_SCMS = set(['git', 'hg'])
META_MAIN = (os.path.join('meta', 'main.yml'), os.path.join('meta', 'main.yaml'))
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')
def __init__(self, galaxy, api, name, src=None, version=None, scm=None, path=None):
self._metadata = None
self._requirements = None
self._install_info = None
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)
@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
galaxy_relative_rolespath="my/custom/roles/path"
# Prep the local git repo with a 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"
pushd "${galaxy_local_test_role_dir}"
ansible-galaxy init "${galaxy_local_test_role}"
pushd "${galaxy_local_test_role}"
# Status message function (f_ to designate that it's a function)
f_ansible_galaxy_status()
{
printf "\n\n\n### Testing ansible-galaxy: %s\n" "${@}"
}
# Use to initialize a repository. Must call the post function too.
f_ansible_galaxy_create_role_repo_pre()
{
repo_name=$1
repo_dir=$2
pushd "${repo_dir}"
ansible-galaxy init "${repo_name}"
pushd "${repo_name}"
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.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 commit -m "local testing ansible galaxy role"
git archive \
--format=tar \
--prefix="${galaxy_local_test_role}/" \
master > "${galaxy_local_test_role_tar}"
popd # "${galaxy_local_test_role}"
popd # "${galaxy_local_test_role_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" "${@}"
--prefix="${repo_name}/" \
master > "${repo_tar}"
popd # "${repo_name}"
popd # "${repo_dir}"
}
# 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
#
# Install local git repo
@ -55,6 +91,7 @@ pushd "${galaxy_testdir}"
[[ -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
#
@ -71,6 +108,45 @@ pushd "${galaxy_testdir}"
popd # ${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
#
# 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
f_ansible_galaxy_status \
"role list"
f_ansible_galaxy_status "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 test-role | tee -a out.txt
[[ $(grep -c '^- test-role' out.txt ) -eq 2 ]]
popd # ${galaxy_testdir}
# Galaxy role test case
#
@ -185,7 +264,6 @@ f_ansible_galaxy_status \
popd # ${role_testdir}
rm -fr "${role_testdir}"
# 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
#

Loading…
Cancel
Save