pyinfra-dev / pyinfra

pyinfra turns Python code into shell commands and runs them on your servers. Execute ad-hoc commands and write declarative operations. Target SSH servers, local machine and Docker containers. Fast and scales from one server to thousands.
https://pyinfra.com
MIT License
3.85k stars 374 forks source link

still able to get 'dateutil.parser._parser.ParserError: Unknown string format' #867

Closed drewp closed 1 year ago

drewp commented 2 years ago

Describe the bug

Despite #725 saying it's fixed, I got this today: dateutil.parser._parser.ParserError: Unknown string format: Sun Aug 7 20:37:59 America 2022

My config is old and weird, so this is surely my fault, but perhaps the error message can be better? If that's a hassle, just close the issue.

To Reproduce

  1. don't have tzdata installed on the target
  2. run the following

system.py, abridged:

 12                                                                                                                              
 13 def timezone():                                                                                                              
 14     files.link(path='/etc/localtime', target=f'/usr/share/zoneinfo/{TZ}')                                                    
 15     files.replace(path='/etc/timezone', text='.*', replace=TZ)                                                               
 16     apt.packages(update=True,                                                                                                
 17                 cache_time=86400,                                                                                            
 18                 packages=['tzdata'],                                                                                         
 19                 force=True,                                                                                                  
 20                 _env={                                                                                                       
 21                     'TZ': TZ,                                                                                                
 22                     'LANG': 'en_US.UTF-8',                                                                                   
 23                     'DEBIAN_FRONTEND': 'noninteractive'                                                                      
 24                 })                                                                                                           
 25                                                                          

Run:


🛁 bang(pts/3):/stor6/my/proj/infra# env/bin/pyinfra inventory.py system.py --limit bang -vv              
--> Loading config...
--> Loading inventory...

--> Connecting to hosts...
    [bang] Connected

--> Preparing operations...
    Loading: system.py
[bang] >>> sh -c 'cd /etc/ && for file in $(ls -pdL *-release | grep -v /); do echo "/etc/${file}"; cat "/etc/${file}"; echo ---; done'
    [bang] Loaded fact server.LinuxDistribution
[bang] >>> sh -c 'uname -n'
    [bang] Loaded fact server.Hostname
[bang] >>> sh -c 'which hostnamectl || true'
    [bang] Loaded fact server.Which (command=hostnamectl)
    [bang] noop: hostname is set
[bang] >>> sh -c '! (test -e /etc/localtime || test -L /etc/localtime ) || ( stat -c '"'"'user=%U group=%G mode=%A atime=%X mtime=%Y ctime=%Z size=%s %N'"'"' /etc/localtime 2> /dev/null || stat -f '"'"'user=%Su group=%Sg mode=%Sp atime=%a mtime=%m ctime=%c size=%z %N%SY'"'"' /etc/localtime )'
    [bang] Loaded fact files.Link (path=/etc/localtime)
    [bang] noop: link /etc/localtime already exists
[bang] >>> sh -c 'grep -e '"'"'.*'"'"' /etc/timezone 2> /dev/null || ( find /etc/timezone -type f > /dev/null && echo __pyinfra_exists_/etc/timezone || true )'
    [bang] Loaded fact files.FindInFile (interpolate_variables=False, path=/etc/timezone, pattern=.*)
[bang] >>> sh -c 'export "TZ=America/Los_Angeles" "LANG=en_US.UTF-8" "DEBIAN_FRONTEND=noninteractive" && ! (test -e /var/lib/apt/periodic/update-success-stamp || test -L /var/lib/apt/periodic/update-success-stamp ) || ( stat -c '"'"'user=%U group=%G mode=%A atime=%X mtime=%Y ctime=%Z size=%s %N'"'"' /var/lib/apt/periodic/update-success-stamp 2> /dev/null || stat -f '"'"'user=%Su group=%Sg mode=%Sp atime=%a mtime=%m ctime=%c size=%z %N%SY'"'"' /var/lib/apt/periodic/update-success-stamp )'
    [bang] Loaded fact files.File (path=/var/lib/apt/periodic/update-success-stamp)
