@ -4,13 +4,17 @@ from __future__ import absolute_import, print_function
import datetime
import datetime
import json
import json
import functools
import os
import os
import platform
import platform
import re
import re
import signal
import sys
import sys
import time
from lib . config import (
from lib . config import (
CommonConfig ,
CommonConfig ,
TestConfig ,
)
)
from lib . util import (
from lib . util import (
@ -34,6 +38,18 @@ from lib.docker_util import (
docker_version
docker_version
)
)
from lib . thread import (
WrappedThread ,
)
from lib . constants import (
TIMEOUT_PATH ,
)
from lib . test import (
TestTimeout ,
)
class EnvConfig ( CommonConfig ) :
class EnvConfig ( CommonConfig ) :
""" Configuration for the tools command. """
""" Configuration for the tools command. """
@ -43,14 +59,26 @@ class EnvConfig(CommonConfig):
"""
"""
super ( EnvConfig , self ) . __init__ ( args , ' env ' )
super ( EnvConfig , self ) . __init__ ( args , ' env ' )
self . show = args . show or not args . dump
self . show = args . show
self . dump = args . dump
self . dump = args . dump
self . timeout = args . timeout
def command_env ( args ) :
def command_env ( args ) :
"""
"""
: type args : EnvConfig
: type args : EnvConfig
"""
"""
show_dump_env ( args )
set_timeout ( args )
def show_dump_env ( args ) :
"""
: type args : EnvConfig
"""
if not args . show and not args . dump :
return
data = dict (
data = dict (
ansible = dict (
ansible = dict (
version = get_ansible_version ( args ) ,
version = get_ansible_version ( args ) ,
@ -84,6 +112,105 @@ def command_env(args):
results_fd . write ( json . dumps ( data , sort_keys = True ) )
results_fd . write ( json . dumps ( data , sort_keys = True ) )
def set_timeout ( args ) :
"""
: type args : EnvConfig
"""
if args . timeout is None :
return
if args . timeout :
deadline = ( datetime . datetime . utcnow ( ) + datetime . timedelta ( minutes = args . timeout ) ) . strftime ( ' % Y- % m- %d T % H: % M: % SZ ' )
display . info ( ' Setting a %d minute test timeout which will end at: %s ' % ( args . timeout , deadline ) , verbosity = 1 )
else :
deadline = None
display . info ( ' Clearing existing test timeout. ' , verbosity = 1 )
if args . explain :
return
if deadline :
data = dict (
duration = args . timeout ,
deadline = deadline ,
)
with open ( TIMEOUT_PATH , ' w ' ) as timeout_fd :
json . dump ( data , timeout_fd , indent = 4 , sort_keys = True )
elif os . path . exists ( TIMEOUT_PATH ) :
os . remove ( TIMEOUT_PATH )
def get_timeout ( ) :
"""
: rtype : dict [ str , any ] | None
"""
if not os . path . exists ( TIMEOUT_PATH ) :
return None
with open ( TIMEOUT_PATH , ' r ' ) as timeout_fd :
data = json . load ( timeout_fd )
data [ ' deadline ' ] = datetime . datetime . strptime ( data [ ' deadline ' ] , ' % Y- % m- %d T % H: % M: % SZ ' )
return data
def configure_timeout ( args ) :
"""
: type args : CommonConfig
"""
if isinstance ( args , TestConfig ) :
configure_test_timeout ( args ) # only tests are subject to the timeout
def configure_test_timeout ( args ) :
"""
: type args : TestConfig
"""
timeout = get_timeout ( )
if not timeout :
return
timeout_start = datetime . datetime . utcnow ( )
timeout_duration = timeout [ ' duration ' ]
timeout_deadline = timeout [ ' deadline ' ]
timeout_remaining = timeout_deadline - timeout_start
test_timeout = TestTimeout ( timeout_duration )
if timeout_remaining < = datetime . timedelta ( ) :
test_timeout . write ( args )
raise ApplicationError ( ' The %d minute test timeout expired %s ago at %s . ' % (
timeout_duration , timeout_remaining * - 1 , timeout_deadline ) )
display . info ( ' The %d minute test timeout expires in %s at %s . ' % (
timeout_duration , timeout_remaining , timeout_deadline ) , verbosity = 1 )
def timeout_handler ( _dummy1 , _dummy2 ) :
""" Runs when SIGUSR1 is received. """
test_timeout . write ( args )
raise ApplicationError ( ' Tests aborted after exceeding the %d minute time limit. ' % timeout_duration )
def timeout_waiter ( timeout_seconds ) :
"""
: type timeout_seconds : int
"""
time . sleep ( timeout_seconds )
os . kill ( os . getpid ( ) , signal . SIGUSR1 )
signal . signal ( signal . SIGUSR1 , timeout_handler )
instance = WrappedThread ( functools . partial ( timeout_waiter , timeout_remaining . seconds ) )
instance . daemon = True
instance . start ( )
def show_dict ( data , verbose , root_verbosity = 0 , path = None ) :
def show_dict ( data , verbose , root_verbosity = 0 , path = None ) :
"""
"""
: type data : dict [ str , any ]
: type data : dict [ str , any ]