Extending SaltStack
上QQ阅读APP看书,第一时间看更新

Troubleshooting execution modules

As with any programming, the more time you spend writing execution modules, the more likely you are to encounter issues. Let's take a moment to talk about how to troubleshoot and debug your code.

Using salt-call

The salt-call command has always been a valuable tool for testing and troubleshooting code. Without it, you would need to restart the salt-minion service each time you wanted to test new code; believe me, that gets old fast.

Because salt-call doesn't start up a service, it will always run the latest copy of the Salt code. It does do most of the things that the salt-minion service does: it loads grains, connects to the Master (unless told not to) to obtain pillar data, goes through the loader process to decide which modules to load, and then performs the requested command. Pretty much the only thing it doesn't do is keep running.

Using salt-call to issue a command is also the same as using the salt command, except that a target is not required (because the target is the Minion that salt-call is running on):

#salt '*' mysqltest.ping
#salt-call mysqltest.ping

You may notice that even though you're issuing salt-call commands on the same machine that will be performing the execution, it tends to run a little slower. There are two reasons for this. First of all, you are still basically starting up the salt-minion service each time, without actually keeping it running. That means that detecting grains, loading modules, and so on will have to happen each time.

To get a feel for how much time this really takes, try comparing execution times both with and without grain detection:

# time salt-call test.ping
local:
 True
real 0m3.257s
user 0m0.863s
sys 0m0.197s
# time salt-call --skip-grains test.ping
local:
 True
real 0m0.675s
user 0m0.507s
sys 0m0.080s

Of course, if you're testing a module that makes use of grains, this is not an acceptable strategy. The second thing that slows down commands is having to connect to the Master. This doesn't take nearly as much time as grain detection, but it does take a hit:

# time salt-call --local test.ping
local:
 True
real 0m2.820s
user 0m0.797s
sys 0m0.120s

The --local flag doesn't just tell salt-call not to talk to the Master. It actually tells salt-call to use itself as the Master (meaning, operate in local mode). If your module makes use of pillars or other resources on the Master, then you can just serve them locally instead.

Any configuration in the master configuration file that you need can be copied directly to the Minion file. If you're just using the defaults, you don't even need to do that: just copy the necessary files from the Master to the Minion:

# scp -r saltmaster:/srv/salt /srv
# scp -r saltmaster:/srv/pillar /srv

Once everything is in place, go ahead and fire up salt-call with the --local flag and get to troubleshooting.

<function> is not available

When I'm writing a new module, one of the first problems I have is getting the module to show up. Quite often this is because of obviously bad code, such as a typo. For instance, if we were to change our import from salt.utils to salt.util, our module would fail to load:

$ grep 'import salt' salt/modules/mysqltest.py
import salt.util
# salt-call --local mysqltest.ping
'mysqltest.ping' is not available.

In cases like this, we can find the problem by running salt-call in debug mode:

# salt-call --local -l debug mysqltest.ping
...
[DEBUG ] Failed to import module mysqltest:
Traceback (most recent call last):
 File "/usr/lib/python2.7/site-packages/salt/loader.py", line 1217, in _load_module
 ), fn_, fpath, desc)
 File "/usr/lib/python2.7/site-packages/salt/modules/mysqltest.py", line 4, in <module>
 import salt.util
ImportError: No module named util
...
'mysqltest.ping' is not available.

Another possibility is that there is a problem with the __virtual__() function. This is the one time I would recommend adding log messages to that function:

def __virtual__():
    '''
    Check dependencies, using both methods from the chapter
    '''
    log.debug('Checking for mysql command')
    if not salt.utils.which('mysql'):
        return False

    log.debug('Checking for libs')
    if HAS_LIBS:
        return __virtualname__

    return False

However, make sure you pull them out before you ever get into production, or you're going to have some very unhappy users sooner or later.

Tip

Downloading the example code

You can download the example code files for this book from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

You can download the code files by following these steps:

  • Log in or register to our website using your e-mail address and password.
  • Hover the mouse pointer on the SUPPORT tab at the top.
  • Click on Code Downloads & Errata.
  • Enter the name of the book in the Search box.
  • Select the book for which you're looking to download the code files.
  • Choose from the drop-down menu where you purchased this book from.
  • Click on Code Download.

Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:

  • WinRAR/7-Zip for Windows
  • Zipeg/iZip/UnRarX for Mac
  • 7-Zip/PeaZip for Linux