[bang] >>> sh -c 'export "TZ=America/Los_Angeles" "LANG=en_US.UTF-8" "DEBIAN_FRONTEND=noninteractive" && LANG=C LC_TIME=en_US.UTF-8 date'
Traceback (most recent call last):
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra_cli/util.py", line 68, in exec_file
    exec(PYTHON_CODES[filename], data)
  File "system.py", line 66, in <module>
    timezone()
  File "system.py", line 16, in timezone
    apt.packages(update=True,
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/operation.py", line 316, in decorated_func
    commands = [  # convert any strings -> StringCommand's
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/operation.py", line 316, in <listcomp>
    commands = [  # convert any strings -> StringCommand's
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/operations/apt.py", line 443, in packages
    yield from _update(cache_time=cache_time)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/operations/apt.py", line 317, in update
    host_cache_time = host.get_fact(Date).replace(tzinfo=None) - timedelta(seconds=cache_time)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/host.py", line 234, in get_fact
    return get_host_fact(self.state, self, name_or_cls, args=args, kwargs=kwargs)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/facts.py", line 295, in get_host_fact
    return get_fact(state, host, cls, args=args, kwargs=kwargs, fact_hash=fact_hash)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/facts.py", line 134, in get_fact
    return _get_fact(
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/facts.py", line 244, in _get_fact
    data = fact.process(stdout)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/facts/server.py", line 127, in process
    return parse_date(output[0])
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/dateutil/parser/_parser.py", line 1368, in parse
    return DEFAULTPARSER.parse(timestr, **kwargs)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/dateutil/parser/_parser.py", line 643, in parse
    raise ParserError("Unknown string format: %s", timestr)
dateutil.parser._parser.ParserError: Unknown string format: Sun Aug  7 20:43:41 America 2022

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "src/gevent/greenlet.py", line 906, in gevent._gevent_cgreenlet.Greenlet.run
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra_cli/util.py", line 232, in load_file
    exec_file(filename)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra_cli/util.py", line 72, in exec_file
    raise UnexpectedExternalError(e, filename)
pyinfra_cli.exceptions.UnexpectedExternalError: <unprintable UnexpectedExternalError object>
2022-08-07T20:43:41Z <Greenlet at 0x7f8a6eba3ac0: load_file(Host(bang))> failed with UnexpectedExternalError

--> An unexpected exception occurred in: system.py:

  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra_cli/util.py", line 68, in exec_file
    exec(PYTHON_CODES[filename], data)
  File "system.py", line 66, in <module>
    timezone()
  File "system.py", line 16, in timezone
    apt.packages(update=True,
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/operation.py", line 316, in decorated_func
    commands = [  # convert any strings -> StringCommand's
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/operation.py", line 316, in <listcomp>
    commands = [  # convert any strings -> StringCommand's
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/operations/apt.py", line 443, in packages
    yield from _update(cache_time=cache_time)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/operations/apt.py", line 317, in update
    host_cache_time = host.get_fact(Date).replace(tzinfo=None) - timedelta(seconds=cache_time)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/host.py", line 234, in get_fact
    return get_host_fact(self.state, self, name_or_cls, args=args, kwargs=kwargs)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/facts.py", line 295, in get_host_fact
    return get_fact(state, host, cls, args=args, kwargs=kwargs, fact_hash=fact_hash)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/facts.py", line 134, in get_fact
    return _get_fact(
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/api/facts.py", line 244, in _get_fact
    data = fact.process(stdout)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/pyinfra/facts/server.py", line 127, in process
    return parse_date(output[0])
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/dateutil/parser/_parser.py", line 1368, in parse
    return DEFAULTPARSER.parse(timestr, **kwargs)
  File "/stor6/my/proj/infra/env/lib/python3.10/site-packages/dateutil/parser/_parser.py", line 643, in parse
    raise ParserError("Unknown string format: %s", timestr)
dateutil.parser._parser.ParserError: Unknown string format: Sun Aug  7 20:43:41 America 2022

Expected behavior

A more actionable error message :)

Fizzadar commented 2 years ago

100% agree this error message is rubbish!

Fizzadar commented 1 year ago

OK this should now properly work everywhere in v2.5 by always using ISO format (https://github.com/Fizzadar/pyinfra/commit/3e0c2b9bb9e5621d473d094422c20c644a6f727f).