@ -4,6 +4,7 @@
"""
"""
Ansible module to manage symbolic link alternatives .
Ansible module to manage symbolic link alternatives .
( c ) 2014 , Gabe Mulley < gabe . mulley @gmail.com >
( c ) 2014 , Gabe Mulley < gabe . mulley @gmail.com >
( c ) 2015 , David Wittman < dwittman @gmail.com >
This file is part of Ansible
This file is part of Ansible
@ -26,7 +27,7 @@ DOCUMENTATION = '''
module : alternatives
module : alternatives
short_description : Manages alternative programs for common commands
short_description : Manages alternative programs for common commands
description :
description :
- Manages symbolic links using the ' update-alternatives ' tool provided on debian - like systems .
- Manages symbolic links using the ' update-alternatives ' tool
- Useful when multiple programs are installed but provide similar functionality ( e . g . different editors ) .
- Useful when multiple programs are installed but provide similar functionality ( e . g . different editors ) .
version_added : " 1.6 "
version_added : " 1.6 "
options :
options :
@ -41,6 +42,7 @@ options:
link :
link :
description :
description :
- The path to the symbolic link that should point to the real executable .
- The path to the symbolic link that should point to the real executable .
- This option is required on RHEL - based distributions
required : false
required : false
requirements : [ update - alternatives ]
requirements : [ update - alternatives ]
'''
'''
@ -55,12 +57,14 @@ EXAMPLES = '''
DEFAULT_LINK_PRIORITY = 50
DEFAULT_LINK_PRIORITY = 50
import re
def main ( ) :
def main ( ) :
module = AnsibleModule (
module = AnsibleModule (
argument_spec = dict (
argument_spec = dict (
name = dict ( required = True ) ,
name = dict ( required = True ) ,
path = dict ( required = True ) ,
path = dict ( required = True ) ,
link = dict ( required = False ) ,
link = dict ( required = False ) ,
) ,
) ,
supports_check_mode = True ,
supports_check_mode = True ,
@ -71,78 +75,55 @@ def main():
path = params [ ' path ' ]
path = params [ ' path ' ]
link = params [ ' link ' ]
link = params [ ' link ' ]
UPDATE_ALTERNATIVES = module . get_bin_path ( ' update-alternatives ' , True )
UPDATE_ALTERNATIVES = module . get_bin_path ( ' update-alternatives ' , True )
current_path = None
current_path = None
all_alternatives = [ ]
all_alternatives = [ ]
os_family = None
( rc , query_output , query_error ) = module . run_command (
# Run `update-alternatives --display <name>` to find existing alternatives
[ UPDATE_ALTERNATIVES , ' --query ' , name ]
( rc , display_output , _ ) = module . run_command (
[ UPDATE_ALTERNATIVES , ' --display ' , name ]
)
)
# Gather the current setting and all alternatives from the query output.
# Query output should look something like this on Debian systems:
# Name: java
# Link: /usr/bin/java
# Slaves:
# java.1.gz /usr/share/man/man1/java.1.gz
# Status: manual
# Best: /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java
# Value: /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java
# Alternative: /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java
# Priority: 1061
# Slaves:
# java.1.gz /usr/lib/jvm/java-6-openjdk-amd64/jre/man/man1/java.1.gz
# Alternative: /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java
# Priority: 1071
# Slaves:
# java.1.gz /usr/lib/jvm/java-7-openjdk-amd64/jre/man/man1/java.1.gz
if rc == 0 :
if rc == 0 :
os_family = " Debian "
# Alternatives already exist for this link group
for line in query_output . splitlines ( ) :
# Parse the output to determine the current path of the symlink and
split_line = line . split ( ' : ' )
# available alternatives
if len ( split_line ) == 2 :
current_path_regex = re . compile ( r ' ^ \ s*link currently points to (.*)$ ' ,
key = split_line [ 0 ]
re . MULTILINE )
value = split_line [ 1 ] . strip ( )
alternative_regex = re . compile ( r ' ^( \ /.*) \ s- \ spriority ' , re . MULTILINE )
if key == ' Value ' :
current_path = value
current_path = current_path_regex . search ( display_output ) . group ( 1 )
elif key == ' Alternative ' :
all_alternatives = alternative_regex . findall ( display_output )
all_alternatives . append ( value )
elif key == ' Link ' and not link :
if not link :
link = value
# Read the current symlink target from `update-alternatives --query`
elif rc == 2 :
# in case we need to install the new alternative before setting it.
os_family = " RedHat "
#
# This is the version of update-alternatives that is shipped with
# This is only compatible on Debian-based systems, as the other
# chkconfig on RedHat-based systems. Try again with the right options.
# alternatives don't have --query available
( rc , query_output , query_error ) = module . run_command (
rc , query_output , _ = module . run_command (
[ UPDATE_ALTERNATIVES , ' --list ' ]
[ UPDATE_ALTERNATIVES , ' --query ' , name ]
)
)
for line in query_output . splitlines ( ) :
if rc == 0 :
line_name , line_mode , line_path = line . strip ( ) . split ( " \t " )
for line in query_output . splitlines ( ) :
if line_name != name :
if line . startswith ( ' Link: ' ) :
continue
link = line . split ( ) [ 1 ]
current_path = line_path
break
break
if current_path != path :
if current_path != path :
if module . check_mode :
if module . check_mode :
module . exit_json ( changed = True , current_path = current_path )
module . exit_json ( changed = True , current_path = current_path )
try :
try :
# install the requested path if necessary
# install the requested path if necessary
# (unsupported on the RedHat version)
if path not in all_alternatives :
if path not in all_alternatives and os_family == " Debian " :
if not link :
if link :
module . fail_json ( msg = " Needed to install the alternative, but unable to do so as we are missing the link " )
module . run_command (
[ UPDATE_ALTERNATIVES , ' --install ' , link , name , path , str ( DEFAULT_LINK_PRIORITY ) ] ,
module . run_command (
check_rc = True
[ UPDATE_ALTERNATIVES , ' --install ' , link , name , path , str ( DEFAULT_LINK_PRIORITY ) ] ,
)
check_rc = True
else :
)
module . fail_json ( " Needed to install the alternative, but unable to do so, as we are missking the link " )
# select the requested path
# select the requested path
module . run_command (
module . run_command (
@ -151,7 +132,7 @@ def main():
)
)
module . exit_json ( changed = True )
module . exit_json ( changed = True )
except subprocess . CalledProcessError , cpe :
except subprocess . CalledProcessError as cpe :
module . fail_json ( msg = str ( dir ( cpe ) ) )
module . fail_json ( msg = str ( dir ( cpe ) ) )
else :
else :
module . exit_json ( changed = False )
module . exit_json ( changed = False )