saltstack / saltstack/salt

[BUG] "Invalid IPv6 URL" when providing an invalid state name to state.apply

Open
#59,185 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug severity-medium ZD
Dominant language
Python
Stars
15.7k
Forks
5.6k
Avg merge
2d 44m
Merged PRs (30d)
80

Description

Description

When providing certain bad arguments to state.apply, the execution will fail with a ValueError and nothing easily actionable by the user. E.g.:

salt-call state.apply '\["some.state"\]'

This will raise an exception:

ValueError: Invalid IPv6 URL

Although this seems a bit contrived, it's easier to stumble on when using salt-api where it can be easy to lose track of the right magic required to supply the arg value, e.g.:

 curl -sSk https://localhost:8000/ -H 'Accept: application/x-yaml' ... -d fun='state.sls' -d arg='["some.state"]'

Setup

As above.

Steps to Reproduce the behavior

As above. Debug logs below. I added one log by changing https://github.com/saltstack/salt/blob/da6819735ce055f16e326472cb1768faece72ad6/salt/fileclient.py#L478 to:

        try: 
            url_data = urlparse(url) 
        except ValueError: 
            log.debug("URL was: %s", url) 
            raise
[DEBUG   ] URL was: salt://\["some/state"\].sls
full debug log
[DEBUG   ] Reading configuration from /etc/salt/minion
[DEBUG   ] Including configuration from '/etc/salt/minion.d/_schedule.conf'
[DEBUG   ] Reading configuration from /etc/salt/minion.d/_schedule.conf
[DEBUG   ] Configuration file path: /etc/salt/minion
[WARNING ] Insecure logging configuration detected! Sensitive data may be logged.
[DEBUG   ] Grains refresh requested. Refreshing grains.
[DEBUG   ] Reading configuration from /etc/salt/minion
[DEBUG   ] Including configuration from '/etc/salt/minion.d/_schedule.conf'
[DEBUG   ] Reading configuration from /etc/salt/minion.d/_schedule.conf
[DEBUG   ] Elapsed time getting FQDNs: 0.008494853973388672 seconds
[DEBUG   ] LazyLoaded zfs.is_supported
[DEBUG   ] Connecting to master. Attempt 1 of 1
[DEBUG   ] "master1" Not an IP address? Assuming it is a hostname.
[DEBUG   ] Master URI: tcp://192.168.144.2:4506
[DEBUG   ] Initializing new AsyncAuth for ('/etc/salt/pki/minion', 'master1', 'tcp://192.168.144.2:4506')
[DEBUG   ] Generated random reconnect delay between '1000ms' and '11000ms' (10132)
[DEBUG   ] Setting zmq_reconnect_ivl to '10132ms'
[DEBUG   ] Setting zmq_reconnect_ivl_max to '11000ms'
[DEBUG   ] Initializing new AsyncZeroMQReqChannel for ('/etc/salt/pki/minion', 'master1', 'tcp://192.168.144.2:4506', 'clear')
[DEBUG   ] Connecting the Minion to the Master URI (for the return server): tcp://192.168.144.2:4506
[DEBUG   ] Trying to connect to: tcp://192.168.144.2:4506
[DEBUG   ] salt.crypt.get_rsa_pub_key: Loading public key
[DEBUG   ] Decrypting the current master AES key
[DEBUG   ] salt.crypt.get_rsa_key: Loading private key
[DEBUG   ] salt.crypt._get_key_with_evict: Loading private key
[DEBUG   ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[DEBUG   ] salt.crypt.get_rsa_pub_key: Loading public key
[DEBUG   ] Closing AsyncZeroMQReqChannel instance
[DEBUG   ] Connecting the Minion to the Master publish port, using the URI: tcp://192.168.144.2:4505
[DEBUG   ] salt.crypt.get_rsa_key: Loading private key
[DEBUG   ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[DEBUG   ] Determining pillar cache
[DEBUG   ] Initializing new AsyncZeroMQReqChannel for ('/etc/salt/pki/minion', 'master1', 'tcp://192.168.144.2:4506', 'aes')
[DEBUG   ] Initializing new AsyncAuth for ('/etc/salt/pki/minion', 'master1', 'tcp://192.168.144.2:4506')
[DEBUG   ] Connecting the Minion to the Master URI (for the return server): tcp://192.168.144.2:4506
[DEBUG   ] Trying to connect to: tcp://192.168.144.2:4506
[DEBUG   ] salt.crypt.get_rsa_key: Loading private key
[DEBUG   ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[DEBUG   ] Closing AsyncZeroMQReqChannel instance
[DEBUG   ] LazyLoaded jinja.render
[DEBUG   ] LazyLoaded yaml.render
[DEBUG   ] LazyLoaded state.apply
[DEBUG   ] LazyLoaded direct_call.execute
[DEBUG   ] LazyLoaded saltutil.is_running
[DEBUG   ] LazyLoaded grains.get
[DEBUG   ] LazyLoaded config.get
[DEBUG   ] Initializing new AsyncZeroMQReqChannel for ('/etc/salt/pki/minion', 'master1', 'tcp://192.168.144.2:4506', 'aes')
[DEBUG   ] Initializing new AsyncAuth for ('/etc/salt/pki/minion', 'master1', 'tcp://192.168.144.2:4506')
[DEBUG   ] Connecting the Minion to the Master URI (for the return server): tcp://192.168.144.2:4506
[DEBUG   ] Trying to connect to: tcp://192.168.144.2:4506
[DEBUG   ] Gathering pillar data for state run
[DEBUG   ] Finished gathering pillar data for state run
[INFO    ] Loading fresh modules for state activity
[DEBUG   ] LazyLoaded jinja.render
[DEBUG   ] LazyLoaded yaml.render
[DEBUG   ] URL was: salt://\["some/state"\].sls
[DEBUG   ] Closing AsyncZeroMQReqChannel instance
[ERROR   ] An un-handled exception was caught by salt's global exception handler:
ValueError: Invalid IPv6 URL
Traceback (most recent call last):
  File "/usr/bin/salt-call", line 11, in <module>
    load_entry_point('salt==3002.2', 'console_scripts', 'salt-call')()
  File "/usr/lib/python3/dist-packages/salt/scripts.py", line 449, in salt_call
    client.run()
  File "/usr/lib/python3/dist-packages/salt/cli/call.py", line 58, in run
    caller.run()
  File "/usr/lib/python3/dist-packages/salt/cli/caller.py", line 112, in run
    ret = self.call()
  File "/usr/lib/python3/dist-packages/salt/cli/caller.py", line 219, in call
    ret["return"] = self.minion.executors[fname](
  File "/usr/lib/python3/dist-packages/salt/executors/direct_call.py", line 12, in execute
    return func(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/salt/modules/state.py", line 800, in apply_
    return sls(mods, **kwargs)
  File "/usr/lib/python3/dist-packages/salt/modules/state.py", line 1386, in sls
    high_, errors = st_.render_highstate({opts["saltenv"]: mods})
  File "/usr/lib/python3/dist-packages/salt/state.py", line 4300, in render_highstate
    state, errors = self.render_state(
  File "/usr/lib/python3/dist-packages/salt/state.py", line 3942, in render_state
    state_data = self.client.get_state(sls, saltenv)
  File "/usr/lib/python3/dist-packages/salt/fileclient.py", line 399, in get_state
    dest = self.cache_file(path, saltenv, cachedir=cachedir)
  File "/usr/lib/python3/dist-packages/salt/fileclient.py", line 186, in cache_file
    return self.get_url(
  File "/usr/lib/python3/dist-packages/salt/fileclient.py", line 479, in get_url
    url_data = urlparse(url)
  File "/usr/lib/python3.8/urllib/parse.py", line 373, in urlparse
    splitresult = urlsplit(url, scheme, allow_fragments)
  File "/usr/lib/python3.8/urllib/parse.py", line 464, in urlsplit
    raise ValueError("Invalid IPv6 URL")
ValueError: Invalid IPv6 URL
Traceback (most recent call last):
  File "/usr/bin/salt-call", line 11, in <module>
    load_entry_point('salt==3002.2', 'console_scripts', 'salt-call')()
  File "/usr/lib/python3/dist-packages/salt/scripts.py", line 449, in salt_call
    client.run()
  File "/usr/lib/python3/dist-packages/salt/cli/call.py", line 58, in run
    caller.run()
  File "/usr/lib/python3/dist-packages/salt/cli/caller.py", line 112, in run
    ret = self.call()
  File "/usr/lib/python3/dist-packages/salt/cli/caller.py", line 219, in call
    ret["return"] = self.minion.executors[fname](
  File "/usr/lib/python3/dist-packages/salt/executors/direct_call.py", line 12, in execute
    return func(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/salt/modules/state.py", line 800, in apply_
    return sls(mods, **kwargs)
  File "/usr/lib/python3/dist-packages/salt/modules/state.py", line 1386, in sls
    high_, errors = st_.render_highstate({opts["saltenv"]: mods})
  File "/usr/lib/python3/dist-packages/salt/state.py", line 4300, in render_highstate
    state, errors = self.render_state(
  File "/usr/lib/python3/dist-packages/salt/state.py", line 3942, in render_state
    state_data = self.client.get_state(sls, saltenv)
  File "/usr/lib/python3/dist-packages/salt/fileclient.py", line 399, in get_state
    dest = self.cache_file(path, saltenv, cachedir=cachedir)
  File "/usr/lib/python3/dist-packages/salt/fileclient.py", line 186, in cache_file
    return self.get_url(
  File "/usr/lib/python3/dist-packages/salt/fileclient.py", line 479, in get_url
    url_data = urlparse(url)
  File "/usr/lib/python3.8/urllib/parse.py", line 373, in urlparse
    splitresult = urlsplit(url, scheme, allow_fragments)
  File "/usr/lib/python3.8/urllib/parse.py", line 464, in urlsplit
    raise ValueError("Invalid IPv6 URL")
ValueError: Invalid IPv6 URL

Expected behavior

More informative errors and/or logs.

Versions Report

salt --versions-report
Salt Version:
          Salt: 3002.2
 
Dependency Versions:
          cffi: 1.14.4
      cherrypy: unknown
      dateutil: 2.7.3
     docker-py: Not Installed
         gitdb: 2.0.6
     gitpython: 3.0.7
        Jinja2: 2.10.1
       libgit2: Not Installed
      M2Crypto: Not Installed
          Mako: Not Installed
       msgpack: 0.6.2
  msgpack-pure: Not Installed
  mysql-python: Not Installed
     pycparser: 2.20
      pycrypto: 2.6.1
  pycryptodome: 3.6.1
        pygit2: Not Installed
        Python: 3.8.5 (default, Jul 28 2020, 12:59:40)
  python-gnupg: 0.4.5
        PyYAML: 5.3.1
         PyZMQ: 18.1.1
         smmap: 2.0.5
       timelib: Not Installed
       Tornado: 4.5.3
           ZMQ: 4.3.2
 
System Versions:
          dist: ubuntu 20.04 focal
        locale: utf-8
       machine: x86_64
       release: 5.4.0-54-generic
        system: Linux
       version: Ubuntu 20.04 focal

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in salt/fileclient.py at the urlparse call around line 478 and trace how the invalid state name reaches get_url from salt/modules/state.py. Reproduce the salt-call state.apply example, then make the resulting error or logs actionable and verify the behavior with the relevant existing fileclient or state tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devops, infrastructure
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.