New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add bindep module #22159
Add bindep module #22159
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
#!/usr/bin/python | ||
# Copyright 2017 Red Hat, Inc. | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
from __future__ import absolute_import, division, print_function | ||
__metaclass__ = type | ||
|
||
ANSIBLE_METADATA = { | ||
'metadata_version': '1.1', | ||
'status': ['preview'], | ||
'supported_by': 'community' | ||
} | ||
|
||
DOCUMENTATION = ''' | ||
--- | ||
module: bindep | ||
short_description: Get lists of missing distro packages to be installed | ||
author: Monty Taylor (@mordred) | ||
version_added: "2.4" | ||
description: | ||
- Retreive a list of packages that are not already installed based on a | ||
list of requirements in bindep format. For more information on bindep, | ||
please see https://docs.openstack.org/infra/bindep/. | ||
requirements: | ||
- "python >= 2.7" | ||
- "bindep >= 2.2.0" | ||
options: | ||
path: | ||
description: | ||
- Path to a bindep.txt file or to a directory that contains either | ||
a bindep.txt file or an other-requirements.txt file that should | ||
be used as input. Mutually exclusive with I(requirements). | ||
required: false | ||
default: None | ||
requirements: | ||
description: | ||
- A list of bindep requirements strings. Mutually exclusive with I(path). | ||
required: false | ||
default: None | ||
profiles: | ||
description: | ||
- An explicit list of profiles to filter by. | ||
required: false | ||
default: [default] | ||
''' | ||
|
||
EXAMPLES = ''' | ||
- name: Get the list of packages to install on a given host from a file | ||
bindep: | ||
path: /home/example/bindep.txt | ||
|
||
- name: Get the list of test packages to install from current directory | ||
bindep: | ||
profiles: | ||
- test | ||
register: ret | ||
- name: Install the missing packages | ||
package: | ||
name: "{{ item }}" | ||
state: present | ||
with_items: "{{ ret.bindep_packages.missing }}" | ||
|
||
- name: Get the list of packages to install from an explicit list | ||
bindep: | ||
requirements: | ||
- "build-essential [platform:dpkg test]" | ||
- "gcc [platform:rpm test]" | ||
- "language-pack-en [platform:ubuntu]" | ||
- "libffi-dev [platform:dpkg test]" | ||
- "libffi-devel [platform:rpm test]" | ||
|
||
- name: Get the list of packages to install for the test profile | ||
bindep: | ||
requirements: | ||
- "build-essential [platform:dpkg test]" | ||
- "gcc [platform:rpm test]" | ||
- "language-pack-en [platform:ubuntu]" | ||
- "libffi-dev [platform:dpkg test]" | ||
- "libffi-devel [platform:rpm test]" | ||
profiles: | ||
- test | ||
''' | ||
|
||
|
||
RETURN = ''' | ||
bindep_packages: | ||
description: Dictionary containing information about the requirements. | ||
returned: On success. | ||
type: complex | ||
contains: | ||
missing: | ||
description: Packages that are missing from the system | ||
returned: success | ||
type: list | ||
sample: | ||
- libmysqlclient-dev | ||
- libxml2-dev | ||
badversion: | ||
description: Packages that are installed but at bad versions. | ||
returned: success | ||
type: list | ||
sample: | ||
- package: libxml2-dev | ||
version: 2.9.4+dfsg1-2 | ||
constraint: ">= 3.0" | ||
up_to_date: | ||
description: Flag indicating all packages are up to date | ||
returned: success | ||
type: bool | ||
''' | ||
|
||
import os | ||
|
||
from ansible.module_utils.basic import AnsibleModule | ||
|
||
try: | ||
import bindep.depends | ||
import ometa.runtime | ||
HAS_BINDEP = True | ||
except ImportError: | ||
HAS_BINDEP = False | ||
|
||
|
||
def main(): | ||
module = AnsibleModule( | ||
argument_spec=dict( | ||
path=dict(), | ||
requirements=dict(required=False, type="list"), | ||
profiles=dict(required=False, default=['default'], type='list'), | ||
), | ||
mutually_exclusive=[['path', 'requirements']], | ||
required_one_of=[['path', 'requirements']], | ||
supports_check_mode=True | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The module should support check mode but I don't see any support for that in the code. Can you explain? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The module doesn't actually make any changes itself - so all invocations of it are safe for check mode. |
||
) | ||
|
||
if not HAS_BINDEP: | ||
module.fail_json(msg='bindep is required for this module') | ||
if not hasattr(bindep.depends, 'get_depends'): | ||
module.fail_json( | ||
msg='bindep is required at version >= 2.2 for this module') | ||
|
||
path = module.params['path'] | ||
requirements = module.params['requirements'] | ||
profiles = module.params['profiles'] | ||
|
||
if requirements: | ||
req_string = '\n'.join(requirements) + '\n' | ||
try: | ||
depends = bindep.depends.Depends(req_string) | ||
except ometa.runtime.ParseError as e: | ||
module.fail_json(msg='bindep parse error: %s' % str(e)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
else: | ||
if path and os.path.isdir(path): | ||
os.chdir(path) | ||
try: | ||
depends = bindep.depends.get_depends() | ||
except ometa.runtime.ParseError as e: | ||
module.fail_json(msg='bindep parse error: %s' % str(e)) | ||
if not depends: | ||
module.fail_json(msg="no bindep.txt file found at %s" % path) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
elif path and not os.path.isdir(path): | ||
module.fail_json(msg="path %s was given but does not exist" % path) | ||
else: | ||
try: | ||
depends = bindep.depends.get_depends(filename=path) | ||
except ometa.runtime.ParseError as e: | ||
module.fail_json(msg='bindep parse error: %s' % str(e)) | ||
if not depends: | ||
module.fail_json(msg="bindep file %s not found" % path) | ||
|
||
profiles = profiles + depends.platform_profiles() | ||
rules = depends.active_rules(profiles) | ||
results = depends.check_rules(rules) | ||
|
||
ret = { | ||
'up_to_date': True, | ||
'missing': [], | ||
'badversion': [] | ||
} | ||
|
||
if results: | ||
ret['up_to_date'] = False | ||
for result in results: | ||
if result[0] == 'missing': | ||
ret['missing'].append(result[1]) | ||
if result[0] == 'badversion': | ||
for pkg, constraint, version in result[1]: | ||
ret['badversion'].append({ | ||
'package': pkg, | ||
'version': version, | ||
'constraint': constraint, | ||
}) | ||
|
||
module.exit_json(changed=False, bindep_packages=ret) | ||
|
||
if __name__ == '__main__': | ||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
destructive | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment explaining why some systems are skipped. |
||
skip/freebsd | ||
skip/osx | ||
skip/rhel |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
hello [platform:dpkg] | ||
sos [platform:rpm] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
dependencies: | ||
- prepare_tests |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
- name: make sure packages aren't installed | ||
package: | ||
name: "{{ item }}" | ||
state: absent | ||
with_items: | ||
- finger | ||
- hello | ||
|
||
- name: ask bindep what should be installed | ||
bindep: | ||
register: bindep_missing | ||
|
||
- name: verify bindep wants us to install hello | ||
assert: | ||
that: | ||
- "'hello' in bindep_missing.missing" | ||
|
||
- name: ask bindep directly if finger is installed | ||
bindep: | ||
requirements: | ||
- finger | ||
register: bindep_finger | ||
|
||
- name: verify bindep wants us to install finger | ||
assert: | ||
that: | ||
- "'finger' in bindep_finger.missing" | ||
|
||
- name: ask bindep directly if about a mixed list | ||
bindep: | ||
requirements: | ||
- "finger [platform:dpkg]" | ||
- "libssl-devel [platform:rpm]" | ||
register: bindep_mixed | ||
|
||
- name: verify bindep wants us to install finger and not libssl-devel | ||
assert: | ||
that: | ||
- "'finger' in bindep_mixed.missing" | ||
- "'libssl-devel' not in bindep_mixed.missing" | ||
|
||
- name: install packages | ||
package: | ||
name: "{{ item }}" | ||
state: present | ||
with_items: "{{ bindep_missing.missing }}" | ||
|
||
- name: ask bindep what should be installed again | ||
bindep: | ||
register: bindep_missing_again | ||
|
||
- name: verify uninstallation of hello | ||
assert: | ||
that: | ||
- "not bindep_missing_again.missing" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Copyright 2017 Red Hat, Inc. | ||
|
||
# This file is part of Ansible | ||
# | ||
# Ansible is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
# the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# Ansible is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
- name: show python version | ||
debug: var=ansible_python_version | ||
|
||
- name: install bindep | ||
pip: | ||
name: bindep | ||
|
||
- name: Copy bindep file to target | ||
copy: | ||
src: bindep.txt | ||
dest: "{{ ansible_user_dir }}/bindep.txt" | ||
|
||
- include: 'dpkg.yml' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I am not sure how the integration tests could succeed on OpenSuse 42 ? Integration tests were not run by the CI (see), for example for 2017-09-02 16:06:09 Processing pull request for branch devel commit 43938f4c617430230647985a1c61774a994df859 2017-09-02 16:06:09 Detected changes in 8 file(s). 2017-09-02 16:06:09 .github/BOTMETA.yml 2017-09-02 16:06:09 lib/ansible/modules/packaging/os/bindep.py 2017-09-02 16:06:09 test/integration/targets/bindep/aliases 2017-09-02 16:06:09 test/integration/targets/bindep/files/bindep.txt 2017-09-02 16:06:09 test/integration/targets/bindep/meta/main.yml 2017-09-02 16:06:09 test/integration/targets/bindep/tasks/dpkg.yml 2017-09-02 16:06:09 test/integration/targets/bindep/tasks/main.yml 2017-09-02 16:06:09 test/integration/targets/bindep/tasks/rpm.yml 2017-09-02 16:06:09 Mapping 8 changed file(s) to tests. 2017-09-02 16:06:09 .github/BOTMETA.yml -> integration: none 2017-09-02 16:06:09 lib/ansible/modules/packaging/os/bindep.py -> integration: bindep (targeted) 2017-09-02 16:06:09 test/integration/targets/bindep/aliases -> integration: bindep (targeted) 2017-09-02 16:06:09 test/integration/targets/bindep/files/bindep.txt -> integration: bindep (targeted) 2017-09-02 16:06:09 test/integration/targets/bindep/meta/main.yml -> integration: bindep (targeted) 2017-09-02 16:06:09 test/integration/targets/bindep/tasks/dpkg.yml -> integration: bindep (targeted) 2017-09-02 16:06:09 test/integration/targets/bindep/tasks/main.yml -> integration: bindep (targeted) 2017-09-02 16:06:09 test/integration/targets/bindep/tasks/rpm.yml -> integration: bindep (targeted) 2017-09-02 16:06:09 WARNING: All targets skipped. If I remember well, By the way, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The tests should have the alias There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is one warning:
|
||
when: ansible_distribution in ('Ubuntu', 'Debian') | ||
|
||
- include: 'rpm.yml' | ||
when: ansible_distribution in ('RedHat', 'CentOS', 'ScientificLinux') |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
- name: make sure packages aren't installed | ||
package: | ||
name: "{{ item }}" | ||
state: absent | ||
with_items: | ||
- sos | ||
- finger | ||
|
||
- name: ask bindep what should be installed | ||
bindep: | ||
register: bindep_missing | ||
|
||
- name: verify bindep wants us to install sos | ||
assert: | ||
that: | ||
- "'sos' in bindep_missing.missing" | ||
|
||
- name: ask bindep directly if finger is installed | ||
bindep: | ||
requirements: | ||
- finger | ||
register: bindep_finger | ||
|
||
- name: verify bindep wants us to install finger | ||
assert: | ||
that: | ||
- "'finger' in bindep_finger.missing" | ||
|
||
- name: ask bindep directly if about a mixed list | ||
bindep: | ||
requirements: | ||
- "finger [platform:rpm]" | ||
- "libssl-dev [platform:dpkg]" | ||
register: bindep_mixed | ||
|
||
- name: verify bindep wants us to install finger and not libssl-dev | ||
assert: | ||
that: | ||
- "'finger' in bindep_mixed.missing" | ||
- "'libssl-dev' not in bindep_mixed.missing" | ||
|
||
- name: install packages | ||
package: | ||
name: "{{ item }}" | ||
state: present | ||
with_items: "{{ bindep_missing.missing }}" | ||
|
||
- name: ask bindep what should be installed again | ||
bindep: | ||
register: bindep_missing_again | ||
|
||
- name: verify uninstallation of sos | ||
assert: | ||
that: | ||
- "not bindep_missing_again.missing" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
path
type could be used (some vars would be expanded) forpath
parameter.