@ -129,6 +129,15 @@ options:
choices : [ " yes " , " no " ]
version_added : " 2.1 "
installroot :
description :
- Specifies an alternative installroot , relative to which all packages
will be installed .
required : false
version_added : " 2.3 "
default : " / "
aliases : [ ]
notes :
- When used with a loop of package names in a playbook , ansible optimizes
the call to the yum module . Instead of calling the module with a single
@ -156,6 +165,8 @@ requirements: [ yum ]
author :
- " Ansible Core Team "
- " Seth Vidal "
- " Eduard Snesarev (github.com/verm666) "
- " Berend De Schouwer (github.com/berenddeschouwer) "
'''
EXAMPLES = '''
@ -212,12 +223,18 @@ BUFSIZE = 65536
def_qf = " % {name} - % {version} - % {release} . % {arch} "
rpmbin = None
def yum_base ( conf_file = None ):
def yum_base ( conf_file = None , installroot = ' / ' ):
my = yum . YumBase ( )
my . preconf . debuglevel = 0
my . preconf . errorlevel = 0
my . preconf . plugins = True
#my.preconf.releasever = '/'
if installroot != ' / ' :
# do not setup installroot by default, because of error
# CRITICAL:yum.cli:Config Error: Error accessing file for config file:////etc/yum.conf
# in old yum version (like in CentOS 6.6)
my . conf . installroot = installroot
if conf_file and os . path . exists ( conf_file ) :
my . preconf . fn = conf_file
if os . geteuid ( ) != 0 :
@ -270,7 +287,7 @@ def po_to_nevra(po):
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 = None , dis_repos = None , is_pkg = False ):
def is_installed ( module , repoq , pkgspec , conf_file , qf = def_qf , en_repos = None , dis_repos = None , is_pkg = False , installroot = ' / ' ):
if en_repos is None :
en_repos = [ ]
if dis_repos is None :
@ -279,7 +296,7 @@ def is_installed(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=None, di
if not repoq :
pkgs = [ ]
try :
my = yum_base ( conf_file )
my = yum_base ( conf_file , installroot )
for rid in dis_repos :
my . repos . disableRepo ( rid )
for rid in en_repos :
@ -326,7 +343,7 @@ def is_installed(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=None, di
return [ ]
def is_available ( module , repoq , pkgspec , conf_file , qf = def_qf , en_repos = None , dis_repos = None ):
def is_available ( module , repoq , pkgspec , conf_file , qf = def_qf , en_repos = None , dis_repos = None , installroot = ' / ' ):
if en_repos is None :
en_repos = [ ]
if dis_repos is None :
@ -336,7 +353,7 @@ def is_available(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=None, di
pkgs = [ ]
try :
my = yum_base ( conf_file )
my = yum_base ( conf_file , installroot )
for rid in dis_repos :
my . repos . disableRepo ( rid )
for rid in en_repos :
@ -370,7 +387,7 @@ def is_available(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=None, di
return [ ]
def is_update ( module , repoq , pkgspec , conf_file , qf = def_qf , en_repos = None , dis_repos = None ):
def is_update ( module , repoq , pkgspec , conf_file , qf = def_qf , en_repos = None , dis_repos = None , installroot = ' / ' ):
if en_repos is None :
en_repos = [ ]
if dis_repos is None :
@ -383,7 +400,7 @@ def is_update(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=None, dis_r
updates = [ ]
try :
my = yum_base ( conf_file )
my = yum_base ( conf_file , installroot )
for rid in dis_repos :
my . repos . disableRepo ( rid )
for rid in en_repos :
@ -422,7 +439,7 @@ def is_update(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=None, dis_r
return set ( )
def what_provides ( module , repoq , req_spec , conf_file , qf = def_qf , en_repos = None , dis_repos = None ):
def what_provides ( module , repoq , req_spec , conf_file , qf = def_qf , en_repos = None , dis_repos = None , installroot = ' / ' ):
if en_repos is None :
en_repos = [ ]
if dis_repos is None :
@ -439,7 +456,7 @@ def what_provides(module, repoq, req_spec, conf_file, qf=def_qf, en_repos=None,
pkgs = [ ]
try :
my = yum_base ( conf_file )
my = yum_base ( conf_file , installroot )
for rid in dis_repos :
my . repos . disableRepo ( rid )
for rid in en_repos :
@ -475,7 +492,7 @@ def what_provides(module, repoq, req_spec, conf_file, qf=def_qf, en_repos=None,
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 )
pkgs = is_installed ( module , repoq , req_spec , conf_file , qf = qf , installroot = installroot )
return pkgs
else :
module . fail_json ( msg = ' Error from repoquery: %s : %s ' % ( cmd , err + err2 ) )
@ -570,7 +587,7 @@ def repolist(module, repoq, qf="%{repoid}"):
ret = set ( [ p for p in out . split ( ' \n ' ) if p . strip ( ) ] )
return ret
def list_stuff ( module , repoquerybin , conf_file , stuff ):
def list_stuff ( module , repoquerybin , conf_file , stuff , installroot = ' / ' ):
qf = " % {name} | % {epoch} | % {version} | % {release} | % {arch} | % {repoid} "
# is_installed goes through rpm instead of repoquery so it needs a slightly different format
@ -580,17 +597,17 @@ def list_stuff(module, repoquerybin, conf_file, stuff):
repoq + = [ ' -c ' , conf_file ]
if stuff == ' installed ' :
return [ pkg_to_dict ( p ) for p in sorted ( is_installed ( module , repoq , ' -a ' , conf_file , qf = is_installed_qf )) if p . strip ( ) ]
return [ pkg_to_dict ( p ) for p in sorted ( is_installed ( module , repoq , ' -a ' , conf_file , qf = is_installed_qf , installroot = installroot )) if p . strip ( ) ]
elif stuff == ' updates ' :
return [ pkg_to_dict ( p ) for p in sorted ( is_update ( module , repoq , ' -a ' , conf_file , qf = qf )) if p . strip ( ) ]
return [ pkg_to_dict ( p ) for p in sorted ( is_update ( module , repoq , ' -a ' , conf_file , qf = qf , installroot = installroot )) if p . strip ( ) ]
elif stuff == ' available ' :
return [ pkg_to_dict ( p ) for p in sorted ( is_available ( module , repoq , ' -a ' , conf_file , qf = qf )) if p . strip ( ) ]
return [ pkg_to_dict ( p ) for p in sorted ( is_available ( module , repoq , ' -a ' , conf_file , qf = qf , installroot = installroot )) if p . strip ( ) ]
elif stuff == ' repos ' :
return [ dict ( repoid = name , state = ' enabled ' ) for name in sorted ( repolist ( module , repoq ) ) if name . strip ( ) ]
else :
return [ pkg_to_dict ( p ) for p in sorted ( is_installed ( module , repoq , stuff , conf_file , qf = is_installed_qf ) + is_available ( module , repoq , stuff , conf_file , qf = qf ) ) if p . strip ( ) ]
return [ pkg_to_dict ( p ) for p in sorted ( is_installed ( module , repoq , stuff , conf_file , qf = is_installed_qf , installroot = installroot ) + is_available ( module , repoq , stuff , conf_file , qf = qf , installroot = installroot ) ) if p . strip ( ) ]
def install ( module , items , repoq , yum_basecmd , conf_file , en_repos , dis_repos ):
def install ( module , items , repoq , yum_basecmd , conf_file , en_repos , dis_repos , installroot = ' / ' ):
pkgs = [ ]
res = { }
@ -616,7 +633,7 @@ def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
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 is_installed ( module , repoq , nvra , conf_file , en_repos = en_repos , dis_repos = dis_repos , installroot = installroot ):
# if they are there, skip it
continue
pkg = spec
@ -626,7 +643,7 @@ def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
# download package so that we can check if it's already installed
package = fetch_rpm_from_url ( spec , module = module )
nvra = local_nvra ( module , package )
if is_installed ( module , repoq , nvra , conf_file , en_repos = en_repos , dis_repos = dis_repos ):
if is_installed ( module , repoq , nvra , conf_file , en_repos = en_repos , dis_repos = dis_repos , installroot = installroot ):
# if it's there, skip it
continue
pkg = package
@ -642,13 +659,13 @@ def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
# short circuit all the bs - and search for it as a pkg in is_installed
# if you find it then we're done
if not set ( [ ' * ' , ' ? ' ] ) . intersection ( set ( spec ) ) :
installed_pkgs = is_installed ( module , repoq , spec , conf_file , en_repos = en_repos , dis_repos = dis_repos , is_pkg = True )
installed_pkgs = is_installed ( module , repoq , spec , conf_file , en_repos = en_repos , dis_repos = dis_repos , is_pkg = True , installroot = installroot )
if installed_pkgs :
res [ ' results ' ] . append ( ' %s providing %s is already installed ' % ( installed_pkgs [ 0 ] , spec ) )
continue
# look up what pkgs provide this
pkglist = what_provides ( module , repoq , spec , conf_file , en_repos = en_repos , dis_repos = dis_repos )
pkglist = what_provides ( module , repoq , spec , conf_file , en_repos = en_repos , dis_repos = dis_repos , installroot = installroot )
if not pkglist :
res [ ' msg ' ] + = " No package matching ' %s ' found available, installed or updated " % spec
res [ ' results ' ] . append ( " No package matching ' %s ' found available, installed or updated " % spec )
@ -668,7 +685,7 @@ def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
found = False
for this in pkglist :
if is_installed ( module , repoq , this , conf_file , en_repos = en_repos , dis_repos = dis_repos , is_pkg = True ):
if is_installed ( module , repoq , this , conf_file , en_repos = en_repos , dis_repos = dis_repos , is_pkg = True , installroot = installroot ):
found = True
res [ ' results ' ] . append ( ' %s providing %s is already installed ' % ( this , spec ) )
break
@ -679,7 +696,7 @@ def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
# 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 ):
if is_installed ( module , repoq , spec , conf_file , en_repos = en_repos , dis_repos = dis_repos , installroot = installroot ):
found = True
res [ ' results ' ] . append ( ' package providing %s is already installed ' % ( spec ) )
@ -747,7 +764,7 @@ def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
return res
def remove ( module , items , repoq , yum_basecmd , conf_file , en_repos , dis_repos ):
def remove ( module , items , repoq , yum_basecmd , conf_file , en_repos , dis_repos , installroot = ' / ' ):
pkgs = [ ]
res = { }
@ -762,7 +779,7 @@ def remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
if pkg . startswith ( ' @ ' ) :
is_group = True
else :
if not is_installed ( module , repoq , pkg , conf_file , en_repos = en_repos , dis_repos = dis_repos ):
if not is_installed ( module , repoq , pkg , conf_file , en_repos = en_repos , dis_repos = dis_repos , installroot = installroot ):
res [ ' results ' ] . append ( ' %s is not installed ' % pkg )
continue
@ -791,7 +808,7 @@ def remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
for pkg in pkgs :
if not pkg . startswith ( ' @ ' ) : # 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 ):
if not is_installed ( module , repoq , pkg , conf_file , en_repos = en_repos , dis_repos = dis_repos ,installroot = installroot ):
res [ ' changed ' ] = True
else :
module . fail_json ( * * res )
@ -801,7 +818,7 @@ def remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
return res
def latest ( module , items , repoq , yum_basecmd , conf_file , en_repos , dis_repos ):
def latest ( module , items , repoq , yum_basecmd , conf_file , en_repos , dis_repos , installroot = ' / ' ):
res = { }
res [ ' results ' ] = [ ]
@ -859,11 +876,11 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
continue
# dep/pkgname - find it
else :
if is_installed ( module , repoq , spec , conf_file , en_repos = en_repos , dis_repos = dis_repos ):
if is_installed ( module , repoq , spec , conf_file , en_repos = en_repos , dis_repos = dis_repos , installroot = installroot ):
pkgs [ ' update ' ] . append ( spec )
else :
pkgs [ ' install ' ] . append ( spec )
pkglist = what_provides ( module , repoq , spec , conf_file , en_repos = en_repos , dis_repos = dis_repos )
pkglist = what_provides ( module , repoq , spec , conf_file , en_repos = en_repos , dis_repos = dis_repos , installroot = installroot )
# FIXME..? may not be desirable to throw an exception here if a single package is missing
if not pkglist :
res [ ' msg ' ] + = " No package matching ' %s ' found available, installed or updated " % spec
@ -873,7 +890,7 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
nothing_to_do = True
for this in pkglist :
if spec in pkgs [ ' install ' ] and is_available ( module , repoq , this , conf_file , en_repos = en_repos , dis_repos = dis_repos ):
if spec in pkgs [ ' install ' ] and is_available ( module , repoq , this , conf_file , en_repos = en_repos , dis_repos = dis_repos , installroot = installroot ):
nothing_to_do = False
break
@ -960,7 +977,7 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
return res
def ensure ( module , state , pkgs , conf_file , enablerepo , disablerepo ,
disable_gpg_check , exclude , repoq ):
disable_gpg_check , exclude , repoq , installroot = ' / ' ):
# fedora will redirect yum to dnf, which has incompatibilities
# with how this module expects yum to operate. If yum-deprecated
@ -993,12 +1010,19 @@ def ensure(module, state, pkgs, conf_file, enablerepo, disablerepo,
e_cmd = [ ' --exclude= %s ' % exclude ]
yum_basecmd . extend ( e_cmd )
if installroot != ' / ' :
# do not setup installroot by default, because of error
# CRITICAL:yum.cli:Config Error: Error accessing file for config file:////etc/yum.conf
# in old yum version (like in CentOS 6.6)
e_cmd = [ ' --installroot= %s ' % installroot ]
yum_basecmd . extend ( e_cmd )
if state in [ ' installed ' , ' present ' , ' latest ' ] :
if module . params . get ( ' update_cache ' ) :
module . run_command ( yum_basecmd + [ ' makecache ' ] )
my = yum_base ( conf_file )
my = yum_base ( conf_file , installroot )
try :
if disablerepo :
my . repos . disableRepo ( disablerepo )
@ -1021,13 +1045,13 @@ def ensure(module, state, pkgs, conf_file, enablerepo, disablerepo,
if state in [ ' installed ' , ' present ' ] :
if disable_gpg_check :
yum_basecmd . append ( ' --nogpgcheck ' )
res = install ( module , pkgs , repoq , yum_basecmd , conf_file , en_repos , dis_repos )
res = install ( module , pkgs , repoq , yum_basecmd , conf_file , en_repos , dis_repos , installroot = installroot )
elif state in [ ' removed ' , ' absent ' ] :
res = remove ( module , pkgs , repoq , yum_basecmd , conf_file , en_repos , dis_repos )
res = remove ( module , pkgs , repoq , yum_basecmd , conf_file , en_repos , dis_repos , installroot = installroot )
elif state == ' latest ' :
if disable_gpg_check :
yum_basecmd . append ( ' --nogpgcheck ' )
res = latest ( module , pkgs , repoq , yum_basecmd , conf_file , en_repos , dis_repos )
res = latest ( module , pkgs , repoq , yum_basecmd , conf_file , en_repos , dis_repos , installroot = installroot )
else :
# should be caught by AnsibleModule argument_spec
module . fail_json ( msg = " we should never get here unless this all "
@ -1062,6 +1086,7 @@ def main():
disable_gpg_check = dict ( required = False , default = " no " , type = ' bool ' ) ,
update_cache = dict ( required = False , default = " no " , type = ' bool ' ) ,
validate_certs = dict ( required = False , default = " yes " , type = ' bool ' ) ,
installroot = dict ( required = False , default = " / " , type = ' str ' ) ,
# this should not be needed, but exists as a failsafe
install_repoquery = dict ( required = False , default = " yes " , type = ' bool ' ) ,
) ,
@ -1076,14 +1101,14 @@ def main():
repoquerybin = ensure_yum_utils ( module )
if not repoquerybin :
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 , repoquerybin , params [ ' conf_file ' ] , params [ ' list ' ] ))
results = dict ( results = list_stuff ( module , repoquerybin , params [ ' conf_file ' ] , params [ ' list ' ] , params [ ' installroot ' ] ))
else :
# If rhn-plugin is installed and no rhn-certificate is available on
# the system then users will see an error message using the yum API.
# Use repoquery in those cases.
my = yum_base ( params [ ' conf_file ' ] )
my = yum_base ( params [ ' conf_file ' ] , params [ ' installroot ' ] )
# A sideeffect of accessing conf is that the configuration is
# loaded and plugins are discovered
my . conf
@ -1105,7 +1130,8 @@ def main():
disablerepo = params . get ( ' disablerepo ' , ' ' )
disable_gpg_check = params [ ' disable_gpg_check ' ]
results = ensure ( module , state , pkg , params [ ' conf_file ' ] , enablerepo ,
disablerepo , disable_gpg_check , exclude , repoquery )
disablerepo , disable_gpg_check , exclude , repoquery ,
params [ ' installroot ' ] )
if repoquery :
results [ ' msg ' ] = ' %s %s ' % ( results . get ( ' msg ' , ' ' ) ,
' Warning: Due to potential bad behaviour with rhnplugin and certificates, used slower repoquery calls instead of Yum API. ' )