2017-03-02 17:34:23 +03:00
#!/usr/bin/python
2017-05-11 19:26:36 +03:00
# coding: utf-8 -*-
2017-03-02 17:34:23 +03:00
# (c) 2017, Wayne Witzel III <wayne@riotousliving.com>
Remove wildcard imports
Made the following changes:
* Removed wildcard imports
* Replaced long form of GPL header with short form
* Removed get_exception usage
* Added from __future__ boilerplate
* Adjust division operator to // where necessary
For the following files:
* web_infrastructure modules
* system modules
* linode, lxc, lxd, atomic, cloudscale, dimensiondata, ovh, packet,
profitbricks, pubnub, smartos, softlayer, univention modules
* compat dirs (disabled as its used intentionally)
2017-07-28 08:55:24 +03:00
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import , division , print_function
__metaclass__ = type
2017-03-02 17:34:23 +03:00
2017-08-16 06:16:38 +03:00
ANSIBLE_METADATA = { ' metadata_version ' : ' 1.1 ' ,
2017-03-14 19:07:22 +03:00
' status ' : [ ' preview ' ] ,
' supported_by ' : ' community ' }
2017-03-02 17:34:23 +03:00
DOCUMENTATION = '''
- - -
module : tower_job_wait
version_added : " 2.3 "
2017-03-09 19:20:25 +03:00
author : " Wayne Witzel III (@wwitzel3) "
2017-03-02 17:34:23 +03:00
short_description : Wait for Ansible Tower job to finish .
description :
- Wait for Ansible Tower job to finish and report success or failure . See
U ( https : / / www . ansible . com / tower ) for an overview .
options :
job_id :
description :
- ID of the job to monitor .
required : True
2019-09-30 23:01:44 +03:00
type : int
2017-03-02 17:34:23 +03:00
min_interval :
description :
- Minimum interval in seconds , to request an update from Tower .
default : 1
2019-09-30 23:01:44 +03:00
type : float
2017-03-02 17:34:23 +03:00
max_interval :
description :
- Maximum interval in seconds , to request an update from Tower .
default : 30
2019-09-30 23:01:44 +03:00
type : float
2017-03-02 17:34:23 +03:00
timeout :
description :
- Maximum time in seconds to wait for a job to finish .
2019-09-30 23:01:44 +03:00
type : int
2020-03-25 21:06:32 +03:00
tower_oauthtoken :
description :
- The Tower OAuth token to use .
required : False
type : str
version_added : " 3.7 "
2019-09-18 15:43:36 +03:00
extends_documentation_fragment : awx . awx . auth
2017-03-02 17:34:23 +03:00
'''
EXAMPLES = '''
- name : Launch a job
tower_job_launch :
job_template : " My Job Template "
register : job
2018-08-09 02:10:26 +03:00
2017-03-02 17:34:23 +03:00
- name : Wait for job max 120 s
tower_job_wait :
2019-04-15 23:18:11 +03:00
job_id : " {{ job.id }} "
2017-03-02 17:34:23 +03:00
timeout : 120
'''
RETURN = '''
id :
description : job id that is being waited on
returned : success
type : int
sample : 99
elapsed :
description : total time in seconds the job took to run
returned : success
type : float
sample : 10.879
started :
description : timestamp of when the job started running
returned : success
2018-12-19 00:25:30 +03:00
type : str
2017-04-26 17:56:13 +03:00
sample : " 2017-03-01T17:03:53.200234Z "
2017-03-02 17:34:23 +03:00
finished :
description : timestamp of when the job finished running
returned : success
2018-12-19 00:25:30 +03:00
type : str
2017-04-26 17:56:13 +03:00
sample : " 2017-03-01T17:04:04.078782Z "
2017-03-02 17:34:23 +03:00
status :
description : current status of job
returned : success
2018-12-19 00:25:30 +03:00
type : str
2017-03-02 17:34:23 +03:00
sample : successful
'''
2020-03-25 21:06:32 +03:00
from . . module_utils . tower_api import TowerModule
import time
import itertools
2017-03-02 17:34:23 +03:00
2020-03-25 21:06:32 +03:00
def check_job ( module , job_url ) :
response = module . get_endpoint ( job_url )
if response [ ' status_code ' ] != 200 :
module . fail_json ( msg = " Unable to read job from Tower {0} : {1} " . format ( response [ ' status_code ' ] , module . extract_errors_from_response ( response ) ) )
# Since we were successful, extract the fields we want to return
for k in ( ' id ' , ' status ' , ' elapsed ' , ' started ' , ' finished ' ) :
module . json_output [ k ] = response [ ' json ' ] . get ( k )
2017-03-02 17:34:23 +03:00
2020-03-25 21:06:32 +03:00
# And finally return the payload
return response [ ' json ' ]
2017-03-02 17:34:23 +03:00
def main ( ) :
2020-03-25 21:06:32 +03:00
# Any additional arguments that are not fields of the item can be added here
2018-08-02 18:17:39 +03:00
argument_spec = dict (
2017-05-11 19:26:36 +03:00
job_id = dict ( type = ' int ' , required = True ) ,
timeout = dict ( type = ' int ' ) ,
min_interval = dict ( type = ' float ' , default = 1 ) ,
max_interval = dict ( type = ' float ' , default = 30 ) ,
2018-08-02 18:17:39 +03:00
)
2017-03-02 17:34:23 +03:00
2020-03-25 21:06:32 +03:00
# Create a module for ourselves
module = TowerModule ( argument_spec = argument_spec , supports_check_mode = True )
# Extract our parameters
job_id = module . params . get ( ' job_id ' )
timeout = module . params . get ( ' timeout ' )
min_interval = module . params . get ( ' min_interval ' )
max_interval = module . params . get ( ' max_interval ' )
# Attempt to look up job based on the provided id
job = module . get_one ( ' jobs ' , * * {
' data ' : {
' id ' : job_id ,
}
} )
if job is None :
module . fail_json ( msg = ' Unable to wait, on job {0} that ID does not exist in Tower. ' . format ( job_id ) )
job_url = job [ ' url ' ]
# This comes from tower_cli/models/base.py from the old tower-cli
dots = itertools . cycle ( [ 0 , 1 , 2 , 3 ] )
interval = min_interval
start = time . time ( )
# Poll the Ansible Tower instance for status, and print the status to the outfile (usually standard out).
result = check_job ( module , job_url )
last_poll = time . time ( )
timeout_check = 0
while not result [ ' finished ' ] :
# Sanity check: Have we officially timed out?
# The timeout check is incremented below, so this is checking to see if we were timed out as of
# the previous iteration. If we are timed out, abort.
if timeout and timeout_check - start > timeout :
module . json_output [ ' msg ' ] = " Monitoring aborted due to timeout "
module . fail_json ( * * module . json_output )
# If the outfile is a TTY, print the current status.
output = ' \r Current status: %s %s ' % ( result [ ' status ' ] , ' . ' * next ( dots ) )
# Put the process to sleep briefly.
time . sleep ( 0.2 )
# Sanity check: Have we reached our timeout?
# If we're about to time out, then we need to ensure that we do one last check.
#
# Note that the actual timeout will be performed at the start of the **next** iteration,
# so there's a chance for the job's completion to be noted first.
timeout_check = time . time ( )
if timeout and timeout_check - start > timeout :
last_poll - = interval
# If enough time has elapsed, ask the server for a new status.
#
# Note that this doesn't actually do a status check every single time; we want the "spinner" to
# spin even if we're not actively doing a check.
#
# So, what happens is that we are "counting down" (actually up) to the next time that we intend
# to do a check, and once that time hits, we do the status check as part of the normal cycle.
if time . time ( ) - last_poll > interval :
result = check_job ( module , job_url )
last_poll = time . time ( )
interval = min ( interval * 1.5 , max_interval )
# If the job has failed, we want to raise an Exception for that so we get a non-zero response.
if result [ ' failed ' ] :
module . json_output [ ' msg ' ] = ' Job with id {0} failed ' . format ( job_id )
module . fail_json ( * * module . json_output )
module . exit_json ( * * module . json_output )
2017-03-02 17:34:23 +03:00
if __name__ == ' __main__ ' :
main ( )