mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-08 14:22:46 +00:00
Allow modules to be categorized, and also sort them when generating the documentation.
This commit is contained in:
299
library/packaging/apt
Normal file
299
library/packaging/apt
Normal file
@@ -0,0 +1,299 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2012, Flowroute LLC
|
||||
# Written by Matthew Williams <matthew@flowroute.com>
|
||||
# Based on yum module written by Seth Vidal <skvidal at fedoraproject.org>
|
||||
#
|
||||
# This module 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.
|
||||
#
|
||||
# This software 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 this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: apt
|
||||
short_description: Manages apt-packages
|
||||
description:
|
||||
- Manages I(apt) packages (such as for Debian/Ubuntu).
|
||||
version_added: "0.0.2"
|
||||
options:
|
||||
pkg:
|
||||
description:
|
||||
- A package name or package specifier with version, like C(foo) or C(foo=1.0)
|
||||
required: true
|
||||
default: null
|
||||
state:
|
||||
description:
|
||||
- Indicates the desired package state
|
||||
required: false
|
||||
default: present
|
||||
choices: [ "latest", "absent", "present" ]
|
||||
update_cache:
|
||||
description:
|
||||
- Run the equivalent of C(apt-get update) before the operation. Can be run as part of the package installation or as a separate step
|
||||
required: false
|
||||
default: "no"
|
||||
choices: [ "yes", "no" ]
|
||||
purge:
|
||||
description:
|
||||
- Will force purging of configuration files if the module state is set to I(absent).
|
||||
required: false
|
||||
default: "no"
|
||||
choices: [ "yes", "no" ]
|
||||
default_release:
|
||||
description:
|
||||
- Corresponds to the C(-t) option for I(apt) and sets pin priorities
|
||||
required: false
|
||||
default: null
|
||||
install_recommends:
|
||||
description:
|
||||
- Corresponds to the C(--no-install-recommends) option for I(apt), default behavior works as apt's default behavior, C(no) does not install recommended packages. Suggested packages are never installed.
|
||||
required: false
|
||||
default: "yes"
|
||||
choices: [ "yes", "no" ]
|
||||
force:
|
||||
description:
|
||||
- If C(yes), force installs/removes.
|
||||
required: false
|
||||
default: "no"
|
||||
choices: [ "yes", "no" ]
|
||||
upgrade:
|
||||
description:
|
||||
- 'If yes or safe, performs an aptitude safe-upgrade.'
|
||||
- 'If full, performs an aptitude full-upgrade.'
|
||||
- 'If dist, performs an apt-get dist-upgrade.'
|
||||
- 'Note: This does not upgrade a specific package, use state=latest for that.'
|
||||
version_added: "1.1"
|
||||
required: false
|
||||
default: "yes"
|
||||
choices: [ "yes", "safe", "full", "dist"]
|
||||
author: Matthew Williams
|
||||
notes: []
|
||||
examples:
|
||||
- code: "apt: pkg=foo update_cache=yes"
|
||||
description: Update repositories cache and install C(foo) package
|
||||
- code: "apt: pkg=foo state=removed"
|
||||
description: Remove C(foo) package
|
||||
- code: "apt: pkg=foo state=installed"
|
||||
description: Install the package C(foo)
|
||||
- code: "apt: pkg=foo=1.00 state=installed"
|
||||
description: Install the version '1.00' of package C(foo)
|
||||
- code: "apt: pkg=nginx state=latest default_release=squeeze-backports update_cache=yes"
|
||||
description: Update the repository cache and update package C(ngnix) to latest version using default release C(squeeze-backport)
|
||||
- code: "apt: pkg=openjdk-6-jdk state=latest install_recommends=no"
|
||||
description: Install latest version of C(openjdk-6-jdk) ignoring C(install-reccomends)
|
||||
- code: "apt: upgrade=dist"
|
||||
description: Update all packages to the latest version
|
||||
- code: "apt: update_cache=yes"
|
||||
description: Run the equivalent of C(apt-get update) as a separate step
|
||||
requirements: [ python-apt, aptitude ]
|
||||
'''
|
||||
|
||||
import traceback
|
||||
# added to stave off future warnings about apt api
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore', "apt API not stable yet", FutureWarning)
|
||||
|
||||
# APT related constants
|
||||
APTITUDE_CMD = "aptitude"
|
||||
APT_GET_CMD = "apt-get"
|
||||
APT_ENVVARS = "DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical"
|
||||
DPKG_OPTIONS = '-o "Dpkg::Options::=--force-confdef" -o "Dpkg::Options::=--force-confold"'
|
||||
APT_GET_ZERO = "0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded."
|
||||
APTITUDE_ZERO = "0 packages upgraded, 0 newly installed, 0 to remove and 0 not upgraded."
|
||||
|
||||
def package_split(pkgspec):
|
||||
parts = pkgspec.split('=')
|
||||
if len(parts) > 1:
|
||||
return parts[0], parts[1]
|
||||
else:
|
||||
return parts[0], None
|
||||
|
||||
def package_status(m, pkgname, version, cache, state):
|
||||
try:
|
||||
pkg = cache[pkgname]
|
||||
except KeyError:
|
||||
if state == 'install':
|
||||
m.fail_json(msg="No package matching '%s' is available" % pkgname)
|
||||
else:
|
||||
return False, False
|
||||
if version:
|
||||
try :
|
||||
return pkg.is_installed and pkg.installed.version == version, False
|
||||
except AttributeError:
|
||||
#assume older version of python-apt is installed
|
||||
return pkg.isInstalled and pkg.installedVersion == version, False
|
||||
else:
|
||||
try :
|
||||
return pkg.is_installed, pkg.is_upgradable
|
||||
except AttributeError:
|
||||
#assume older version of python-apt is installed
|
||||
return pkg.isInstalled, pkg.isUpgradable
|
||||
|
||||
def install(m, pkgspec, cache, upgrade=False, default_release=None, install_recommends=True, force=False):
|
||||
packages = ""
|
||||
for package in pkgspec:
|
||||
name, version = package_split(package)
|
||||
installed, upgradable = package_status(m, name, version, cache, state='install')
|
||||
if not installed or (upgrade and upgradable):
|
||||
packages += "'%s' " % package
|
||||
|
||||
if len(packages) != 0:
|
||||
if force:
|
||||
force_yes = '--force-yes'
|
||||
else:
|
||||
force_yes = ''
|
||||
|
||||
if m.check_mode:
|
||||
check_arg = '--simulate'
|
||||
else:
|
||||
check_arg = ''
|
||||
|
||||
cmd = "%s %s -y %s %s %s install %s" % (APT_ENVVARS, APT_GET_CMD, DPKG_OPTIONS, force_yes, check_arg, packages)
|
||||
|
||||
if default_release:
|
||||
cmd += " -t '%s'" % (default_release,)
|
||||
if not install_recommends:
|
||||
cmd += " --no-install-recommends"
|
||||
|
||||
rc, out, err = m.run_command(cmd)
|
||||
if rc:
|
||||
m.fail_json(msg="'apt-get install %s' failed: %s" % (packages, err))
|
||||
else:
|
||||
m.exit_json(changed=True)
|
||||
else:
|
||||
m.exit_json(changed=False)
|
||||
|
||||
def remove(m, pkgspec, cache, purge=False):
|
||||
packages = ""
|
||||
for package in pkgspec:
|
||||
name, version = package_split(package)
|
||||
installed, upgradable = package_status(m, name, version, cache, state='remove')
|
||||
if installed:
|
||||
packages += "'%s' " % package
|
||||
|
||||
if len(packages) == 0:
|
||||
m.exit_json(changed=False)
|
||||
else:
|
||||
purge = ''
|
||||
if purge:
|
||||
purge = '--purge'
|
||||
cmd = "%s -q -y %s remove %s" % (APT_GET_CMD, purge,packages)
|
||||
|
||||
if m.check_mode:
|
||||
m.exit_json(changed=True)
|
||||
|
||||
rc, out, err = m.run_command(cmd)
|
||||
if rc:
|
||||
m.fail_json(msg="'apt-get remove %s' failed: %s" % (packages, err))
|
||||
m.exit_json(changed=True)
|
||||
|
||||
def upgrade(m, mode="yes"):
|
||||
if m.check_mode:
|
||||
check_arg = '--simulate'
|
||||
else:
|
||||
check_arg = ''
|
||||
if mode == "dist":
|
||||
# apt-get dist-upgrade
|
||||
apt_cmd = APT_GET_CMD
|
||||
upgrade_command = "dist-upgrade"
|
||||
elif mode == "full":
|
||||
# aptitude full-upgrade
|
||||
apt_cmd = APTITUDE_CMD
|
||||
upgrade_command = "full-upgrade"
|
||||
else:
|
||||
# aptitude safe-upgrade # mode=yes # default
|
||||
apt_cmd = APTITUDE_CMD
|
||||
upgrade_command = "safe-upgrade"
|
||||
|
||||
apt_cmd_path = m.get_bin_path(apt_cmd, required=True)
|
||||
cmd = '%s %s -y %s %s %s' % (APT_ENVVARS, apt_cmd_path, DPKG_OPTIONS,
|
||||
check_arg, upgrade_command)
|
||||
rc, out, err = m.run_command(cmd)
|
||||
if rc:
|
||||
m.fail_json(msg="'%s %s' failed: %s" % (apt_cmd, upgrade_command, err))
|
||||
m.fail_json(msg="'aptitude safe-upgrade' failed: %s" % err)
|
||||
if (apt_cmd == APT_GET_CMD and APT_GET_ZERO in out) or (apt_cmd == APTITUDE_CMD and APTITUDE_ZERO in out):
|
||||
m.exit_json(changed=False, msg=out)
|
||||
m.exit_json(changed=True, msg=out)
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
state = dict(default='installed', choices=['installed', 'latest', 'removed', 'absent', 'present']),
|
||||
update_cache = dict(aliases=['update-cache'], type='bool'),
|
||||
purge = dict(default='no', type='bool'),
|
||||
package = dict(default=None, aliases=['pkg', 'name']),
|
||||
default_release = dict(default=None, aliases=['default-release']),
|
||||
install_recommends = dict(default='yes', aliases=['install-recommends'], type='bool'),
|
||||
force = dict(default='no', type='bool'),
|
||||
upgrade = dict(choices=['yes', 'safe', 'full', 'dist'])
|
||||
),
|
||||
mutually_exclusive = [['package', 'upgrade']],
|
||||
required_one_of = [['package', 'upgrade', 'update_cache']],
|
||||
supports_check_mode = True
|
||||
)
|
||||
|
||||
try:
|
||||
import apt
|
||||
import apt_pkg
|
||||
except:
|
||||
module.fail_json(msg="Could not import python modules: apt, apt_pkg. Please install python-apt package.")
|
||||
|
||||
p = module.params
|
||||
install_recommends = p['install_recommends']
|
||||
|
||||
try:
|
||||
cache = apt.Cache()
|
||||
if p['default_release']:
|
||||
apt_pkg.config['APT::Default-Release'] = p['default_release']
|
||||
# reopen cache w/ modified config
|
||||
cache.open(progress=None)
|
||||
|
||||
if p['update_cache']:
|
||||
cache.update()
|
||||
cache.open(progress=None)
|
||||
if not p['package'] and not p['upgrade']:
|
||||
module.exit_json(changed=False)
|
||||
|
||||
force_yes = p['force']
|
||||
|
||||
if p['upgrade']:
|
||||
upgrade(module, p['upgrade'])
|
||||
|
||||
packages = p['package'].split(',')
|
||||
latest = p['state'] == 'latest'
|
||||
for package in packages:
|
||||
if package.count('=') > 1:
|
||||
module.fail_json(msg="invalid package spec: %s" % package)
|
||||
if latest and '=' in package:
|
||||
module.fail_json(msg='version number inconsistent with state=latest: %s' % package)
|
||||
|
||||
if p['state'] == 'latest':
|
||||
install(module, packages, cache, upgrade=True,
|
||||
default_release=p['default_release'],
|
||||
install_recommends=install_recommends,
|
||||
force=force_yes)
|
||||
elif p['state'] in [ 'installed', 'present' ]:
|
||||
install(module, packages, cache, default_release=p['default_release'],
|
||||
install_recommends=install_recommends,force=force_yes)
|
||||
elif p['state'] in [ 'removed', 'absent' ]:
|
||||
remove(module, packages, cache, p['purge'])
|
||||
|
||||
except apt.cache.LockFailedException:
|
||||
module.fail_json(msg="Failed to lock apt for exclusive operation")
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
|
||||
main()
|
||||
183
library/packaging/apt_key
Normal file
183
library/packaging/apt_key
Normal file
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# (c) 2012, Jayson Vantuyl <jayson@aggressive.ly>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: apt_key
|
||||
author: Jayson Vantuyl & others
|
||||
version_added: "1.0"
|
||||
short_description: Add or remove an apt key
|
||||
description:
|
||||
- Add or remove an I(apt) key, optionally downloading it
|
||||
notes:
|
||||
- doesn't download the key unless it really needs it
|
||||
- as a sanity check, downloaded key id must match the one specified
|
||||
- best practice is to specify the key id and the url
|
||||
options:
|
||||
id:
|
||||
required: false
|
||||
default: none
|
||||
description:
|
||||
- identifier of key
|
||||
url:
|
||||
required: false
|
||||
default: none
|
||||
description:
|
||||
- url to retrieve key from.
|
||||
state:
|
||||
required: false
|
||||
choices: [ absent, present ]
|
||||
default: present
|
||||
description:
|
||||
- used to specify if key is being added or revoked
|
||||
examples:
|
||||
- code: "apt_key: url=https://ftp-master.debian.org/keys/archive-key-6.0.asc state=present"
|
||||
description: Add an Apt signing key, uses whichever key is at the URL
|
||||
- code: "apt_key: id=473041FA url=https://ftp-master.debian.org/keys/archive-key-6.0.asc state=present"
|
||||
description: Add an Apt signing key, will not download if present
|
||||
- code: "apt_key: url=https://ftp-master.debian.org/keys/archive-key-6.0.asc state=absent"
|
||||
description: Remove an Apt signing key, uses whichever key is at the URL
|
||||
- code: "apt_key: id=473041FA state=absent"
|
||||
description: Remove a Apt specific signing key
|
||||
'''
|
||||
|
||||
# FIXME: standardize into module_common
|
||||
from urllib2 import urlopen, URLError
|
||||
from traceback import format_exc
|
||||
from re import compile as re_compile
|
||||
# FIXME: standardize into module_common
|
||||
from distutils.spawn import find_executable
|
||||
from os import environ
|
||||
from sys import exc_info
|
||||
import traceback
|
||||
|
||||
match_key = re_compile("^gpg:.*key ([0-9a-fA-F]+):.*$")
|
||||
|
||||
REQUIRED_EXECUTABLES=['gpg', 'grep', 'apt-key']
|
||||
|
||||
|
||||
def check_missing_binaries(module):
|
||||
missing = [e for e in REQUIRED_EXECUTABLES if not find_executable(e)]
|
||||
if len(missing):
|
||||
module.fail_json(msg="binaries are missing", names=all)
|
||||
|
||||
def all_keys(module):
|
||||
(rc, out, err) = module.run_command("apt-key list")
|
||||
results = []
|
||||
lines = out.split('\n')
|
||||
for line in lines:
|
||||
if line.startswith("pub"):
|
||||
tokens = line.split()
|
||||
code = tokens[1]
|
||||
(len_type, real_code) = code.split("/")
|
||||
results.append(real_code)
|
||||
return results
|
||||
|
||||
def key_present(module, key_id):
|
||||
(rc, out, err) = module.run_command("apt-key list | 2>&1 grep -q %s" % key_id)
|
||||
return rc == 0
|
||||
|
||||
def download_key(module, url):
|
||||
# FIXME: move get_url code to common, allow for in-memory D/L, support proxies
|
||||
# and reuse here
|
||||
if url is None:
|
||||
module.fail_json(msg="needed a URL but was not specified")
|
||||
try:
|
||||
connection = urlopen(url)
|
||||
if connection is None:
|
||||
module.fail_json("error connecting to download key from url")
|
||||
data = connection.read()
|
||||
return data
|
||||
except:
|
||||
module.fail_json(msg="error getting key id from url", traceback=format_exc())
|
||||
|
||||
|
||||
def add_key(module, key):
|
||||
cmd = "apt-key add -"
|
||||
(rc, out, err) = module.run_command(cmd, data=key, check_rc=True)
|
||||
return True
|
||||
|
||||
def remove_key(module, key_id):
|
||||
# FIXME: use module.run_command, fail at point of error and don't discard useful stdin/stdout
|
||||
cmd = 'apt-key del %s' % key_id
|
||||
(rc, out, err) = module.run_command(cmd, check_rc=True)
|
||||
return True
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
id=dict(required=False, default=None),
|
||||
url=dict(required=False),
|
||||
data=dict(required=False),
|
||||
key=dict(required=False),
|
||||
state=dict(required=False, choices=['present', 'absent'], default='present')
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
key_id = module.params['id']
|
||||
url = module.params['url']
|
||||
data = module.params['data']
|
||||
state = module.params['state']
|
||||
changed = False
|
||||
|
||||
# FIXME: I think we have a common facility for this, if not, want
|
||||
check_missing_binaries(module)
|
||||
|
||||
keys = all_keys(module)
|
||||
return_values = {}
|
||||
|
||||
if state == 'present':
|
||||
if key_id and key_id in keys:
|
||||
module.exit_json(changed=False)
|
||||
else:
|
||||
if not data:
|
||||
data = download_key(module, url)
|
||||
if key_id and key_id in keys:
|
||||
module.exit_json(changed=False)
|
||||
else:
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
add_key(module, data)
|
||||
changed=False
|
||||
keys2 = all_keys(module)
|
||||
if len(keys) != len(keys2):
|
||||
changed=True
|
||||
if key_id and not key_id in keys2:
|
||||
module.fail_json(msg="key does not seem to have been added", id=key_id)
|
||||
module.exit_json(changed=changed)
|
||||
elif state == 'absent':
|
||||
if not key_id:
|
||||
module.fail_json(msg="key is required")
|
||||
if key_id in keys:
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
if remove_key(module, key_id):
|
||||
changed=True
|
||||
else:
|
||||
# FIXME: module.fail_json or exit-json immediately at point of failure
|
||||
module.fail_json(msg="error removing key_id", **return_values)
|
||||
|
||||
module.exit_json(changed=changed, **return_values)
|
||||
|
||||
# include magic from lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
main()
|
||||
148
library/packaging/apt_repository
Normal file
148
library/packaging/apt_repository
Normal file
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2012, Matt Wright <matt@nobien.net>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
# Example:
|
||||
# - name: add nginx repo
|
||||
# action: apt_repository repo=ppa:nginx/stable state=present
|
||||
#
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: apt_repository
|
||||
short_description: Manages apt repositores
|
||||
description:
|
||||
- Manages apt repositories (such as for Debian/Ubuntu).
|
||||
version_added: "0.7"
|
||||
options:
|
||||
repo:
|
||||
description:
|
||||
- The repository name/value
|
||||
required: true
|
||||
default: null
|
||||
state:
|
||||
description:
|
||||
- The repository state
|
||||
required: false
|
||||
default: present
|
||||
choices: [ "present", "absent" ]
|
||||
notes:
|
||||
- This module works on Debian and Ubuntu only and requires C(apt-add-repository) be available on the destination server. To ensure this package is available use the M(apt) module and install the C(python-software-properties) package before using this module.
|
||||
- This module cannot be used on Debian Squeeze (Version 6) as there is no C(add-apt-repository) in C(python-software-properties)
|
||||
- A bug in C(apt-add-repository) always adds C(deb) and C(deb-src) types for repositories (see the issue on Launchpad U(https://bugs.launchpad.net/ubuntu/+source/software-properties/+bug/987264)), if a repo doesn't have source information (eg MongoDB repo from 10gen) the system will fail while updating repositories.
|
||||
author: Matt Wright
|
||||
examples:
|
||||
- code: "apt_repository: repo=ppa:nginx/stable"
|
||||
description: Add nginx stable repository from PPA
|
||||
- code: "apt_repository: repo='deb http://archive.canonical.com/ubuntu hardy partner'"
|
||||
description: Add specified repository into sources.
|
||||
requirements: [ python-apt ]
|
||||
'''
|
||||
|
||||
import platform
|
||||
|
||||
try:
|
||||
import apt
|
||||
import apt_pkg
|
||||
HAVE_PYAPT = True
|
||||
except ImportError:
|
||||
HAVE_PYAPT = False
|
||||
|
||||
APT = "/usr/bin/apt-get"
|
||||
ADD_APT_REPO = 'add-apt-repository'
|
||||
|
||||
def check_cmd_needs_y():
|
||||
if platform.dist()[0] == 'debian' or float(platform.dist()[1]) >= 11.10:
|
||||
return True
|
||||
return False
|
||||
|
||||
def repo_exists(module, repo):
|
||||
configured = False
|
||||
slist = apt_pkg.SourceList()
|
||||
if not slist.read_main_list():
|
||||
module.fail_json(msg="Failed to parse sources.list")
|
||||
for metaindex in slist.list:
|
||||
if repo in metaindex.uri:
|
||||
configured = True
|
||||
return configured
|
||||
|
||||
def main():
|
||||
add_apt_repository = None
|
||||
|
||||
arg_spec = dict(
|
||||
repo=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
module = AnsibleModule(argument_spec=arg_spec, supports_check_mode=True)
|
||||
|
||||
if not HAVE_PYAPT:
|
||||
module.fail_json(msg="Could not import python modules: apt, apt_pkg. Please install python-apt package.")
|
||||
|
||||
add_apt_repository = module.get_bin_path(ADD_APT_REPO, True)
|
||||
if check_cmd_needs_y():
|
||||
add_apt_repository += ' -y'
|
||||
|
||||
repo = module.params['repo']
|
||||
state = module.params['state']
|
||||
|
||||
repo_url = repo
|
||||
if 'ppa' in repo_url:
|
||||
# looks like ppa:nginx/stable
|
||||
repo_url = repo.split(':')[1]
|
||||
elif len(repo_url.split(' ')) > 1:
|
||||
# could be:
|
||||
# http://myserver/path/to/repo free non-free
|
||||
# deb http://myserver/path/to/repo free non-free
|
||||
for i in repo_url.split():
|
||||
if 'http' in i:
|
||||
repo_url = i
|
||||
exists = repo_exists(module, repo_url)
|
||||
|
||||
rc = 0
|
||||
out = ''
|
||||
err = ''
|
||||
if state == 'absent' and exists:
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
cmd = '%s "%s" --remove' % (add_apt_repository, repo)
|
||||
rc, out, err = module.run_command(cmd)
|
||||
elif state == 'present' and not exists:
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
cmd = '%s "%s"' % (add_apt_repository, repo)
|
||||
rc, out, err = module.run_command(cmd)
|
||||
else:
|
||||
module.exit_json(changed=False, repo=repo, state=state)
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg=err)
|
||||
else:
|
||||
changed = True
|
||||
|
||||
if state == 'present' and changed:
|
||||
rc, out, err = module.run_command('%s update' % APT)
|
||||
|
||||
module.exit_json(changed=changed, repo=repo, state=state)
|
||||
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
|
||||
main()
|
||||
142
library/packaging/easy_install
Normal file
142
library/packaging/easy_install
Normal file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2012, Matt Wright <matt@nobien.net>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: easy_install
|
||||
short_description: Installs Python libraries
|
||||
description:
|
||||
- Installs Python libraries, optionally in a I(virtualenv)
|
||||
version_added: "0.7"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- A Python library name
|
||||
required: true
|
||||
default: null
|
||||
aliases: []
|
||||
virtualenv:
|
||||
description:
|
||||
- an optional I(virtualenv) directory path to install into. If the
|
||||
I(virtualenv) does not exist, it is created automatically
|
||||
required: false
|
||||
default: null
|
||||
virtualenv_site_packages:
|
||||
version_added: "1.1"
|
||||
description:
|
||||
- Whether the virtual environment will inherit packages from the
|
||||
global site-packages directory. Note that if this setting is
|
||||
changed on an already existing virtual environment it will not
|
||||
have any effect, the environment must be deleted and newly
|
||||
created.
|
||||
required: false
|
||||
default: "no"
|
||||
choices: [ "yes", "no" ]
|
||||
virtualenv_command:
|
||||
version_added: "1.1"
|
||||
description:
|
||||
- The command to create the virtual environment with. For example
|
||||
C(pyvenv), C(virtualenv), C(virtualenv2).
|
||||
required: false
|
||||
default: virtualenv
|
||||
examples:
|
||||
- code: "easy_install: name=pip"
|
||||
description: "Examples from Ansible Playbooks"
|
||||
- code: "easy_install: name=flask virtualenv=/webapps/myapp/venv"
|
||||
description: "Install I(Flask) (U(http://flask.pocoo.org/)) into the specified I(virtualenv)"
|
||||
notes:
|
||||
- Please note that the M(easy_install) module can only install Python
|
||||
libraries. Thus this module is not able to remove libraries. It is
|
||||
generally recommended to use the M(pip) module which you can first install
|
||||
using M(easy_install).
|
||||
- Also note that I(virtualenv) must be installed on the remote host if the
|
||||
C(virtualenv) parameter is specified.
|
||||
requirements: [ "virtualenv" ]
|
||||
author: Matt Wright
|
||||
'''
|
||||
|
||||
def _is_package_installed(module, name, easy_install):
|
||||
cmd = '%s --dry-run %s' % (easy_install, name)
|
||||
rc, status_stdout, status_stderr = module.run_command(cmd)
|
||||
return not ('Reading' in status_stdout or 'Downloading' in status_stdout)
|
||||
|
||||
|
||||
def main():
|
||||
arg_spec = dict(
|
||||
name=dict(required=True),
|
||||
virtualenv=dict(default=None, required=False),
|
||||
virtualenv_site_packages=dict(default='no', type='bool'),
|
||||
virtualenv_command=dict(default='virtualenv', required=False),
|
||||
)
|
||||
|
||||
module = AnsibleModule(argument_spec=arg_spec, supports_check_mode=True)
|
||||
|
||||
name = module.params['name']
|
||||
env = module.params['virtualenv']
|
||||
easy_install = module.get_bin_path('easy_install', True, ['%s/bin' % env])
|
||||
site_packages = module.params['virtualenv_site_packages']
|
||||
virtualenv_command = module.params['virtualenv_command']
|
||||
|
||||
rc = 0
|
||||
err = ''
|
||||
out = ''
|
||||
|
||||
if env:
|
||||
virtualenv = module.get_bin_path(virtualenv_command, True)
|
||||
|
||||
if not os.path.exists(os.path.join(env, 'bin', 'activate')):
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
command = '%s %s' % (virtualenv, env)
|
||||
if site_packages:
|
||||
command += ' --system-site-packages'
|
||||
rc_venv, out_venv, err_venv = module.run_command('%s %s' % (virtualenv, env))
|
||||
|
||||
rc += rc_venv
|
||||
out += out_venv
|
||||
err += err_venv
|
||||
|
||||
cmd = None
|
||||
changed = False
|
||||
installed = _is_package_installed(module, name, easy_install)
|
||||
|
||||
if not installed:
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
cmd = '%s %s' % (easy_install, name)
|
||||
rc_pip, out_pip, err_pip = module.run_command(cmd)
|
||||
|
||||
rc += rc_pip
|
||||
out += out_pip
|
||||
err += err_pip
|
||||
|
||||
changed = True
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg=err, cmd=cmd)
|
||||
|
||||
module.exit_json(changed=changed, binary=easy_install,
|
||||
name=name, virtualenv=env)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
|
||||
main()
|
||||
204
library/packaging/gem
Normal file
204
library/packaging/gem
Normal file
@@ -0,0 +1,204 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Johan Wiren <johan.wiren.se@gmail.com>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: gem
|
||||
short_description: Manage Ruby gems
|
||||
description:
|
||||
- Manage installation and uninstallation of Ruby gems.
|
||||
version_added: "1.1"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the gem to be managed.
|
||||
required: true
|
||||
state:
|
||||
description:
|
||||
- The desired state of the gem. C(latest) ensures that the latest version is installed.
|
||||
required: true
|
||||
choices: [present, absent, latest]
|
||||
gem_source:
|
||||
description:
|
||||
- The path to a local gem used as installation source.
|
||||
required: false
|
||||
include_dependencies:
|
||||
description:
|
||||
- Wheter to include dependencies or not.
|
||||
required: false
|
||||
choices: [ "yes", "no" ]
|
||||
default: "yes"
|
||||
repository:
|
||||
description:
|
||||
- The repository from which the gem will be installed
|
||||
required: false
|
||||
aliases: [source]
|
||||
version:
|
||||
description:
|
||||
- Version of the gem to be installed/removed.
|
||||
required: false
|
||||
author: Johan Wiren
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Installs version 1.0 of vagrant.
|
||||
gem: name=vagrant version=1.0 state=present
|
||||
|
||||
# Installs latest available version of rake.
|
||||
gem: name=rake state=latest
|
||||
|
||||
# Installs rake version 1.0 from a local gem on disk.
|
||||
gem: name=rake gem_source=/path/to/gems/rake-1.0.gem state=present
|
||||
'''
|
||||
|
||||
import re
|
||||
|
||||
def get_rubygems_version(module):
|
||||
cmd = [module.get_bin_path('gem', True), '--version']
|
||||
(rc, out, err) = module.run_command(cmd, check_rc=True)
|
||||
|
||||
match = re.match(r'^(\d+)\.(\d+)\.(\d+)', out)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
return tuple(int(x) for x in match.groups())
|
||||
|
||||
def get_installed_versions(module, remote=False):
|
||||
|
||||
cmd = [ module.get_bin_path('gem', True) ]
|
||||
cmd.append('query')
|
||||
if remote:
|
||||
cmd.append('--remote')
|
||||
if module.params['repository']:
|
||||
cmd.extend([ '--source', module.params['repository'] ])
|
||||
cmd.append('-n')
|
||||
cmd.append('^%s$' % module.params['name'])
|
||||
(rc, out, err) = module.run_command(cmd, check_rc=True)
|
||||
installed_versions = []
|
||||
for line in out.splitlines():
|
||||
match = re.match(r"\S+\s+\((.+)\)", line)
|
||||
if match:
|
||||
versions = match.group(1)
|
||||
for version in versions.split(', '):
|
||||
installed_versions.append(version)
|
||||
return installed_versions
|
||||
|
||||
def exists(module):
|
||||
|
||||
if module.params['state'] == 'latest':
|
||||
remoteversions = get_installed_versions(module, remote=True)
|
||||
if remoteversions:
|
||||
module.params['version'] = remoteversions[0]
|
||||
installed_versions = get_installed_versions(module)
|
||||
if module.params['version']:
|
||||
if module.params['version'] in installed_versions:
|
||||
return True
|
||||
else:
|
||||
if installed_versions:
|
||||
return True
|
||||
return False
|
||||
|
||||
def uninstall(module):
|
||||
|
||||
if module.check_mode:
|
||||
return
|
||||
cmd = [ module.get_bin_path('gem', True) ]
|
||||
cmd.append('uninstall')
|
||||
if module.params['version']:
|
||||
cmd.extend([ '--version', module.params['version'] ])
|
||||
else:
|
||||
cmd.append('--all')
|
||||
cmd.append(module.params['name'])
|
||||
module.run_command(cmd, check_rc=True)
|
||||
|
||||
def install(module):
|
||||
|
||||
if module.check_mode:
|
||||
return
|
||||
|
||||
ver = get_rubygems_version(module)
|
||||
if ver:
|
||||
major = ver[0]
|
||||
else:
|
||||
major = None
|
||||
|
||||
cmd = [ module.get_bin_path('gem', True) ]
|
||||
cmd.append('install')
|
||||
if module.params['version']:
|
||||
cmd.extend([ '--version', module.params['version'] ])
|
||||
if module.params['repository']:
|
||||
cmd.extend([ '--source', module.params['repository'] ])
|
||||
if not module.params['include_dependencies']:
|
||||
cmd.append('--ignore-dependencies')
|
||||
else:
|
||||
if major and major < 2:
|
||||
cmd.append('--include-dependencies')
|
||||
cmd.append('--no-rdoc')
|
||||
cmd.append('--no-ri')
|
||||
cmd.append(module.params['gem_source'])
|
||||
module.run_command(cmd, check_rc=True)
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
gem_source = dict(required=False, type='str'),
|
||||
include_dependencies = dict(required=False, default=True, type='bool'),
|
||||
name = dict(required=True, type='str'),
|
||||
repository = dict(required=False, aliases=['source'], type='str'),
|
||||
state = dict(required=False, choices=['present','absent','latest'], type='str'),
|
||||
version = dict(required=False, type='str'),
|
||||
),
|
||||
supports_check_mode = True,
|
||||
mutually_exclusive = [ ['gem_source','repository'], ['gem_source','version'] ],
|
||||
)
|
||||
|
||||
if module.params['version'] and module.params['state'] == 'latest':
|
||||
module.fail_json(msg="Cannot specify version when state=latest")
|
||||
if module.params['gem_source'] and module.params['state'] == 'latest':
|
||||
module.fail_json(msg="Cannot maintain state=latest when installing from local source")
|
||||
|
||||
if not module.params['gem_source']:
|
||||
module.params['gem_source'] = module.params['name']
|
||||
|
||||
changed = False
|
||||
|
||||
if module.params['state'] in [ 'present', 'latest']:
|
||||
if not exists(module):
|
||||
install(module)
|
||||
changed = True
|
||||
elif module.params['state'] == 'absent':
|
||||
if exists(module):
|
||||
uninstall(module)
|
||||
changed = True
|
||||
|
||||
result = {}
|
||||
result['name'] = module.params['name']
|
||||
result['state'] = module.params['state']
|
||||
if module.params['version']:
|
||||
result['version'] = module.params['version']
|
||||
result['changed'] = changed
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
# include magic from lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
main()
|
||||
153
library/packaging/homebrew
Normal file
153
library/packaging/homebrew
Normal file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Andrew Dunham <andrew@du.nham.ca>
|
||||
# Based on macports (Jimmy Tang <jcftang@gmail.com>)
|
||||
#
|
||||
# This module 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.
|
||||
#
|
||||
# This software 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 this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: homebrew
|
||||
author: Andrew Dunham
|
||||
short_description: Package manager for Homebrew
|
||||
description:
|
||||
- Manages Homebrew packages
|
||||
version_added: "1.1"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- name of package to install/remove
|
||||
required: true
|
||||
state:
|
||||
description:
|
||||
- state of the package
|
||||
choices: [ 'present', 'absent' ]
|
||||
required: false
|
||||
default: present
|
||||
update_homebrew:
|
||||
description:
|
||||
- update homebrew itself first
|
||||
required: false
|
||||
default: "no"
|
||||
choices: [ "yes", "no" ]
|
||||
notes: []
|
||||
'''
|
||||
EXAMPLES = '''
|
||||
homebrew: name=foo state=present
|
||||
homebrew: name=foo state=present update_homebrew=yes
|
||||
homebrew: name=foo state=absent
|
||||
homebrew: name=foo,bar state=absent
|
||||
'''
|
||||
|
||||
|
||||
def update_homebrew(module, brew_path):
|
||||
""" Updates packages list. """
|
||||
|
||||
rc, out, err = module.run_command("%s update" % brew_path)
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="could not update homebrew")
|
||||
|
||||
|
||||
def query_package(module, brew_path, name, state="present"):
|
||||
""" Returns whether a package is installed or not. """
|
||||
|
||||
if state == "present":
|
||||
rc, out, err = module.run_command("%s list -m1 | grep -q '^%s$'" % (brew_path, name))
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def remove_packages(module, brew_path, packages):
|
||||
""" Uninstalls one or more packages if installed. """
|
||||
|
||||
removed_count = 0
|
||||
|
||||
# Using a for loop incase of error, we can report the package that failed
|
||||
for package in packages:
|
||||
# Query the package first, to see if we even need to remove.
|
||||
if not query_package(module, brew_path, package):
|
||||
continue
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
rc, out, err = module.run_command([brew_path, 'remove', package])
|
||||
|
||||
if query_package(module, brew_path, package):
|
||||
module.fail_json(msg="failed to remove %s: %s" % (package, out.strip()))
|
||||
|
||||
removed_count += 1
|
||||
|
||||
if removed_count > 0:
|
||||
module.exit_json(changed=True, msg="removed %d package(s)" % removed_count)
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already absent")
|
||||
|
||||
|
||||
def install_packages(module, brew_path, packages):
|
||||
""" Installs one or more packages if not already installed. """
|
||||
|
||||
installed_count = 0
|
||||
|
||||
for package in packages:
|
||||
if query_package(module, brew_path, package):
|
||||
continue
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
rc, out, err = module.run_command([brew_path, 'install', package])
|
||||
|
||||
if not query_package(module, brew_path, package):
|
||||
module.fail_json(msg="failed to install %s: %s" % (package, out.strip()))
|
||||
|
||||
installed_count += 1
|
||||
|
||||
if installed_count > 0:
|
||||
module.exit_json(changed=True, msg="installed %d package(s)" % (installed_count,))
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already present")
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(aliases=["pkg"], required=True),
|
||||
state = dict(default="present", choices=["present", "installed", "absent", "removed"]),
|
||||
update_homebrew = dict(default="no", aliases=["update-brew"], type='bool')
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
brew_path = module.get_bin_path('brew', True, ['/usr/local/bin'])
|
||||
|
||||
p = module.params
|
||||
|
||||
if p["update_homebrew"]:
|
||||
update_homebrew(module, brew_path)
|
||||
|
||||
pkgs = p["name"].split(",")
|
||||
|
||||
if p["state"] in ["present", "installed"]:
|
||||
install_packages(module, brew_path, pkgs)
|
||||
|
||||
elif p["state"] in ["absent", "removed"]:
|
||||
remove_packages(module, brew_path, pkgs)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
|
||||
main()
|
||||
215
library/packaging/macports
Normal file
215
library/packaging/macports
Normal file
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Jimmy Tang <jcftang@gmail.com>
|
||||
# Based on okpg (Patrick Pelletier <pp.pelletier@gmail.com>), pacman
|
||||
# (Afterburn) and pkgin (Shaun Zinck) modules
|
||||
#
|
||||
# This module 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.
|
||||
#
|
||||
# This software 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 this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: macports
|
||||
author: Jimmy Tang
|
||||
short_description: Package manager for MacPorts
|
||||
description:
|
||||
- Manages MacPorts packages
|
||||
version_added: "1.1"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- name of package to install/remove
|
||||
required: true
|
||||
state:
|
||||
description:
|
||||
- state of the package
|
||||
choices: [ 'present', 'absent', 'active', 'inactive' ]
|
||||
required: false
|
||||
default: present
|
||||
update_cache:
|
||||
description:
|
||||
- update the package db first
|
||||
required: false
|
||||
default: "no"
|
||||
choices: [ "yes", "no" ]
|
||||
notes: []
|
||||
'''
|
||||
EXAMPLES = '''
|
||||
macports: name=foo state=present
|
||||
macports: name=foo state=present update_cache=yes
|
||||
macports: name=foo state=absent
|
||||
macports: name=foo state=active
|
||||
macports: name=foo state=inactive
|
||||
'''
|
||||
|
||||
|
||||
def update_package_db(module, port_path):
|
||||
""" Updates packages list. """
|
||||
|
||||
rc, out, err = module.run_command("%s sync" % port_path)
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="could not update package db")
|
||||
|
||||
|
||||
def query_package(module, port_path, name, state="present"):
|
||||
""" Returns whether a package is installed or not. """
|
||||
|
||||
if state == "present":
|
||||
|
||||
rc, out, err = module.run_command("%s installed | grep -q ^.*%s" % (port_path, name))
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
elif state == "active":
|
||||
|
||||
rc, out, err = module.run_command("%s installed %s | grep -q active" % (port_path, name))
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def remove_packages(module, port_path, packages):
|
||||
""" Uninstalls one or more packages if installed. """
|
||||
|
||||
remove_c = 0
|
||||
# Using a for loop incase of error, we can report the package that failed
|
||||
for package in packages:
|
||||
# Query the package first, to see if we even need to remove
|
||||
if not query_package(module, port_path, package):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s uninstall %s" % (port_path, package))
|
||||
|
||||
if query_package(module, port_path, package):
|
||||
module.fail_json(msg="failed to remove %s: %s" % (package, out))
|
||||
|
||||
remove_c += 1
|
||||
|
||||
if remove_c > 0:
|
||||
|
||||
module.exit_json(changed=True, msg="removed %s package(s)" % remove_c)
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already absent")
|
||||
|
||||
|
||||
def install_packages(module, port_path, packages):
|
||||
""" Installs one or more packages if not already installed. """
|
||||
|
||||
install_c = 0
|
||||
|
||||
for package in packages:
|
||||
if query_package(module, port_path, package):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s install %s" % (port_path, package))
|
||||
|
||||
if not query_package(module, port_path, package):
|
||||
module.fail_json(msg="failed to install %s: %s" % (package, out))
|
||||
|
||||
install_c += 1
|
||||
|
||||
if install_c > 0:
|
||||
module.exit_json(changed=True, msg="installed %s package(s)" % (install_c))
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already present")
|
||||
|
||||
|
||||
def activate_packages(module, port_path, packages):
|
||||
""" Activate a package if it's inactive. """
|
||||
|
||||
activate_c = 0
|
||||
|
||||
for package in packages:
|
||||
if not query_package(module, port_path, package):
|
||||
module.fail_json(msg="failed to activate %s, package(s) not present" % (package))
|
||||
|
||||
if query_package(module, port_path, package, state="active"):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s activate %s" % (port_path, package))
|
||||
|
||||
if not query_package(module, port_path, package, state="active"):
|
||||
module.fail_json(msg="failed to activate %s: %s" % (package, out))
|
||||
|
||||
activate_c += 1
|
||||
|
||||
if activate_c > 0:
|
||||
module.exit_json(changed=True, msg="activated %s package(s)" % (activate_c))
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already active")
|
||||
|
||||
|
||||
def deactivate_packages(module, port_path, packages):
|
||||
""" Deactivate a package if it's active. """
|
||||
|
||||
deactivated_c = 0
|
||||
|
||||
for package in packages:
|
||||
if not query_package(module, port_path, package):
|
||||
module.fail_json(msg="failed to activate %s, package(s) not present" % (package))
|
||||
|
||||
if not query_package(module, port_path, package, state="active"):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s deactivate %s" % (port_path, package))
|
||||
|
||||
if query_package(module, port_path, package, state="active"):
|
||||
module.fail_json(msg="failed to deactivated %s: %s" % (package, out))
|
||||
|
||||
deactivated_c += 1
|
||||
|
||||
if deactivated_c > 0:
|
||||
module.exit_json(changed=True, msg="deactivated %s package(s)" % (deactivated_c))
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already inactive")
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(aliases=["pkg"], required=True),
|
||||
state = dict(default="present", choices=["present", "installed", "absent", "removed", "active", "inactive"]),
|
||||
update_cache = dict(default="no", aliases=["update-cache"], type='bool')
|
||||
)
|
||||
)
|
||||
|
||||
port_path = module.get_bin_path('port', True, ['/opt/local/bin'])
|
||||
|
||||
p = module.params
|
||||
|
||||
if p["update_cache"]:
|
||||
update_package_db(module, port_path)
|
||||
|
||||
pkgs = p["name"].split(",")
|
||||
|
||||
if p["state"] in ["present", "installed"]:
|
||||
install_packages(module, port_path, pkgs)
|
||||
|
||||
elif p["state"] in ["absent", "removed"]:
|
||||
remove_packages(module, port_path, pkgs)
|
||||
|
||||
elif p["state"] == "active":
|
||||
activate_packages(module, port_path, pkgs)
|
||||
|
||||
elif p["state"] == "inactive":
|
||||
deactivate_packages(module, port_path, pkgs)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
|
||||
main()
|
||||
222
library/packaging/npm
Normal file
222
library/packaging/npm
Normal file
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Chris Hoffman <christopher.hoffman@gmail.com>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: npm
|
||||
short_description: Manage node.js packages with npm
|
||||
description:
|
||||
- Manage node.js packages with Node Package Manager (npm)
|
||||
version_added: 1.2
|
||||
author: Chris Hoffman
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of a node.js library to install
|
||||
requires: false
|
||||
default: null
|
||||
path:
|
||||
description:
|
||||
- The base path where to install the node.js libraries
|
||||
required: false
|
||||
default: null
|
||||
version:
|
||||
description:
|
||||
- The version to be installed
|
||||
required: false
|
||||
default: null
|
||||
global:
|
||||
descrition:
|
||||
- Install the node.js library globally
|
||||
required: false
|
||||
default: no
|
||||
choices: [ "yes", "no" ]
|
||||
executable:
|
||||
description:
|
||||
- The executable location for npm.
|
||||
- This is useful if you are using a version manager, such as nvm
|
||||
required: false
|
||||
default: nvm
|
||||
production:
|
||||
description:
|
||||
- Install dependencies in production mode, excluding devDependencies
|
||||
required: false
|
||||
default: no
|
||||
state:
|
||||
description:
|
||||
- The state of the node.js library
|
||||
required: false
|
||||
default: present
|
||||
choices: [ "present", "absent", "latest" ]
|
||||
examples:
|
||||
- code: "npm: name=coffee-script path=/app/location"
|
||||
description: Install I(coffee-script) node.js package.
|
||||
- code: "npm: name=coffee-script version=1.6.1 path=/app/location"
|
||||
description: Install I(coffee-script) node.js package on version 1.6.1.
|
||||
- code: "npm: name=coffee-script global=yes"
|
||||
description: Install I(coffee-script) node.js package globally.
|
||||
- code: "npm: name=coffee-script global=yes state=absent"
|
||||
description: Remove the globally package I(coffee-script).
|
||||
- code: "npm: path=/app/location"
|
||||
description: Install packages based on package.json.
|
||||
- code: "npm: path=/app/location state=latest"
|
||||
description: Update packages based on package.json to their latest version.
|
||||
- code: "npm: path=/app/location executable=/opt/nvm/v0.10.1/bin/npm state=present"
|
||||
description: Install packages based on package.json using the npm installed with nvm v0.10.1.
|
||||
'''
|
||||
|
||||
import os
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
class Npm(object):
|
||||
def __init__(self, module, **kwargs):
|
||||
self.module = module
|
||||
self.glbl = kwargs['glbl']
|
||||
self.name = kwargs['name']
|
||||
self.version = kwargs['version']
|
||||
self.path = kwargs['path']
|
||||
self.production = kwargs['production']
|
||||
|
||||
if kwargs['executable']:
|
||||
self.executable = kwargs['executable']
|
||||
else:
|
||||
self.executable = module.get_bin_path('npm', True)
|
||||
|
||||
if kwargs['version']:
|
||||
self.name_version = self.name + '@' + self.version
|
||||
else:
|
||||
self.name_version = self.name
|
||||
|
||||
def _exec(self, args, run_in_check_mode=False, check_rc=True):
|
||||
if not self.module.check_mode or (self.module.check_mode and run_in_check_mode):
|
||||
cmd = [self.executable] + args
|
||||
|
||||
if self.glbl:
|
||||
cmd.append('--global')
|
||||
if self.production:
|
||||
cmd.append('--production')
|
||||
if self.name:
|
||||
cmd.append(self.name_version)
|
||||
|
||||
#If path is specified, cd into that path and run the command.
|
||||
if self.path:
|
||||
os.chdir(self.path)
|
||||
|
||||
rc, out, err = self.module.run_command(cmd, check_rc=check_rc)
|
||||
return out
|
||||
return ''
|
||||
|
||||
def list(self):
|
||||
cmd = ['list', '--json']
|
||||
|
||||
installed = list()
|
||||
missing = list()
|
||||
data = json.loads(self._exec(cmd, True, False))
|
||||
if 'dependencies' in data:
|
||||
for dep in data['dependencies']:
|
||||
if 'missing' in data['dependencies'][dep] and data['dependencies'][dep]['missing']:
|
||||
missing.append(dep)
|
||||
else:
|
||||
installed.append(dep)
|
||||
#Named dependency not installed
|
||||
else:
|
||||
missing.append(self.name)
|
||||
|
||||
return installed, missing
|
||||
|
||||
def install(self):
|
||||
return self._exec(['install'])
|
||||
|
||||
def update(self):
|
||||
return self._exec(['update'])
|
||||
|
||||
def uninstall(self):
|
||||
return self._exec(['uninstall'])
|
||||
|
||||
def list_outdated(self):
|
||||
outdated = list()
|
||||
data = self._exec(['outdated'], True, False)
|
||||
for dep in data.splitlines():
|
||||
if dep:
|
||||
pkg, other = dep.split('@', 1)
|
||||
outdated.append(pkg)
|
||||
|
||||
return outdated
|
||||
|
||||
|
||||
def main():
|
||||
arg_spec = dict(
|
||||
name=dict(default=None),
|
||||
path=dict(default=None),
|
||||
version=dict(default=None),
|
||||
production=dict(default='no', type='bool'),
|
||||
executable=dict(default=None),
|
||||
state=dict(default='present', choices=['present', 'absent', 'latest'])
|
||||
)
|
||||
arg_spec['global']=dict(default='no', type='bool')
|
||||
module = AnsibleModule(
|
||||
argument_spec=arg_spec,
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
name = module.params['name']
|
||||
path = module.params['path']
|
||||
version = module.params['version']
|
||||
glbl = module.params['global']
|
||||
production = module.params['production']
|
||||
executable = module.params['executable']
|
||||
state = module.params['state']
|
||||
|
||||
if not path and not glbl:
|
||||
module.fail_json(msg='path must be specified when not using global')
|
||||
if state == 'absent' and not name:
|
||||
module.fail_json(msg='uninstalling a package is only available for named packages')
|
||||
|
||||
npm = Npm(module, name=name, path=path, version=version, glbl=glbl, production=production, \
|
||||
executable=executable)
|
||||
|
||||
changed = False
|
||||
if state == 'present':
|
||||
installed, missing = npm.list()
|
||||
if len(missing):
|
||||
changed = True
|
||||
npm.install()
|
||||
elif state == 'latest':
|
||||
installed, missing = npm.list()
|
||||
outdated = npm.list_outdated()
|
||||
if len(missing) or len(outdated):
|
||||
changed = True
|
||||
npm.install()
|
||||
npm.update()
|
||||
else: #absent
|
||||
installed, missing = npm.list()
|
||||
if name in installed:
|
||||
changed = True
|
||||
npm.uninstall()
|
||||
|
||||
module.exit_json(changed=changed)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
main()
|
||||
222
library/packaging/openbsd_pkg
Normal file
222
library/packaging/openbsd_pkg
Normal file
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Patrik Lundin <patrik.lundin.swe@gmail.com>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
import re
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: openbsd_pkg
|
||||
author: Patrik Lundin
|
||||
version_added: "1.1"
|
||||
short_description: Manage packages on OpenBSD.
|
||||
description:
|
||||
- Manage packages on OpenBSD using the pkg tools.
|
||||
options:
|
||||
name:
|
||||
required: true
|
||||
description:
|
||||
- Name of the package.
|
||||
state:
|
||||
required: true
|
||||
choices: [ present, latest, absent ]
|
||||
description:
|
||||
- C(present) will make sure the package is installed.
|
||||
C(latest) will make sure the latest version of the package is installed.
|
||||
C(absent) will make sure the specified package is not installed.
|
||||
examples:
|
||||
- description: Make sure nmap is installed
|
||||
code: "openbsd_pkg: name=nmap state=present"
|
||||
- description: Make sure nmap is the latest version
|
||||
code: "openbsd_pkg: name=nmap state=latest"
|
||||
- description: Make sure nmap is not installed
|
||||
code: "openbsd_pkg: name=nmap state=absent"
|
||||
'''
|
||||
|
||||
# select whether we dump additional debug info through syslog
|
||||
syslogging = False
|
||||
|
||||
# Function used for executing commands.
|
||||
def execute_command(cmd, syslogging):
|
||||
if syslogging:
|
||||
syslog.openlog('ansible-%s' % os.path.basename(__file__))
|
||||
syslog.syslog(syslog.LOG_NOTICE, 'Command %s' % '|'.join(cmd))
|
||||
|
||||
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
(out, err) = p.communicate()
|
||||
rc = p.returncode
|
||||
return (rc, out, err)
|
||||
|
||||
# Function used for getting the name of a currently installed package.
|
||||
def get_current_name(name, specific_version):
|
||||
info_cmd = 'pkg_info'
|
||||
(rc, stdout, stderr) = execute_command("%s" % (info_cmd), syslogging)
|
||||
if rc != 0:
|
||||
return (rc, stdout, stderr)
|
||||
|
||||
if specific_version:
|
||||
syntax = "%s"
|
||||
else:
|
||||
syntax = "%s-"
|
||||
|
||||
for line in stdout.splitlines():
|
||||
if syntax % name in line:
|
||||
current_name = line.split()[0]
|
||||
|
||||
return current_name
|
||||
|
||||
# Function used to find out if a package is currently installed.
|
||||
def get_package_state(name, specific_version):
|
||||
info_cmd = 'pkg_info -e'
|
||||
|
||||
if specific_version:
|
||||
syntax = "%s %s"
|
||||
else:
|
||||
syntax = "%s %s-*"
|
||||
|
||||
rc, stdout, stderr = execute_command(syntax % (info_cmd, name), syslogging)
|
||||
|
||||
if rc == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# Function used to make sure a package is present.
|
||||
def package_present(name, installed_state):
|
||||
install_cmd = 'pkg_add -I'
|
||||
if installed_state is False:
|
||||
rc, stdout, stderr = execute_command("%s %s" % (install_cmd, name), syslogging)
|
||||
# pkg_add returns 0 even if the package does not exist
|
||||
# so depend on stderr instead if something bad happened.
|
||||
if stderr:
|
||||
rc = 1
|
||||
changed=False
|
||||
else:
|
||||
changed=True
|
||||
else:
|
||||
rc = 0
|
||||
stdout = ''
|
||||
stderr = ''
|
||||
changed=False
|
||||
|
||||
return (rc, stdout, stderr, changed)
|
||||
|
||||
# Function used to make sure a package is the latest available version.
|
||||
def package_latest(name, installed_state, specific_version):
|
||||
|
||||
upgrade_cmd = 'pkg_add -u'
|
||||
pre_upgrade_name = ''
|
||||
post_upgrade_name = ''
|
||||
if installed_state is True:
|
||||
|
||||
# pkg_add -u exits 0 even if no update was needed, so compare the
|
||||
# installed package before and after to know if we changed anything.
|
||||
pre_upgrade_name = get_current_name(name, specific_version)
|
||||
|
||||
(rc, stdout, stderr) = execute_command("%s %s" % (upgrade_cmd, name), syslogging)
|
||||
|
||||
# 'pkg_add -u' returns 0 even when something strange happened, stdout
|
||||
# should be empty if everything went fine.
|
||||
if stdout:
|
||||
rc=1
|
||||
|
||||
post_upgrade_name = get_current_name(name, specific_version)
|
||||
|
||||
if pre_upgrade_name == post_upgrade_name:
|
||||
changed = False
|
||||
else:
|
||||
changed = True
|
||||
|
||||
return (rc, stdout, stderr, changed)
|
||||
|
||||
else:
|
||||
# If package was not installed at all just make it present.
|
||||
return package_present(name, installed_state)
|
||||
|
||||
# Function used to make sure a package is not installed.
|
||||
def package_absent(name, installed_state):
|
||||
remove_cmd = 'pkg_delete -I'
|
||||
if installed_state is True:
|
||||
rc, stdout, stderr = execute_command("%s %s" % (remove_cmd, name), syslogging)
|
||||
|
||||
if rc == 0:
|
||||
changed=True
|
||||
else:
|
||||
changed=False
|
||||
else:
|
||||
rc = 0
|
||||
stdout = ''
|
||||
stderr = ''
|
||||
changed=False
|
||||
|
||||
return (rc, stdout, stderr, changed)
|
||||
|
||||
# ===========================================
|
||||
# Main control flow
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required=True),
|
||||
state = dict(required=True, choices=['absent', 'installed', 'latest', 'present', 'removed']),
|
||||
)
|
||||
)
|
||||
|
||||
name = module.params['name']
|
||||
state = module.params['state']
|
||||
|
||||
rc = 0
|
||||
stdout = ''
|
||||
stderr = ''
|
||||
result = {}
|
||||
result['name'] = name
|
||||
result['state'] = state
|
||||
|
||||
# Decide if the name contains a version number.
|
||||
# This regex is based on packages-specs(7).
|
||||
match = re.search("-[0-9]", name)
|
||||
if match:
|
||||
specific_version = True
|
||||
else:
|
||||
specific_version = False
|
||||
|
||||
# Get package state
|
||||
installed_state = get_package_state(name, specific_version)
|
||||
|
||||
# Perform requested action
|
||||
if state in ['installed', 'present']:
|
||||
(rc, stdout, stderr, changed) = package_present(name, installed_state)
|
||||
elif state in ['absent', 'removed']:
|
||||
(rc, stdout, stderr, changed) = package_absent(name, installed_state)
|
||||
elif state == 'latest':
|
||||
(rc, stdout, stderr, changed) = package_latest(name, installed_state, specific_version)
|
||||
|
||||
if rc != 0:
|
||||
if stderr:
|
||||
module.fail_json(msg=stderr)
|
||||
else:
|
||||
module.fail_json(msg=stdout)
|
||||
|
||||
result['changed'] = changed
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
main()
|
||||
149
library/packaging/opkg
Normal file
149
library/packaging/opkg
Normal file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Patrick Pelletier <pp.pelletier@gmail.com>
|
||||
# Based on pacman (Afterburn) and pkgin (Shaun Zinck) modules
|
||||
#
|
||||
# This module 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.
|
||||
#
|
||||
# This software 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 this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: opkg
|
||||
author: Patrick Pelletier
|
||||
short_description: Package manager for OpenWrt
|
||||
description:
|
||||
- Manages OpenWrt packages
|
||||
version_added: "1.1"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- name of package to install/remove
|
||||
required: true
|
||||
state:
|
||||
description:
|
||||
- state of the package
|
||||
choices: [ 'present', 'absent' ]
|
||||
required: false
|
||||
default: present
|
||||
update_cache:
|
||||
description:
|
||||
- update the package db first
|
||||
required: false
|
||||
default: "no"
|
||||
choices: [ "yes", "no" ]
|
||||
notes: []
|
||||
'''
|
||||
EXAMPLES = '''
|
||||
opkg: name=foo state=present
|
||||
opkg: name=foo state=present update_cache=yes
|
||||
opkg: name=foo state=absent
|
||||
opkg: name=foo,bar state=absent
|
||||
'''
|
||||
|
||||
|
||||
def update_package_db(module, opkg_path):
|
||||
""" Updates packages list. """
|
||||
|
||||
rc, out, err = module.run_command("%s update" % opkg_path)
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="could not update package db")
|
||||
|
||||
|
||||
def query_package(module, opkg_path, name, state="present"):
|
||||
""" Returns whether a package is installed or not. """
|
||||
|
||||
if state == "present":
|
||||
|
||||
rc, out, err = module.run_command("%s list-installed | grep -q ^%s" % (opkg_path, name))
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def remove_packages(module, opkg_path, packages):
|
||||
""" Uninstalls one or more packages if installed. """
|
||||
|
||||
remove_c = 0
|
||||
# Using a for loop incase of error, we can report the package that failed
|
||||
for package in packages:
|
||||
# Query the package first, to see if we even need to remove
|
||||
if not query_package(module, opkg_path, package):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s remove %s" % (opkg_path, package))
|
||||
|
||||
if query_package(module, opkg_path, package):
|
||||
module.fail_json(msg="failed to remove %s: %s" % (package, out))
|
||||
|
||||
remove_c += 1
|
||||
|
||||
if remove_c > 0:
|
||||
|
||||
module.exit_json(changed=True, msg="removed %s package(s)" % remove_c)
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already absent")
|
||||
|
||||
|
||||
def install_packages(module, opkg_path, packages):
|
||||
""" Installs one or more packages if not already installed. """
|
||||
|
||||
install_c = 0
|
||||
|
||||
for package in packages:
|
||||
if query_package(module, opkg_path, package):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s install %s" % (opkg_path, package))
|
||||
|
||||
if not query_package(module, opkg_path, package):
|
||||
module.fail_json(msg="failed to install %s: %s" % (package, out))
|
||||
|
||||
install_c += 1
|
||||
|
||||
if install_c > 0:
|
||||
module.exit_json(changed=True, msg="installed %s package(s)" % (install_c))
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already present")
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(aliases=["pkg"], required=True),
|
||||
state = dict(default="present", choices=["present", "installed", "absent", "removed"]),
|
||||
update_cache = dict(default="no", aliases=["update-cache"], type='bool')
|
||||
)
|
||||
)
|
||||
|
||||
opkg_path = module.get_bin_path('opkg', True, ['/bin'])
|
||||
|
||||
p = module.params
|
||||
|
||||
if p["update_cache"]:
|
||||
update_package_db(module, opkg_path)
|
||||
|
||||
pkgs = p["name"].split(",")
|
||||
|
||||
if p["state"] in ["present", "installed"]:
|
||||
install_packages(module, opkg_path, pkgs)
|
||||
|
||||
elif p["state"] in ["absent", "removed"]:
|
||||
remove_packages(module, opkg_path, pkgs)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
|
||||
main()
|
||||
163
library/packaging/pacman
Normal file
163
library/packaging/pacman
Normal file
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/python -tt
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2012, Afterburn
|
||||
# Written by Afterburn <http://github.com/afterburn>
|
||||
# Based on apt module written by Matthew Williams <matthew@flowroute.com>
|
||||
#
|
||||
# This module 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.
|
||||
#
|
||||
# This software 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 this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: pacman
|
||||
short_description: Package manager for Archlinux
|
||||
description:
|
||||
- Manages Archlinux packages
|
||||
|
||||
version_added: "1.0"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- name of package to install, upgrade or remove.
|
||||
required: true
|
||||
|
||||
state:
|
||||
description:
|
||||
- state of the package (installed or absent).
|
||||
required: false
|
||||
|
||||
update_cache:
|
||||
description:
|
||||
- update the package database first (pacman -Syy).
|
||||
required: false
|
||||
default: "no"
|
||||
choices: [ "yes", "no" ]
|
||||
|
||||
author: Afterburn
|
||||
notes: []
|
||||
examples:
|
||||
- code: "pacman: name=foo state=installed"
|
||||
description: install package foo
|
||||
- code: "pacman: name=foo state=absent"
|
||||
description: remove package foo
|
||||
- code: "pacman: name=foo,bar state=absent"
|
||||
description: remove packages foo and bar
|
||||
- code: "pacman: name=bar, state=installed, update_cache=yes"
|
||||
description: update the package database (pacman -Syy) and install bar (bar will be the updated if a newer version exists)
|
||||
|
||||
'''
|
||||
|
||||
|
||||
import json
|
||||
import shlex
|
||||
import os
|
||||
import sys
|
||||
|
||||
PACMAN_PATH = "/usr/bin/pacman"
|
||||
|
||||
def query_package(module, name, state="installed"):
|
||||
|
||||
# pacman -Q returns 0 if the package is installed,
|
||||
# 1 if it is not installed
|
||||
if state == "installed":
|
||||
rc = os.system("pacman -Q %s" % (name))
|
||||
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def update_package_db(module):
|
||||
rc = os.system("pacman -Syy > /dev/null")
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="could not update package db")
|
||||
|
||||
|
||||
def remove_packages(module, packages):
|
||||
|
||||
remove_c = 0
|
||||
# Using a for loop incase of error, we can report the package that failed
|
||||
for package in packages:
|
||||
# Query the package first, to see if we even need to remove
|
||||
if not query_package(module, package):
|
||||
continue
|
||||
|
||||
rc = os.system("pacman -R %s --noconfirm > /dev/null" % (package))
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="failed to remove %s" % (package))
|
||||
|
||||
remove_c += 1
|
||||
|
||||
if remove_c > 0:
|
||||
|
||||
module.exit_json(changed=True, msg="removed %s package(s)" % remove_c)
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already absent")
|
||||
|
||||
|
||||
def install_packages(module, packages):
|
||||
|
||||
install_c = 0
|
||||
|
||||
for package in packages:
|
||||
if query_package(module, package):
|
||||
continue
|
||||
|
||||
rc = os.system("pacman -S %s --noconfirm > /dev/null" % (package))
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="failed to install %s" % (package))
|
||||
|
||||
install_c += 1
|
||||
|
||||
if install_c > 0:
|
||||
module.exit_json(changed=True, msg="installed %s package(s)" % (install_c))
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already installed")
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
state = dict(default="installed", choices=["installed","absent"]),
|
||||
update_cache = dict(default="no", aliases=["update-cache"], type='bool'),
|
||||
name = dict(aliases=["pkg"], required=True)))
|
||||
|
||||
|
||||
if not os.path.exists(PACMAN_PATH):
|
||||
module.fail_json(msg="cannot find pacman, looking for %s" % (PACMAN_PATH))
|
||||
|
||||
p = module.params
|
||||
|
||||
|
||||
if p["update_cache"]:
|
||||
update_package_db(module)
|
||||
|
||||
pkgs = p["name"].split(",")
|
||||
|
||||
if p["state"] == "installed":
|
||||
install_packages(module, pkgs)
|
||||
|
||||
elif p["state"] == "absent":
|
||||
remove_packages(module, pkgs)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
|
||||
main()
|
||||
242
library/packaging/pip
Normal file
242
library/packaging/pip
Normal file
@@ -0,0 +1,242 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2012, Matt Wright <matt@nobien.net>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
import tempfile
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: pip
|
||||
short_description: Manages Python library dependencies.
|
||||
description:
|
||||
- Manage Python library dependencies.
|
||||
version_added: "0.7"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of a Python library to install
|
||||
required: false
|
||||
default: null
|
||||
version:
|
||||
description:
|
||||
- The version number to install of the Python library specified in the I(name) parameter
|
||||
required: false
|
||||
default: null
|
||||
requirements:
|
||||
description:
|
||||
- The path to a pip requirements file
|
||||
required: false
|
||||
default: null
|
||||
virtualenv:
|
||||
description:
|
||||
- An optional path to a I(virtualenv) directory to install into
|
||||
required: false
|
||||
default: null
|
||||
virtualenv_site_packages:
|
||||
version_added: "1.0"
|
||||
description:
|
||||
- Whether the virtual environment will inherit packages from the
|
||||
global site-packages directory. Note that if this setting is
|
||||
changed on an already existing virtual environment it will not
|
||||
have any effect, the environment must be deleted and newly
|
||||
created.
|
||||
required: false
|
||||
default: "no"
|
||||
choices: [ "yes", "no" ]
|
||||
virtualenv_command:
|
||||
version_aded: "1.1"
|
||||
description:
|
||||
- The command to create the virtual environment with. For example
|
||||
C(pyvenv), C(virtualenv), C(virtualenv2).
|
||||
required: false
|
||||
default: virtualenv
|
||||
use_mirrors:
|
||||
description:
|
||||
- Whether to use mirrors when installing python libraries. If using
|
||||
an older version of pip (< 1.0), you should set this to no because
|
||||
older versions of pip do not support I(--use-mirrors).
|
||||
required: false
|
||||
default: "yes"
|
||||
choices: [ "yes", "no" ]
|
||||
version_added: "1.0"
|
||||
state:
|
||||
description:
|
||||
- The state of module
|
||||
required: false
|
||||
default: present
|
||||
choices: [ "present", "absent", "latest" ]
|
||||
extra_args:
|
||||
description:
|
||||
- Extra arguments passed to pip.
|
||||
required: false
|
||||
default: null
|
||||
version_added: "1.0"
|
||||
examples:
|
||||
- code: "pip: name=flask"
|
||||
description: Install I(flask) python package.
|
||||
- code: "pip: name=flask version=0.8"
|
||||
description: Install I(flask) python package on version 0.8.
|
||||
- code: "pip: name=flask virtualenv=/my_app/venv"
|
||||
description: "Install I(Flask) (U(http://flask.pocoo.org/)) into the specified I(virtualenv), inheriting none of the globally installed modules"
|
||||
- code: "pip: name=flask virtualenv=/my_app/venv virtualenv_site_packages=yes"
|
||||
description: "Install I(Flask) (U(http://flask.pocoo.org/)) into the specified I(virtualenv), inheriting globally installed modules"
|
||||
- code: "pip: name=flask virtualenv=/my_app/venv virtualenv_command=virtualenv-2.7"
|
||||
description: "Install I(Flask) (U(http://flask.pocoo.org/)) into the specified I(virtualenv), using Python 2.7"
|
||||
- code: "pip: requirements=/my_app/requirements.txt"
|
||||
description: Install specified python requirements.
|
||||
- code: "pip: requirements=/my_app/requirements.txt virtualenv=/my_app/venv"
|
||||
description: Install specified python requirements in indicated I(virtualenv).
|
||||
- code: "pip: requirements=/my_app/requirements.txt extra_args='-i https://example.com/pypi/simple'"
|
||||
description: Install specified python requirements and custom Index URL.
|
||||
notes:
|
||||
- Please note that virtualenv (U(http://www.virtualenv.org/)) must be installed on the remote host if the virtualenv parameter is specified.
|
||||
requirements: [ "virtualenv", "pip" ]
|
||||
author: Matt Wright
|
||||
'''
|
||||
|
||||
|
||||
def _get_full_name(name, version=None):
|
||||
if version is None:
|
||||
resp = name
|
||||
else:
|
||||
resp = name + '==' + version
|
||||
return resp
|
||||
|
||||
|
||||
def _get_pip(module, env):
|
||||
# On Debian and Ubuntu, pip is pip.
|
||||
# On Fedora18 and up, pip is python-pip.
|
||||
# On Fedora17 and below, CentOS and RedHat 6 and 5, pip is pip-python.
|
||||
# On Fedora, CentOS, and RedHat, the exception is in the virtualenv.
|
||||
# There, pip is just pip.
|
||||
# Try pip with the virtualenv directory first.
|
||||
pip = module.get_bin_path('pip', False, ['%s/bin' % env])
|
||||
for p in ['python-pip', 'pip-python']:
|
||||
if not pip:
|
||||
pip = module.get_bin_path(p, False, ['%s/bin' % env])
|
||||
# pip should have been found by now. The final call to get_bin_path
|
||||
# will trigger fail_json.
|
||||
if not pip:
|
||||
pip = module.get_bin_path('pip', True, ['%s/bin' % env])
|
||||
return pip
|
||||
|
||||
|
||||
def _fail(module, cmd, out, err):
|
||||
msg = ''
|
||||
if out:
|
||||
msg += "stdout: %s" % (out, )
|
||||
if err:
|
||||
msg += "\n:stderr: %s" % (err, )
|
||||
module.fail_json(cmd=cmd, msg=msg)
|
||||
|
||||
|
||||
def main():
|
||||
state_map = dict(
|
||||
present='install',
|
||||
absent='uninstall -y',
|
||||
latest='install -U',
|
||||
)
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
state=dict(default='present', choices=state_map.keys()),
|
||||
name=dict(default=None, required=False),
|
||||
version=dict(default=None, required=False),
|
||||
requirements=dict(default=None, required=False),
|
||||
virtualenv=dict(default=None, required=False),
|
||||
virtualenv_site_packages=dict(default='no', type='bool'),
|
||||
virtualenv_command=dict(default='virtualenv', required=False),
|
||||
use_mirrors=dict(default='yes', type='bool'),
|
||||
extra_args=dict(default=None, required=False),
|
||||
),
|
||||
required_one_of=[['name', 'requirements']],
|
||||
mutually_exclusive=[['name', 'requirements']],
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
state = module.params['state']
|
||||
name = module.params['name']
|
||||
version = module.params['version']
|
||||
requirements = module.params['requirements']
|
||||
use_mirrors = module.params['use_mirrors']
|
||||
extra_args = module.params['extra_args']
|
||||
|
||||
if state == 'latest' and version is not None:
|
||||
module.fail_json(msg='version is incompatible with state=latest')
|
||||
if name and '=' in name:
|
||||
module.fail_json(msg='version must be specified in the version parameter')
|
||||
|
||||
err = ''
|
||||
out = ''
|
||||
|
||||
env = module.params['virtualenv']
|
||||
virtualenv_command = module.params['virtualenv_command']
|
||||
|
||||
if env:
|
||||
env = os.path.expanduser(env)
|
||||
virtualenv = module.get_bin_path(virtualenv_command, True)
|
||||
if not os.path.exists(os.path.join(env, 'bin', 'activate')):
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
if module.params['virtualenv_site_packages']:
|
||||
cmd = '%s --system-site-packages %s' % (virtualenv, env)
|
||||
else:
|
||||
cmd = '%s %s' % (virtualenv, env)
|
||||
rc, out_venv, err_venv = module.run_command(cmd)
|
||||
out += out_venv
|
||||
err += err_venv
|
||||
if rc != 0:
|
||||
_fail(module, cmd, out, err)
|
||||
|
||||
pip = _get_pip(module, env)
|
||||
|
||||
cmd = '%s %s' % (pip, state_map[state])
|
||||
if state != 'absent' and use_mirrors:
|
||||
cmd += ' --use-mirrors'
|
||||
if extra_args:
|
||||
cmd += ' %s' % extra_args
|
||||
if name:
|
||||
cmd += ' %s' % _get_full_name(name, version)
|
||||
elif requirements:
|
||||
cmd += ' -r %s' % requirements
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
os.chdir(tempfile.gettempdir())
|
||||
rc, out_pip, err_pip = module.run_command(cmd)
|
||||
out += out_pip
|
||||
err += err_pip
|
||||
if rc == 1 and state == 'absent' and 'not installed' in out_pip:
|
||||
pass # rc is 1 when attempting to uninstall non-installed package
|
||||
elif rc != 0:
|
||||
_fail(module, cmd, out, err)
|
||||
|
||||
if state == 'absent':
|
||||
changed = 'Successfully uninstalled' in out_pip
|
||||
else:
|
||||
changed = 'Successfully installed' in out_pip
|
||||
|
||||
module.exit_json(changed=changed, cmd=cmd, name=name, version=version,
|
||||
state=state, requirements=requirements, virtualenv=env, stdout=out, stderr=err)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
|
||||
main()
|
||||
136
library/packaging/pkgin
Normal file
136
library/packaging/pkgin
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Shaun Zinck
|
||||
# Written by Shaun Zinck <shaun.zinck at gmail.com>
|
||||
# Based on pacman module written by Afterburn <http://github.com/afterburn>
|
||||
# that was based on apt module written by Matthew Williams <matthew@flowroute.com>
|
||||
#
|
||||
# This module 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.
|
||||
#
|
||||
# This software 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 this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: pkgin
|
||||
short_description: Package manager for SmartOS
|
||||
description:
|
||||
- Manages SmartOS packages
|
||||
version_added: "1.0"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- name of package to install/remove
|
||||
required: true
|
||||
state:
|
||||
description:
|
||||
- state of the package
|
||||
choices: [ 'present', 'absent' ]
|
||||
required: false
|
||||
default: present
|
||||
author: Shaun Zinck
|
||||
notes: []
|
||||
examples:
|
||||
- code: "pkgin: name=foo state=present"
|
||||
description: install package foo"
|
||||
- code: "pkgin: name=foo state=absent"
|
||||
description: remove package foo
|
||||
- code: "pkgin: name=foo,bar state=absent"
|
||||
description: remove packages foo and bar
|
||||
'''
|
||||
|
||||
|
||||
import json
|
||||
import shlex
|
||||
import os
|
||||
import sys
|
||||
|
||||
def query_package(module, pkgin_path, name, state="present"):
|
||||
|
||||
if state == "present":
|
||||
|
||||
rc, out, err = module.run_command("%s list | grep ^%s" % (pkgin_path, name))
|
||||
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def remove_packages(module, pkgin_path, packages):
|
||||
|
||||
remove_c = 0
|
||||
# Using a for loop incase of error, we can report the package that failed
|
||||
for package in packages:
|
||||
# Query the package first, to see if we even need to remove
|
||||
if not query_package(module, pkgin_path, package):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s -y remove %s" % (pkgin_path, package))
|
||||
|
||||
if query_package(module, pkgin_path, package):
|
||||
module.fail_json(msg="failed to remove %s: %s" % (package, out))
|
||||
|
||||
remove_c += 1
|
||||
|
||||
if remove_c > 0:
|
||||
|
||||
module.exit_json(changed=True, msg="removed %s package(s)" % remove_c)
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already absent")
|
||||
|
||||
|
||||
def install_packages(module, pkgin_path, packages):
|
||||
|
||||
install_c = 0
|
||||
|
||||
for package in packages:
|
||||
if query_package(module, pkgin_path, package):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s -y install %s" % (pkgin_path, package))
|
||||
|
||||
if not query_package(module, pkgin_path, package):
|
||||
module.fail_json(msg="failed to install %s: %s" % (package, out))
|
||||
|
||||
install_c += 1
|
||||
|
||||
if install_c > 0:
|
||||
module.exit_json(changed=True, msg="present %s package(s)" % (install_c))
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already present")
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
state = dict(default="present", choices=["present","absent"]),
|
||||
name = dict(aliases=["pkg"], required=True)))
|
||||
|
||||
pkgin_path = module.get_bin_path('pkgin', True, ['/opt/local/bin'])
|
||||
|
||||
p = module.params
|
||||
|
||||
pkgs = p["name"].split(",")
|
||||
|
||||
if p["state"] == "present":
|
||||
install_packages(module, pkgin_path, pkgs)
|
||||
|
||||
elif p["state"] == "absent":
|
||||
remove_packages(module, pkgin_path, pkgs)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
|
||||
main()
|
||||
149
library/packaging/rhn_channel
Normal file
149
library/packaging/rhn_channel
Normal file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: rhn_channel
|
||||
short_description: Adds or removes Red Hat software channels
|
||||
description:
|
||||
- Adds or removes Red Hat software channels
|
||||
version_added: "1.1"
|
||||
author: Vincent Van der Kussen
|
||||
notes:
|
||||
- this module fetches the system id from RHN.
|
||||
requirements:
|
||||
- none
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- name of the software channel
|
||||
required: true
|
||||
default: null
|
||||
sysname:
|
||||
description:
|
||||
- name of the system as it is known in RHN/Satellite
|
||||
required: true
|
||||
default: null
|
||||
state:
|
||||
description:
|
||||
- whether the channel should be present or not
|
||||
required: false
|
||||
default: present
|
||||
url:
|
||||
description:
|
||||
- The full url to the RHN/Satellite api
|
||||
required: true
|
||||
user:
|
||||
description:
|
||||
- RHN/Satellite user
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- "the user's password"
|
||||
required: true
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
rhn_channel: name=rhel-x86_64-server-v2vwin-6 sysname=server01 url=https://rhn.redhat.com/rpc/api user=rhnuser password=guessme
|
||||
'''
|
||||
|
||||
import xmlrpclib
|
||||
from operator import itemgetter
|
||||
import re
|
||||
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
|
||||
def get_systemid(client, session, sysname):
|
||||
systems = client.system.listUserSystems(session)
|
||||
for system in systems:
|
||||
if system.get('name') == sysname:
|
||||
idres = system.get('id')
|
||||
idd = int(idres)
|
||||
return idd
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
|
||||
# unused:
|
||||
#
|
||||
#def get_localsystemid():
|
||||
# f = open("/etc/sysconfig/rhn/systemid", "r")
|
||||
# content = f.read()
|
||||
# loc_id = re.search(r'\b(ID-)(\d{10})' ,content)
|
||||
# return loc_id.group(2)
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
|
||||
def subscribe_channels(channels, client, session, sysname, sys_id):
|
||||
c = base_channels(client, session, sys_id)
|
||||
c.append(channels)
|
||||
return client.channel.software.setSystemChannels(session, sys_id, c)
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
|
||||
def unsubscribe_channels(channels, client, session, sysname, sys_id):
|
||||
c = base_channels(client, session, sys_id)
|
||||
c.remove(channels)
|
||||
return client.channel.software.setSystemChannels(session, sys_id, c)
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
|
||||
def base_channels(client, session, sys_id):
|
||||
basechan = client.channel.software.listSystemChannels(session, sys_id)
|
||||
chans = [item['channel_label'] for item in basechan]
|
||||
return chans
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
state = dict(default='present', choices=['present', 'absent']),
|
||||
name = dict(required=True),
|
||||
sysname = dict(required=True),
|
||||
url = dict(required=True),
|
||||
user = dict(required=True),
|
||||
password = dict(required=True, aliases=['pwd']),
|
||||
)
|
||||
# supports_check_mode=True
|
||||
)
|
||||
|
||||
state = module.params['state']
|
||||
channelname = module.params['name']
|
||||
systname = module.params['sysname']
|
||||
saturl = module.params['url']
|
||||
user = module.params['user']
|
||||
password = module.params['password']
|
||||
|
||||
#initialize connection
|
||||
client = xmlrpclib.Server(saturl, verbose=0)
|
||||
session = client.auth.login(user, password)
|
||||
|
||||
# get systemid
|
||||
sys_id = get_systemid(client, session, systname)
|
||||
|
||||
# get channels for system
|
||||
chans = base_channels(client, session, sys_id)
|
||||
|
||||
|
||||
if state == 'present':
|
||||
if channelname in chans:
|
||||
module.exit_json(changed=False, msg="Channel %s already exists" % channelname)
|
||||
else:
|
||||
subscribe_channels(channelname, client, session, systname, sys_id)
|
||||
module.exit_json(changed=True, msg="Channel %s added" % channelname)
|
||||
|
||||
if state == 'absent':
|
||||
if not channelname in chans:
|
||||
module.exit_json(changed=False, msg="Not subscribed to channel %s." % channelname)
|
||||
else:
|
||||
unsubscribe_channels(channelname, client, session, systname, sys_id)
|
||||
module.exit_json(changed=True, msg="Channel %s removed" % channelname)
|
||||
|
||||
client.auth.logout(session)
|
||||
|
||||
|
||||
# include magic from lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
main()
|
||||
179
library/packaging/svr4pkg
Normal file
179
library/packaging/svr4pkg
Normal file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2012, Boyd Adamson <boyd () boydadamson.com>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: svr4pkg
|
||||
short_description: Manage Solaris SVR4 packages
|
||||
description:
|
||||
- Manages SVR4 packages on Solaris 10 and 11.
|
||||
- These were the native packages on Solaris <= 10 and are available
|
||||
as a legacy feature in Solaris 11.
|
||||
- Note that this is a very basic packaging system. It will not enforce
|
||||
dependencies on install or remove.
|
||||
version_added: "0.9"
|
||||
author: Boyd Adamson
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Package name, e.g. C(SUNWcsr)
|
||||
required: true
|
||||
|
||||
state:
|
||||
description:
|
||||
- Whether to install (C(present)), or remove (C(absent)) a package.
|
||||
- If the package is to be installed, then I(src) is required.
|
||||
- The SVR4 package system doesn't provide an upgrade operation. You need to uninstall the old, then install the new package.
|
||||
required: true
|
||||
choices: ["present", "absent"]
|
||||
|
||||
src:
|
||||
description:
|
||||
- Specifies the location to install the package from. Required when C(state=present).
|
||||
- "Can be any path acceptable to the C(pkgadd) command's C(-d) option. e.g.: C(somefile.pkg), C(/dir/with/pkgs), C(http:/server/mypkgs.pkg)."
|
||||
- If using a file or directory, they must already be accessible by the host. See the M(copy) module for a way to get them there.
|
||||
proxy:
|
||||
description:
|
||||
- HTTP[s] proxy to be used if C(src) is a URL.
|
||||
|
||||
examples:
|
||||
- code: svr4pkg name=CSWcommon src=/tmp/cswpkgs.pkg state=present
|
||||
description: Install a package from an already copied file
|
||||
- code: 'svr4pkg name=CSWpkgutil src=http://get.opencsw.org/now state=present'
|
||||
description: Install a package directly from an http site
|
||||
- code: svr4pkg name=SUNWgnome-sound-recorder state=absent
|
||||
description: Ensure that a package is not installed.
|
||||
'''
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
def package_installed(module, name):
|
||||
cmd = [module.get_bin_path('pkginfo', True)]
|
||||
cmd.append('-q')
|
||||
cmd.append(name)
|
||||
rc, out, err = module.run_command(' '.join(cmd), shell=False)
|
||||
if rc == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def create_admin_file():
|
||||
(desc, filename) = tempfile.mkstemp(prefix='ansible_svr4pkg', text=True)
|
||||
fullauto = '''
|
||||
mail=
|
||||
instance=unique
|
||||
partial=nocheck
|
||||
runlevel=quit
|
||||
idepend=nocheck
|
||||
rdepend=nocheck
|
||||
space=quit
|
||||
setuid=nocheck
|
||||
conflict=nocheck
|
||||
action=nocheck
|
||||
networktimeout=60
|
||||
networkretries=3
|
||||
authentication=quit
|
||||
keystore=/var/sadm/security
|
||||
proxy=
|
||||
basedir=default
|
||||
'''
|
||||
os.write(desc, fullauto)
|
||||
os.close(desc)
|
||||
return filename
|
||||
|
||||
def run_command(module, cmd):
|
||||
progname = cmd[0]
|
||||
cmd[0] = module.get_bin_path(progname, True)
|
||||
return module.run_command(cmd)
|
||||
|
||||
def package_install(module, name, src, proxy):
|
||||
adminfile = create_admin_file()
|
||||
cmd = [ 'pkgadd', '-na', adminfile, '-d', src ]
|
||||
if proxy is not None:
|
||||
cmd += [ '-x', proxy ]
|
||||
cmd.append(name)
|
||||
(rc, out, err) = run_command(module, cmd)
|
||||
os.unlink(adminfile)
|
||||
return (rc, out, err)
|
||||
|
||||
def package_uninstall(module, name, src):
|
||||
adminfile = create_admin_file()
|
||||
cmd = [ 'pkgrm', '-na', adminfile, name]
|
||||
(rc, out, err) = run_command(module, cmd)
|
||||
os.unlink(adminfile)
|
||||
return (rc, out, err)
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required = True),
|
||||
state = dict(required = True, choices=['present', 'absent']),
|
||||
src = dict(default = None),
|
||||
proxy = dict(default = None)
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
state = module.params['state']
|
||||
name = module.params['name']
|
||||
src = module.params['src']
|
||||
proxy = module.params['proxy']
|
||||
rc = None
|
||||
out = ''
|
||||
err = ''
|
||||
result = {}
|
||||
result['name'] = name
|
||||
result['state'] = state
|
||||
|
||||
if state == 'present':
|
||||
if src is None:
|
||||
module.fail_json(name=name,
|
||||
msg="src is required when state=present")
|
||||
if not package_installed(module, name):
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
(rc, out, err) = package_install(module, name, src, proxy)
|
||||
# Stdout is normally empty but for some packages can be
|
||||
# very long and is not often useful
|
||||
if len(out) > 75:
|
||||
out = out[:75] + '...'
|
||||
|
||||
elif state == 'absent':
|
||||
if package_installed(module, name):
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
(rc, out, err) = package_uninstall(module, name, src)
|
||||
out = out[:75]
|
||||
|
||||
if rc is None:
|
||||
result['changed'] = False
|
||||
else:
|
||||
result['changed'] = True
|
||||
|
||||
if out:
|
||||
result['stdout'] = out
|
||||
if err:
|
||||
result['stderr'] = err
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
# include magic from lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
main()
|
||||
700
library/packaging/yum
Normal file
700
library/packaging/yum
Normal file
@@ -0,0 +1,700 @@
|
||||
#!/usr/bin/python -tt
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2012, Red Hat, Inc
|
||||
# Written by Seth Vidal <skvidal at fedoraproject.org>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
|
||||
import traceback
|
||||
import os
|
||||
import yum
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: yum
|
||||
short_description: Manages packages with the I(yum) package manager
|
||||
description:
|
||||
- Will install, upgrade, remove, and list packages with the I(yum) package manager.
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- package name, or package specifier with version, like C(name-1.0).
|
||||
required: true
|
||||
default: null
|
||||
aliases: []
|
||||
list:
|
||||
description:
|
||||
- various non-idempotent commands for usage with C(/usr/bin/ansible) and I(not) playbooks. See examples.
|
||||
required: false
|
||||
default: null
|
||||
state:
|
||||
description:
|
||||
- whether to install (C(present), C(latest)), or remove (C(absent)) a package.
|
||||
required: false
|
||||
choices: [ "present", "latest", "absent" ]
|
||||
default: "present"
|
||||
enablerepo:
|
||||
description:
|
||||
- Repoid of repositories to enable for the install/update operation.
|
||||
These repos will not persist beyond the transaction
|
||||
multiple repos separated with a ','
|
||||
required: false
|
||||
version_added: "0.9"
|
||||
default: null
|
||||
aliases: []
|
||||
|
||||
disablerepo:
|
||||
description:
|
||||
- I(repoid) of repositories to disable for the install/update operation
|
||||
These repos will not persist beyond the transaction
|
||||
Multiple repos separated with a ','
|
||||
required: false
|
||||
version_added: "0.9"
|
||||
default: null
|
||||
aliases: []
|
||||
|
||||
conf_file:
|
||||
description:
|
||||
- The remote yum configuration file to use for the transaction.
|
||||
required: false
|
||||
version_added: "0.6"
|
||||
default: null
|
||||
aliases: []
|
||||
|
||||
disable_gpg_check:
|
||||
description:
|
||||
- Whether to disable the GPG checking of signatures of packages being
|
||||
installed. Has an effect only if state is I(present) or I(latest).
|
||||
required: false
|
||||
version_added: "1.2"
|
||||
default: "no"
|
||||
choices: ["yes", "no"]
|
||||
aliases: []
|
||||
|
||||
examples:
|
||||
- code: yum name=httpd state=latest
|
||||
- code: yum name=httpd state=removed
|
||||
- code: yum name=httpd enablerepo=testing state=installed
|
||||
notes: []
|
||||
# informational: requirements for nodes
|
||||
requirements: [ yum, rpm ]
|
||||
author: Seth Vidal
|
||||
'''
|
||||
|
||||
def_qf = "%{name}-%{version}-%{release}.%{arch}"
|
||||
|
||||
repoquery='/usr/bin/repoquery'
|
||||
if not os.path.exists(repoquery):
|
||||
repoquery = None
|
||||
|
||||
yumbin='/usr/bin/yum'
|
||||
|
||||
def yum_base(conf_file=None, cachedir=False):
|
||||
|
||||
my = yum.YumBase()
|
||||
my.preconf.debuglevel=0
|
||||
my.preconf.errorlevel=0
|
||||
if conf_file and os.path.exists(conf_file):
|
||||
my.preconf.fn = conf_file
|
||||
if cachedir or os.geteuid() != 0:
|
||||
if hasattr(my, 'setCacheDir'):
|
||||
my.setCacheDir()
|
||||
else:
|
||||
cachedir = yum.misc.getCacheDir()
|
||||
my.repos.setCacheDir(cachedir)
|
||||
my.conf.cache = 0
|
||||
|
||||
return my
|
||||
|
||||
def po_to_nevra(po):
|
||||
|
||||
if hasattr(po, 'ui_nevra'):
|
||||
return po.ui_nevra
|
||||
else:
|
||||
return '%s-%s-%s.%s' % (po.name, po.version, po.release, po.arch)
|
||||
|
||||
def is_installed(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=[], dis_repos=[]):
|
||||
|
||||
if not repoq:
|
||||
|
||||
pkgs = []
|
||||
try:
|
||||
my = yum_base(conf_file)
|
||||
for rid in en_repos:
|
||||
my.repos.enableRepo(rid)
|
||||
for rid in dis_repos:
|
||||
my.repos.disableRepo(rid)
|
||||
|
||||
e,m,u = my.rpmdb.matchPackageNames([pkgspec])
|
||||
pkgs = e + m
|
||||
if not pkgs:
|
||||
pkgs.extend(my.returnInstalledPackagesByDep(pkgspec))
|
||||
except Exception, e:
|
||||
module.fail_json(msg="Failure talking to yum: %s" % e)
|
||||
|
||||
return [ po_to_nevra(p) for p in pkgs ]
|
||||
|
||||
else:
|
||||
|
||||
cmd = repoq + ["--disablerepo=*", "--pkgnarrow=installed", "--qf", qf, pkgspec]
|
||||
rc,out,err = module.run_command(cmd)
|
||||
cmd = repoq + ["--disablerepo=*", "--pkgnarrow=installed", "--qf", qf, "--whatprovides", pkgspec]
|
||||
rc2,out2,err2 = module.run_command(cmd)
|
||||
if rc == 0 and rc2 == 0:
|
||||
out += out2
|
||||
return [ p for p in out.split('\n') if p.strip() ]
|
||||
else:
|
||||
module.fail_json(msg='Error from repoquery: %s: %s' % (cmd, err + err2))
|
||||
|
||||
return []
|
||||
|
||||
def is_available(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=[], dis_repos=[]):
|
||||
|
||||
if not repoq:
|
||||
|
||||
pkgs = []
|
||||
try:
|
||||
my = yum_base(conf_file)
|
||||
for rid in en_repos:
|
||||
my.repos.enableRepo(rid)
|
||||
for rid in dis_repos:
|
||||
my.repos.disableRepo(rid)
|
||||
|
||||
e,m,u = my.pkgSack.matchPackageNames([pkgspec])
|
||||
pkgs = e + m
|
||||
if not pkgs:
|
||||
pkgs.extend(my.returnPackagesByDep(pkgspec))
|
||||
except Exception, e:
|
||||
module.fail_json(msg="Failure talking to yum: %s" % e)
|
||||
|
||||
return [ po_to_nevra(p) for p in pkgs ]
|
||||
|
||||
else:
|
||||
myrepoq = list(repoq)
|
||||
|
||||
for repoid in en_repos:
|
||||
r_cmd = ['--enablerepo', repoid]
|
||||
myrepoq.extend(r_cmd)
|
||||
|
||||
for repoid in dis_repos:
|
||||
r_cmd = ['--disablerepo', repoid]
|
||||
myrepoq.extend(r_cmd)
|
||||
|
||||
cmd = myrepoq + ["--qf", qf, pkgspec]
|
||||
rc,out,err = module.run_command(cmd)
|
||||
if rc == 0:
|
||||
return [ p for p in out.split('\n') if p.strip() ]
|
||||
else:
|
||||
module.fail_json(msg='Error from repoquery: %s: %s' % (cmd, err))
|
||||
|
||||
|
||||
return []
|
||||
|
||||
def is_update(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=[], dis_repos=[]):
|
||||
|
||||
if not repoq:
|
||||
|
||||
retpkgs = []
|
||||
pkgs = []
|
||||
updates = []
|
||||
|
||||
try:
|
||||
my = yum_base(conf_file)
|
||||
for rid in en_repos:
|
||||
my.repos.enableRepo(rid)
|
||||
for rid in dis_repos:
|
||||
my.repos.disableRepo(rid)
|
||||
|
||||
pkgs = my.returnPackagesByDep(pkgspec) + my.returnInstalledPackagesByDep(pkgspec)
|
||||
if not pkgs:
|
||||
e,m,u = my.pkgSack.matchPackageNames([pkgspec])
|
||||
pkgs = e + m
|
||||
updates = my.doPackageLists(pkgnarrow='updates').updates
|
||||
except Exception, e:
|
||||
module.fail_json(msg="Failure talking to yum: %s" % e)
|
||||
|
||||
for pkg in pkgs:
|
||||
if pkg in updates:
|
||||
retpkgs.append(pkg)
|
||||
|
||||
return set([ po_to_nevra(p) for p in retpkgs ])
|
||||
|
||||
else:
|
||||
myrepoq = list(repoq)
|
||||
for repoid in en_repos:
|
||||
r_cmd = ['--enablerepo', repoid]
|
||||
myrepoq.extend(r_cmd)
|
||||
|
||||
for repoid in dis_repos:
|
||||
r_cmd = ['--disablerepo', repoid]
|
||||
myrepoq.extend(r_cmd)
|
||||
|
||||
|
||||
cmd = myrepoq + ["--pkgnarrow=updates", "--qf", qf, pkgspec]
|
||||
rc,out,err = module.run_command(cmd)
|
||||
|
||||
if rc == 0:
|
||||
return set([ p for p in out.split('\n') if p.strip() ])
|
||||
else:
|
||||
module.fail_json(msg='Error from repoquery: %s: %s' % (cmd, err))
|
||||
|
||||
return []
|
||||
|
||||
def what_provides(module, repoq, req_spec, conf_file, qf=def_qf, en_repos=[], dis_repos=[]):
|
||||
|
||||
if not repoq:
|
||||
|
||||
pkgs = []
|
||||
try:
|
||||
my = yum_base(conf_file)
|
||||
for rid in en_repos:
|
||||
my.repos.enableRepo(rid)
|
||||
for rid in dis_repos:
|
||||
my.repos.disableRepo(rid)
|
||||
|
||||
pkgs = my.returnPackagesByDep(req_spec) + my.returnInstalledPackagesByDep(req_spec)
|
||||
if not pkgs:
|
||||
e,m,u = my.pkgSack.matchPackageNames([req_spec])
|
||||
pkgs.extend(e)
|
||||
pkgs.extend(m)
|
||||
e,m,u = my.rpmdb.matchPackageNames([req_spec])
|
||||
pkgs.extend(e)
|
||||
pkgs.extend(m)
|
||||
except Exception, e:
|
||||
module.fail_json(msg="Failure talking to yum: %s" % e)
|
||||
|
||||
return set([ po_to_nevra(p) for p in pkgs ])
|
||||
|
||||
else:
|
||||
myrepoq = list(repoq)
|
||||
for repoid in en_repos:
|
||||
r_cmd = ['--enablerepo', repoid]
|
||||
myrepoq.extend(r_cmd)
|
||||
|
||||
for repoid in dis_repos:
|
||||
r_cmd = ['--disablerepo', repoid]
|
||||
myrepoq.extend(r_cmd)
|
||||
|
||||
cmd = myrepoq + ["--qf", qf, "--whatprovides", req_spec]
|
||||
rc,out,err = module.run_command(cmd)
|
||||
cmd = myrepoq + ["--qf", qf, req_spec]
|
||||
rc2,out2,err2 = module.run_command(cmd)
|
||||
if rc == 0 and rc2 == 0:
|
||||
out += out2
|
||||
pkgs = set([ p for p in out.split('\n') if p.strip() ])
|
||||
if not pkgs:
|
||||
pkgs = is_installed(module, repoq, req_spec, conf_file, qf=qf)
|
||||
return pkgs
|
||||
else:
|
||||
module.fail_json(msg='Error from repoquery: %s: %s' % (cmd, err + err2))
|
||||
|
||||
return []
|
||||
|
||||
def local_nvra(module, path):
|
||||
"""return nvra of a local rpm passed in"""
|
||||
|
||||
cmd = ['/bin/rpm', '-qp' ,'--qf',
|
||||
'%{name}-%{version}-%{release}.%{arch}\n', path ]
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc != 0:
|
||||
return None
|
||||
nvra = out.split('\n')[0]
|
||||
return nvra
|
||||
|
||||
def pkg_to_dict(pkgstr):
|
||||
|
||||
if pkgstr.strip():
|
||||
n,e,v,r,a,repo = pkgstr.split('|')
|
||||
else:
|
||||
return {'error_parsing': pkgstr}
|
||||
|
||||
d = {
|
||||
'name':n,
|
||||
'arch':a,
|
||||
'epoch':e,
|
||||
'release':r,
|
||||
'version':v,
|
||||
'repo':repo,
|
||||
'nevra': '%s:%s-%s-%s.%s' % (e,n,v,r,a)
|
||||
}
|
||||
|
||||
if repo == 'installed':
|
||||
d['yumstate'] = 'installed'
|
||||
else:
|
||||
d['yumstate'] = 'available'
|
||||
|
||||
return d
|
||||
|
||||
def repolist(module, repoq, qf="%{repoid}"):
|
||||
|
||||
cmd = repoq + ["--qf", qf, "-a"]
|
||||
rc,out,err = module.run_command(cmd)
|
||||
ret = []
|
||||
if rc == 0:
|
||||
ret = set([ p for p in out.split('\n') if p.strip() ])
|
||||
return ret
|
||||
|
||||
def list_stuff(module, conf_file, stuff):
|
||||
|
||||
qf = "%{name}|%{epoch}|%{version}|%{release}|%{arch}|%{repoid}"
|
||||
repoq = [repoquery, '--show-duplicates', '--plugins', '--quiet', '-q']
|
||||
if conf_file and os.path.exists(conf_file):
|
||||
repoq += ['-c', conf_file]
|
||||
|
||||
if stuff == 'installed':
|
||||
return [ pkg_to_dict(p) for p in is_installed(module, repoq, '-a', conf_file, qf=qf) if p.strip() ]
|
||||
elif stuff == 'updates':
|
||||
return [ pkg_to_dict(p) for p in is_update(module, repoq, '-a', conf_file, qf=qf) if p.strip() ]
|
||||
elif stuff == 'available':
|
||||
return [ pkg_to_dict(p) for p in is_available(module, repoq, '-a', conf_file, qf=qf) if p.strip() ]
|
||||
elif stuff == 'repos':
|
||||
return [ dict(repoid=name, state='enabled') for name in repolist(module, repoq) if name.strip() ]
|
||||
else:
|
||||
return [ pkg_to_dict(p) for p in is_installed(module, repoq, stuff, conf_file, qf=qf) + is_available(module, repoq, stuff, conf_file, qf=qf) if p.strip() ]
|
||||
|
||||
def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
|
||||
|
||||
res = {}
|
||||
res['results'] = []
|
||||
res['msg'] = ''
|
||||
res['rc'] = 0
|
||||
res['changed'] = False
|
||||
|
||||
for spec in items:
|
||||
pkg = None
|
||||
|
||||
# check if pkgspec is installed (if possible for idempotence)
|
||||
# localpkg
|
||||
if spec.endswith('.rpm') and '://' not in spec:
|
||||
# get the pkg name-v-r.arch
|
||||
if not os.path.exists(spec):
|
||||
res['msg'] += "No Package file matching '%s' found on system" % spec
|
||||
module.fail_json(**res)
|
||||
|
||||
nvra = local_nvra(module, spec)
|
||||
# look for them in the rpmdb
|
||||
if is_installed(module, repoq, nvra, conf_file, en_repos=en_repos, dis_repos=dis_repos):
|
||||
# if they are there, skip it
|
||||
continue
|
||||
pkg = spec
|
||||
|
||||
# URL
|
||||
elif '://' in spec:
|
||||
pkg = spec
|
||||
|
||||
#groups :(
|
||||
elif spec.startswith('@'):
|
||||
# complete wild ass guess b/c it's a group
|
||||
pkg = spec
|
||||
|
||||
# range requires or file-requires or pkgname :(
|
||||
else:
|
||||
# look up what pkgs provide this
|
||||
pkglist = what_provides(module, repoq, spec, conf_file, en_repos=en_repos, dis_repos=dis_repos)
|
||||
if not pkglist:
|
||||
res['msg'] += "No Package matching '%s' found available, installed or updated" % spec
|
||||
module.fail_json(**res)
|
||||
|
||||
# if any of them are installed
|
||||
# then nothing to do
|
||||
|
||||
found = False
|
||||
for this in pkglist:
|
||||
if is_installed(module, repoq, this, conf_file, en_repos=en_repos, dis_repos=dis_repos):
|
||||
found = True
|
||||
res['results'].append('%s providing %s is already installed' % (this, spec))
|
||||
break
|
||||
|
||||
# if the version of the pkg you have installed is not in ANY repo, but there are
|
||||
# other versions in the repos (both higher and lower) then the previous checks won't work.
|
||||
# so we check one more time. This really only works for pkgname - not for file provides or virt provides
|
||||
# but virt provides should be all caught in what_provides on its own.
|
||||
# highly irritating
|
||||
if not found:
|
||||
if is_installed(module, repoq, spec, conf_file, en_repos=en_repos, dis_repos=dis_repos):
|
||||
found = True
|
||||
res['results'].append('package providing %s is already installed' % (spec))
|
||||
|
||||
if found:
|
||||
continue
|
||||
# if not - then pass in the spec as what to install
|
||||
# we could get here if nothing provides it but that's not
|
||||
# the error we're catching here
|
||||
pkg = spec
|
||||
|
||||
cmd = yum_basecmd + ['install', pkg]
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
|
||||
changed = True
|
||||
|
||||
rc, out, err = module.run_command(cmd)
|
||||
|
||||
if rc != 0 and 'Nothing to do' in err:
|
||||
# avoid failing in the 'Nothing To Do' case
|
||||
# this may happen with an URL spec
|
||||
rc = 0
|
||||
err = ''
|
||||
out = '%s: Nothing to do' % spec
|
||||
changed = False
|
||||
|
||||
res['rc'] += rc
|
||||
res['results'].append(out)
|
||||
res['msg'] += err
|
||||
|
||||
# FIXME - if we did an install - go and check the rpmdb to see if it actually installed
|
||||
# look for the pkg in rpmdb
|
||||
# look for the pkg via obsoletes
|
||||
|
||||
# accumulate any changes
|
||||
res['changed'] |= changed
|
||||
|
||||
module.exit_json(**res)
|
||||
|
||||
|
||||
def remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
|
||||
|
||||
res = {}
|
||||
res['results'] = []
|
||||
res['msg'] = ''
|
||||
res['changed'] = False
|
||||
res['rc'] = 0
|
||||
|
||||
for pkg in items:
|
||||
is_group = False
|
||||
# group remove - this is doom on a stick
|
||||
if pkg.startswith('@'):
|
||||
is_group = True
|
||||
else:
|
||||
if not is_installed(module, repoq, pkg, conf_file, en_repos=en_repos, dis_repos=dis_repos):
|
||||
res['results'].append('%s is not installed' % pkg)
|
||||
continue
|
||||
|
||||
# run an actual yum transaction
|
||||
cmd = yum_basecmd + ["remove", pkg]
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
|
||||
rc, out, err = module.run_command(cmd)
|
||||
|
||||
res['rc'] += rc
|
||||
res['results'].append(out)
|
||||
res['msg'] += err
|
||||
|
||||
# compile the results into one batch. If anything is changed
|
||||
# then mark changed
|
||||
# at the end - if we've end up failed then fail out of the rest
|
||||
# of the process
|
||||
|
||||
# at this point we should check to see if the pkg is no longer present
|
||||
|
||||
if not is_group: # we can't sensibly check for a group being uninstalled reliably
|
||||
# look to see if the pkg shows up from is_installed. If it doesn't
|
||||
if not is_installed(module, repoq, pkg, conf_file, en_repos=en_repos, dis_repos=dis_repos):
|
||||
res['changed'] = True
|
||||
else:
|
||||
module.fail_json(**res)
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(**res)
|
||||
|
||||
module.exit_json(**res)
|
||||
|
||||
def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
|
||||
|
||||
res = {}
|
||||
res['results'] = []
|
||||
res['msg'] = ''
|
||||
res['changed'] = False
|
||||
res['rc'] = 0
|
||||
|
||||
for spec in items:
|
||||
|
||||
pkg = None
|
||||
basecmd = 'update'
|
||||
# groups, again
|
||||
if spec.startswith('@'):
|
||||
pkg = spec
|
||||
# dep/pkgname - find it
|
||||
else:
|
||||
if is_installed(module, repoq, spec, conf_file, en_repos=en_repos, dis_repos=dis_repos):
|
||||
basecmd = 'update'
|
||||
else:
|
||||
basecmd = 'install'
|
||||
|
||||
pkglist = what_provides(module, repoq, spec, conf_file, en_repos=en_repos, dis_repos=dis_repos)
|
||||
if not pkglist:
|
||||
res['msg'] += "No Package matching '%s' found available, installed or updated" % spec
|
||||
module.fail_json(**res)
|
||||
|
||||
nothing_to_do = True
|
||||
for this in pkglist:
|
||||
if basecmd == 'install' and is_available(module, repoq, this, conf_file, en_repos=en_repos, dis_repos=dis_repos):
|
||||
nothing_to_do = False
|
||||
break
|
||||
|
||||
if basecmd == 'update' and is_update(module, repoq, this, conf_file, en_repos=en_repos, dis_repos=en_repos):
|
||||
nothing_to_do = False
|
||||
break
|
||||
|
||||
if nothing_to_do:
|
||||
res['results'].append("All packages providing %s are up to date" % spec)
|
||||
continue
|
||||
|
||||
pkg = spec
|
||||
|
||||
cmd = yum_basecmd + [basecmd, pkg]
|
||||
|
||||
if module.check_mode:
|
||||
return module.exit_json(changed=True)
|
||||
|
||||
rc, out, err = module.run_command(cmd)
|
||||
|
||||
res['rc'] += rc
|
||||
res['results'].append(out)
|
||||
res['msg'] += err
|
||||
|
||||
# FIXME if it is - update it and check to see if it applied
|
||||
# check to see if there is no longer an update available for the pkgspec
|
||||
|
||||
if rc:
|
||||
res['failed'] = True
|
||||
else:
|
||||
res['changed'] = True
|
||||
|
||||
module.exit_json(**res)
|
||||
|
||||
def ensure(module, state, pkgspec, conf_file, enablerepo, disablerepo,
|
||||
disable_gpg_check):
|
||||
|
||||
# take multiple args comma separated
|
||||
items = pkgspec.split(',')
|
||||
|
||||
yum_basecmd = [yumbin, '-d', '1', '-y']
|
||||
|
||||
|
||||
if not repoquery:
|
||||
repoq = None
|
||||
else:
|
||||
repoq = [repoquery, '--show-duplicates', '--plugins', '--quiet', '-q']
|
||||
|
||||
if conf_file and os.path.exists(conf_file):
|
||||
yum_basecmd += ['-c', conf_file]
|
||||
if repoq:
|
||||
repoq += ['-c', conf_file]
|
||||
|
||||
dis_repos =[]
|
||||
en_repos = []
|
||||
if disablerepo:
|
||||
dis_repos = disablerepo.split(',')
|
||||
if enablerepo:
|
||||
en_repos = enablerepo.split(',')
|
||||
|
||||
for repoid in en_repos:
|
||||
r_cmd = ['--enablerepo', repoid]
|
||||
yum_basecmd.extend(r_cmd)
|
||||
|
||||
for repoid in dis_repos:
|
||||
r_cmd = ['--disablerepo', repoid]
|
||||
yum_basecmd.extend(r_cmd)
|
||||
|
||||
if state in ['installed', 'present', 'latest']:
|
||||
my = yum_base(conf_file)
|
||||
try:
|
||||
for r in dis_repos:
|
||||
my.repos.disableRepo(r)
|
||||
|
||||
for r in en_repos:
|
||||
try:
|
||||
my.repos.enableRepo(r)
|
||||
rid = my.repos.getRepo(r)
|
||||
a = rid.repoXML.repoid
|
||||
except yum.Errors.YumBaseError, e:
|
||||
module.fail_json(msg="Error setting/accessing repo %s: %s" % (r, e))
|
||||
except yum.Errors.YumBaseError, e:
|
||||
module.fail_json(msg="Error accessing repos: %s" % e)
|
||||
|
||||
if state in ['installed', 'present']:
|
||||
if disable_gpg_check:
|
||||
yum_basecmd.append('--nogpgcheck')
|
||||
install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos)
|
||||
elif state in ['removed', 'absent']:
|
||||
remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos)
|
||||
elif state == 'latest':
|
||||
if disable_gpg_check:
|
||||
yum_basecmd.append('--nogpgcheck')
|
||||
latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos)
|
||||
|
||||
# should be caught by AnsibleModule argument_spec
|
||||
return dict(changed=False, failed=True, results='', errors='unexpected state')
|
||||
|
||||
def main():
|
||||
|
||||
# state=installed name=pkgspec
|
||||
# state=removed name=pkgspec
|
||||
# state=latest name=pkgspec
|
||||
#
|
||||
# informational commands:
|
||||
# list=installed
|
||||
# list=updates
|
||||
# list=available
|
||||
# list=repos
|
||||
# list=pkgspec
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name=dict(aliases=['pkg']),
|
||||
# removed==absent, installed==present, these are accepted as aliases
|
||||
state=dict(default='installed', choices=['absent','present','installed','removed','latest']),
|
||||
enablerepo=dict(),
|
||||
disablerepo=dict(),
|
||||
list=dict(),
|
||||
conf_file=dict(default=None),
|
||||
disable_gpg_check=dict(required=False, default="no",
|
||||
choices=BOOLEANS, type='bool'),
|
||||
),
|
||||
required_one_of = [['name','list']],
|
||||
mutually_exclusive = [['name','list']],
|
||||
supports_check_mode = True
|
||||
)
|
||||
|
||||
params = module.params
|
||||
|
||||
if params['list']:
|
||||
if not repoquery:
|
||||
module.fail_json(msg="repoquery is required to use list= with this module. Please install the yum-utils package.")
|
||||
results = dict(results=list_stuff(module, params['conf_file'], params['list']))
|
||||
module.exit_json(**results)
|
||||
|
||||
else:
|
||||
pkg = params['name']
|
||||
state = params['state']
|
||||
enablerepo = params.get('enablerepo', '')
|
||||
disablerepo = params.get('disablerepo', '')
|
||||
disable_gpg_check = params['disable_gpg_check']
|
||||
res = ensure(module, state, pkg, params['conf_file'], enablerepo,
|
||||
disablerepo, disable_gpg_check)
|
||||
module.fail_json(msg="we should never get here unless this all failed", **res)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user