parent
110fd917d6
commit
8fca263560
2 changed files with 54 additions and 46 deletions
|
@ -180,9 +180,21 @@ EXAMPLES = '''
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import xml
|
import xml
|
||||||
from ansible.module_utils.pycompat24 import get_exception
|
|
||||||
from xml.dom.minidom import parseString as parseXML
|
|
||||||
import re
|
import re
|
||||||
|
from xml.dom.minidom import parseString as parseXML
|
||||||
|
from ansible.module_utils.six import iteritems
|
||||||
|
|
||||||
|
|
||||||
|
class Package:
|
||||||
|
def __init__(self, name, prefix, version):
|
||||||
|
self.name = name
|
||||||
|
self.prefix = prefix
|
||||||
|
self.version = version
|
||||||
|
self.shouldinstall = (prefix == '+')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.prefix + self.name + self.version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def split_name_version(name):
|
def split_name_version(name):
|
||||||
|
@ -202,35 +214,35 @@ def split_name_version(name):
|
||||||
if name[0] in ['-', '~', '+']:
|
if name[0] in ['-', '~', '+']:
|
||||||
prefix = name[0]
|
prefix = name[0]
|
||||||
name = name[1:]
|
name = name[1:]
|
||||||
|
if prefix == '~':
|
||||||
|
prefix = '-'
|
||||||
|
|
||||||
version_check = re.compile('^(.*?)((?:<|>|<=|>=|=)[0-9.-]*)?$')
|
version_check = re.compile('^(.*?)((?:<|>|<=|>=|=)[0-9.-]*)?$')
|
||||||
try:
|
try:
|
||||||
reres = version_check.match(name)
|
reres = version_check.match(name)
|
||||||
name, version = reres.groups()
|
name, version = reres.groups()
|
||||||
|
if version is None:
|
||||||
|
version = ''
|
||||||
return prefix, name, version
|
return prefix, name, version
|
||||||
except:
|
except:
|
||||||
return prefix, name, None
|
return prefix, name, ''
|
||||||
|
|
||||||
|
|
||||||
def get_want_state(m, names, remove=False):
|
def get_want_state(names, remove=False):
|
||||||
packages_install = {}
|
packages = []
|
||||||
packages_remove = {}
|
|
||||||
urls = []
|
urls = []
|
||||||
for name in names:
|
for name in names:
|
||||||
if '://' in name or name.endswith('.rpm'):
|
if '://' in name or name.endswith('.rpm'):
|
||||||
urls.append(name)
|
urls.append(name)
|
||||||
else:
|
else:
|
||||||
prefix, pname, version = split_name_version(name)
|
prefix, pname, version = split_name_version(name)
|
||||||
if prefix in ['-', '~']:
|
if prefix not in ['-', '+']:
|
||||||
packages_remove[pname] = version
|
|
||||||
elif prefix == '+':
|
|
||||||
packages_install[pname] = version
|
|
||||||
else:
|
|
||||||
if remove:
|
if remove:
|
||||||
packages_remove[pname] = version
|
prefix = '-'
|
||||||
else:
|
else:
|
||||||
packages_install[pname] = version
|
prefix = '+'
|
||||||
return packages_install, packages_remove, urls
|
packages.append(Package(pname, prefix, version))
|
||||||
|
return packages, urls
|
||||||
|
|
||||||
|
|
||||||
def get_installed_state(m, packages):
|
def get_installed_state(m, packages):
|
||||||
|
@ -238,7 +250,7 @@ def get_installed_state(m, packages):
|
||||||
|
|
||||||
cmd = get_cmd(m, 'search')
|
cmd = get_cmd(m, 'search')
|
||||||
cmd.extend(['--match-exact', '--details', '--installed-only'])
|
cmd.extend(['--match-exact', '--details', '--installed-only'])
|
||||||
cmd.extend(packages)
|
cmd.extend([p.name for p in packages])
|
||||||
return parse_zypper_xml(m, cmd, fail_not_found=False)[0]
|
return parse_zypper_xml(m, cmd, fail_not_found=False)[0]
|
||||||
|
|
||||||
|
|
||||||
|
@ -340,42 +352,35 @@ def set_diff(m, retvals, result):
|
||||||
def package_present(m, name, want_latest):
|
def package_present(m, name, want_latest):
|
||||||
"install and update (if want_latest) the packages in name_install, while removing the packages in name_remove"
|
"install and update (if want_latest) the packages in name_install, while removing the packages in name_remove"
|
||||||
retvals = {'rc': 0, 'stdout': '', 'stderr': ''}
|
retvals = {'rc': 0, 'stdout': '', 'stderr': ''}
|
||||||
name_install, name_remove, urls = get_want_state(m, name)
|
packages, urls = get_want_state(name)
|
||||||
|
|
||||||
# if a version string is given, pass it to zypper
|
|
||||||
install_version = [p+name_install[p] for p in name_install if name_install[p]]
|
|
||||||
remove_version = [p+name_remove[p] for p in name_remove if name_remove[p]]
|
|
||||||
|
|
||||||
# add oldpackage flag when a version is given to allow downgrades
|
# add oldpackage flag when a version is given to allow downgrades
|
||||||
if install_version or remove_version:
|
if any(p.version for p in packages):
|
||||||
m.params['oldpackage'] = True
|
m.params['oldpackage'] = True
|
||||||
|
|
||||||
if not want_latest:
|
if not want_latest:
|
||||||
# for state=present: filter out already installed packages
|
# for state=present: filter out already installed packages
|
||||||
install_and_remove = name_install.copy()
|
# if a version is given leave the package in to let zypper handle the version
|
||||||
install_and_remove.update(name_remove)
|
# resolution
|
||||||
prerun_state = get_installed_state(m, install_and_remove)
|
packageswithoutversion = [p for p in packages if not p.version]
|
||||||
|
prerun_state = get_installed_state(m, packageswithoutversion)
|
||||||
# generate lists of packages to install or remove
|
# generate lists of packages to install or remove
|
||||||
name_install = [p for p in name_install if p not in prerun_state]
|
packages = [p for p in packages if p.shouldinstall != (p.name in prerun_state)]
|
||||||
name_remove = [p for p in name_remove if p in prerun_state]
|
|
||||||
if not any((name_install, name_remove, urls, install_version, remove_version)):
|
if not packages and not urls:
|
||||||
# nothing to install/remove and nothing to update
|
# nothing to install/remove and nothing to update
|
||||||
return None, retvals
|
return None, retvals
|
||||||
|
|
||||||
# zypper install also updates packages
|
# zypper install also updates packages
|
||||||
cmd = get_cmd(m, 'install')
|
cmd = get_cmd(m, 'install')
|
||||||
cmd.append('--')
|
cmd.append('--')
|
||||||
cmd.extend(urls)
|
cmd.extend(urls)
|
||||||
|
# pass packages to zypper
|
||||||
# pass packages with version information
|
|
||||||
cmd.extend(install_version)
|
|
||||||
cmd.extend(['-%s' % p for p in remove_version])
|
|
||||||
|
|
||||||
# allow for + or - prefixes in install/remove lists
|
# allow for + or - prefixes in install/remove lists
|
||||||
|
# also add version specifier if given
|
||||||
# do this in one zypper run to allow for dependency-resolution
|
# do this in one zypper run to allow for dependency-resolution
|
||||||
# for example "-exim postfix" runs without removing packages depending on mailserver
|
# for example "-exim postfix" runs without removing packages depending on mailserver
|
||||||
cmd.extend(name_install)
|
cmd.extend([str(p) for p in packages])
|
||||||
cmd.extend(['-%s' % p for p in name_remove])
|
|
||||||
|
|
||||||
retvals['cmd'] = cmd
|
retvals['cmd'] = cmd
|
||||||
result, retvals['rc'], retvals['stdout'], retvals['stderr'] = parse_zypper_xml(m, cmd)
|
result, retvals['rc'], retvals['stdout'], retvals['stderr'] = parse_zypper_xml(m, cmd)
|
||||||
|
@ -402,22 +407,21 @@ def package_absent(m, name):
|
||||||
"remove the packages in name"
|
"remove the packages in name"
|
||||||
retvals = {'rc': 0, 'stdout': '', 'stderr': ''}
|
retvals = {'rc': 0, 'stdout': '', 'stderr': ''}
|
||||||
# Get package state
|
# Get package state
|
||||||
name_install, name_remove, urls = get_want_state(m, name, remove=True)
|
packages, urls = get_want_state(name, remove=True)
|
||||||
if name_install:
|
if any(p.prefix == '+' for p in packages):
|
||||||
m.fail_json(msg="Can not combine '+' prefix with state=remove/absent.")
|
m.fail_json(msg="Can not combine '+' prefix with state=remove/absent.")
|
||||||
if urls:
|
if urls:
|
||||||
m.fail_json(msg="Can not remove via URL.")
|
m.fail_json(msg="Can not remove via URL.")
|
||||||
if m.params['type'] == 'patch':
|
if m.params['type'] == 'patch':
|
||||||
m.fail_json(msg="Can not remove patches.")
|
m.fail_json(msg="Can not remove patches.")
|
||||||
prerun_state = get_installed_state(m, name_remove)
|
prerun_state = get_installed_state(m, packages)
|
||||||
remove_version = [p+name_remove[p] for p in name_remove if name_remove[p]]
|
packages = [p for p in packages if p.name in prerun_state]
|
||||||
name_remove = [p for p in name_remove if p in prerun_state]
|
|
||||||
if not name_remove and not remove_version:
|
if not packages:
|
||||||
return None, retvals
|
return None, retvals
|
||||||
|
|
||||||
cmd = get_cmd(m, 'remove')
|
cmd = get_cmd(m, 'remove')
|
||||||
cmd.extend(name_remove)
|
cmd.extend([p.name + p.version for p in packages])
|
||||||
cmd.extend(remove_version)
|
|
||||||
|
|
||||||
retvals['cmd'] = cmd
|
retvals['cmd'] = cmd
|
||||||
result, retvals['rc'], retvals['stdout'], retvals['stderr'] = parse_zypper_xml(m, cmd)
|
result, retvals['rc'], retvals['stdout'], retvals['stderr'] = parse_zypper_xml(m, cmd)
|
||||||
|
|
|
@ -211,10 +211,14 @@
|
||||||
# test simultaneous remove and install using +- prefixes
|
# test simultaneous remove and install using +- prefixes
|
||||||
|
|
||||||
- name: install hello to prep next task
|
- name: install hello to prep next task
|
||||||
zypper: name=hello, state=present
|
zypper:
|
||||||
|
name: hello
|
||||||
|
state: present
|
||||||
|
|
||||||
- name: remove metamail to prep next task
|
- name: remove metamail to prep next task
|
||||||
zypper: name=hello, state=absent
|
zypper:
|
||||||
|
name: metamail
|
||||||
|
state: absent
|
||||||
|
|
||||||
- name: install and remove in the same run, with +- prefix
|
- name: install and remove in the same run, with +- prefix
|
||||||
zypper:
|
zypper:
|
||||||
|
|
Loading…
Reference in a new issue