2012-02-23 23:19:06 +01:00
#!/usr/bin/python
2012-08-03 03:20:43 +02:00
# -*- coding: utf-8 -*-
2012-02-23 23:19:06 +01:00
2012-02-29 01:08:09 +01:00
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>, and others
2016-08-24 17:27:36 +02:00
# (c) 2016, Toshio Kuratomi <tkuratomi@ansible.com>
2012-02-29 01:08:09 +01:00
#
# 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/>.
2012-02-24 10:35:51 +01:00
2012-09-28 21:55:49 +02:00
DOCUMENTATION = '''
- - -
module : command
short_description : Executes a command on a remote node
2015-07-30 23:04:41 +02:00
version_added : historical
2012-09-28 21:55:49 +02:00
description :
2012-11-21 18:49:30 +01:00
- The M ( command ) module takes the command name followed by a list of space - delimited arguments .
2012-09-28 21:55:49 +02:00
- The given command will be executed on all selected nodes . It will not be
processed through the shell , so variables like C ( $ HOME ) and operations
2016-09-02 21:26:33 +02:00
like C ( " < " ) , C ( " > " ) , C ( " | " ) , C ( " ; " ) and C ( " & " ) will not work ( use the M ( shell )
2014-01-27 21:56:52 +01:00
module if you need these features ) .
2012-09-28 21:55:49 +02:00
options :
free_form :
description :
2014-04-03 23:34:11 +02:00
- the command module takes a free form command to run . There is no parameter actually named ' free form ' .
See the examples !
2012-09-28 21:55:49 +02:00
required : true
default : null
creates :
description :
2015-12-12 23:16:47 +01:00
- a filename or ( since 2.0 ) glob pattern , when it already exists , this step will B ( not ) be run .
2012-09-28 21:55:49 +02:00
required : no
default : null
2012-10-03 04:32:17 +02:00
removes :
description :
2015-12-12 23:16:47 +01:00
- a filename or ( since 2.0 ) glob pattern , when it does not exist , this step will B ( not ) be run .
2012-10-03 04:32:17 +02:00
version_added : " 0.8 "
required : no
default : null
2012-09-28 21:55:49 +02:00
chdir :
description :
- cd into this directory before running the command
2013-11-28 03:23:03 +01:00
version_added : " 0.6 "
2012-09-28 21:55:49 +02:00
required : false
default : null
2012-11-08 14:56:16 +01:00
executable :
description :
- change the shell used to execute the command . Should be an absolute path to the executable .
required : false
default : null
version_added : " 0.9 "
2013-12-02 10:54:15 +01:00
warn :
2014-08-22 21:33:57 +02:00
version_added : " 1.8 "
default : yes
2013-12-02 10:54:15 +01:00
description :
2014-08-22 22:12:32 +02:00
- if command warnings are on in ansible . cfg , do not warn about this particular line if set to no / false .
2013-12-02 10:54:15 +01:00
required : false
2012-09-28 21:55:49 +02:00
notes :
- If you want to run a command through the shell ( say you are using C ( < ) ,
C ( > ) , C ( | ) , etc ) , you actually want the M ( shell ) module instead . The
M ( command ) module is much more secure as it ' s not affected by the user ' s
environment .
2013-06-14 11:53:43 +02:00
- " C(creates), C(removes), and C(chdir) can be specified after the command. For instance, if you only want to run a command if a certain file does not exist, use this. "
2015-06-15 21:53:30 +02:00
author :
- Ansible Core Team
- Michael DeHaan
2012-09-28 21:55:49 +02:00
'''
2013-06-14 11:53:43 +02:00
EXAMPLES = '''
2014-06-24 13:45:49 +02:00
# Example from Ansible Playbooks.
2013-06-14 11:53:43 +02:00
- command : / sbin / shutdown - t now
2014-06-24 13:45:49 +02:00
# Run the command if the specified file does not exist.
2013-06-14 11:53:43 +02:00
- command : / usr / bin / make_database . sh arg1 arg2 creates = / path / to / database
2014-06-24 13:45:49 +02:00
# You can also use the 'args' form to provide the options. This command
# will change the working directory to somedir/ and will only run when
# /path/to/database doesn't exist.
- command : / usr / bin / make_database . sh arg1 arg2
args :
chdir : somedir /
creates : / path / to / database
2013-06-14 11:53:43 +02:00
'''
2016-08-24 17:27:36 +02:00
import datetime
import glob
import re
import shlex
import os
from ansible . module_utils . basic import AnsibleModule
from ansible . module_utils . six import b
2013-12-02 10:54:15 +01:00
def check_command ( commandline ) :
arguments = { ' chown ' : ' owner ' , ' chmod ' : ' mode ' , ' chgrp ' : ' group ' ,
' ln ' : ' state=link ' , ' mkdir ' : ' state=directory ' ,
' rmdir ' : ' state=absent ' , ' rm ' : ' state=absent ' , ' touch ' : ' state=touch ' }
2016-07-21 19:57:41 +02:00
commands = { ' hg ' : ' hg ' , ' curl ' : ' get_url or uri ' , ' wget ' : ' get_url or uri ' ,
2013-12-02 10:54:15 +01:00
' svn ' : ' subversion ' , ' service ' : ' service ' ,
2016-05-01 11:02:57 +02:00
' mount ' : ' mount ' , ' rpm ' : ' yum, dnf or zypper ' , ' yum ' : ' yum ' , ' apt-get ' : ' apt ' ,
2013-12-02 10:54:15 +01:00
' tar ' : ' unarchive ' , ' unzip ' : ' unarchive ' , ' sed ' : ' template or lineinfile ' ,
2016-07-21 19:57:41 +02:00
' dnf ' : ' dnf ' , ' zypper ' : ' zypper ' }
2015-07-27 17:02:24 +02:00
become = [ ' sudo ' , ' su ' , ' pbrun ' , ' pfexec ' , ' runas ' ]
2013-12-02 10:54:15 +01:00
warnings = list ( )
command = os . path . basename ( commandline . split ( ) [ 0 ] )
if command in arguments :
warnings . append ( " Consider using file module with %s rather than running %s " % ( arguments [ command ] , command ) )
if command in commands :
warnings . append ( " Consider using %s module rather than running %s " % ( commands [ command ] , command ) )
2015-07-27 17:02:24 +02:00
if command in become :
warnings . append ( " Consider using ' become ' , ' become_method ' , and ' become_user ' rather than running %s " % ( command , ) )
2013-12-02 10:54:15 +01:00
return warnings
2014-07-22 03:40:58 +02:00
2012-07-25 00:52:52 +02:00
def main ( ) :
# the command module is the one ansible module that does not take key=value args
# hence don't copy this one if you are looking to build others!
2014-11-19 22:54:47 +01:00
module = AnsibleModule (
argument_spec = dict (
_raw_params = dict ( ) ,
_uses_shell = dict ( type = ' bool ' , default = False ) ,
2016-08-24 17:27:36 +02:00
chdir = dict ( type = ' path ' ) ,
2014-11-19 22:54:47 +01:00
executable = dict ( ) ,
2016-08-24 17:27:36 +02:00
creates = dict ( type = ' path ' ) ,
removes = dict ( type = ' path ' ) ,
2014-11-19 22:54:47 +01:00
warn = dict ( type = ' bool ' , default = True ) ,
)
)
2012-07-25 00:52:52 +02:00
2014-11-19 22:54:47 +01:00
shell = module . params [ ' _uses_shell ' ]
2012-07-30 17:39:45 +02:00
chdir = module . params [ ' chdir ' ]
2012-11-08 14:56:16 +01:00
executable = module . params [ ' executable ' ]
2014-11-19 22:54:47 +01:00
args = module . params [ ' _raw_params ' ]
2013-02-28 23:38:52 +01:00
creates = module . params [ ' creates ' ]
removes = module . params [ ' removes ' ]
2014-10-08 13:30:20 +02:00
warn = module . params [ ' warn ' ]
2012-07-25 00:52:52 +02:00
2012-08-17 03:40:52 +02:00
if args . strip ( ) == ' ' :
2012-10-30 10:36:11 +01:00
module . fail_json ( rc = 256 , msg = " no command given " )
2012-08-14 02:17:07 +02:00
2012-07-30 17:39:45 +02:00
if chdir :
2016-08-24 17:27:36 +02:00
chdir = os . path . abspath ( chdir )
2013-05-29 17:05:11 +02:00
os . chdir ( chdir )
2012-07-30 17:39:45 +02:00
2013-02-28 23:38:52 +01:00
if creates :
# do not run the command if the line contains creates=filename
# and the filename already exists. This allows idempotence
# of command executions.
2016-08-24 17:27:36 +02:00
if glob . glob ( creates ) :
2013-02-28 23:38:52 +01:00
module . exit_json (
cmd = args ,
2016-08-24 17:27:36 +02:00
stdout = " skipped, since %s exists " % creates ,
2013-02-28 23:38:52 +01:00
changed = False ,
rc = 0
)
if removes :
# do not run the command if the line contains removes=filename
# and the filename does not exist. This allows idempotence
# of command executions.
2016-08-24 17:27:36 +02:00
if not glob . glob ( removes ) :
2013-02-28 23:38:52 +01:00
module . exit_json (
cmd = args ,
2016-08-24 17:27:36 +02:00
stdout = " skipped, since %s does not exist " % removes ,
2013-02-28 23:38:52 +01:00
changed = False ,
rc = 0
)
2013-12-02 10:54:15 +01:00
warnings = list ( )
if warn :
warnings = check_command ( args )
2012-07-25 00:52:52 +02:00
if not shell :
args = shlex . split ( args )
startd = datetime . datetime . now ( )
2014-03-10 22:11:24 +01:00
rc , out , err = module . run_command ( args , executable = executable , use_unsafe_shell = shell )
2012-07-25 00:52:52 +02:00
endd = datetime . datetime . now ( )
delta = endd - startd
if out is None :
2016-08-24 17:27:36 +02:00
out = b ( ' ' )
2012-07-25 00:52:52 +02:00
if err is None :
2016-08-24 17:27:36 +02:00
err = b ( ' ' )
2012-07-25 00:52:52 +02:00
module . exit_json (
2013-12-02 10:54:15 +01:00
cmd = args ,
2016-08-24 17:27:36 +02:00
stdout = out . rstrip ( b ( " \r \n " ) ) ,
stderr = err . rstrip ( b ( " \r \n " ) ) ,
2013-12-02 10:54:15 +01:00
rc = rc ,
start = str ( startd ) ,
end = str ( endd ) ,
delta = str ( delta ) ,
changed = True ,
warnings = warnings
2012-07-25 00:52:52 +02:00
)
2016-08-24 17:27:36 +02:00
if __name__ == ' __main__ ' :
main ( )