kitchen-salt icon indicating copy to clipboard operation
kitchen-salt copied to clipboard

Support for mocking ext_pillars

Open NinjaSomething opened this issue 4 years ago • 3 comments

Hello,

I was wondering if there were any plans to support ext_pillars in kitchen-salt. I have a situation where I have an ext_pillar that is used as an input for another pillar. I haven't been able to find any documentation regarding if this kind of usage is supported or not. The closest I was able to find is PR16 which was closed.

What I want to do is use kitchen-salt to validate that a SLS pillar file has been written correctly and nothing was fat fingered. Errors in the pillar SLS file mean invalid inputs for the states. I think the way to do this is to allow simulated ext_pillars to be populated before the system pillars. This is similar to the how the_ext_pillar_first_ parameter on the salt master works.

If this is already supported, can someone please point me towards the documentation for this?

Summary of the logs: In the files below I have a wireguard-formula that has inputs being provided by the '../pillar/wireguard.sls' pillar. This pillar extracts data from an ext_pillar called wireguard_data. The real ext_pillar calls a database and retrieves the appropriate IP and keys. I already have a unit test for the real wireguard_data ext_pillar so I don't need this here. What I need from kitchen-salt is to be able to crate a mock ext_pillar with an SLS file that is fully populated and made available to subsequent pillars.

.kitchen.yml

<% @version = '3000.6' %>
driver:
  name: docker
  user_sudo: false
  privileged: true
  username: root
  forward:
    - 80

platforms:
  - name: ubuntu-18.04
    driver_config:
      run_command: /lib/systemd/systemd

suites:
  - name: salt-kitchen-test

provisioner:
  name: salt_solo
  sudo: false
  salt_install: bootstrap
  salt_bootstrap_options: -x python3 -P stable <%= @version %>
  log_level: debug
  is_file_root: true
  state_top_from_file: true
  require_chef: false
  dependencies:
    - name: wireguard
      repo: git
      source: git://github.com/energytoolbase/wireguard-formula
  state_copy_filter:
    - .bundle
    - .git
    - .gitignore
    - .kitchen
    - .kitchen.yml
    - Gemfile
    - Gemfile.lock
  pillars:
    top.sls:
      base:
        "*":
          - wireguard_data
          - wireguard
  pillars_from_files:
    wireguard_data.sls: tests/pillars/wireguard_data.sls
  pillars_from_directories:
    - ../pillar

verifier:
  name: shell
  remote_exec: false
  command: python3 -m pytest -s -v tests/

tests/pillars/wireguard_data.sls

wireguard_data:
  private_key: TEST_PRIVATE_KEY
  public_key: TEST_PUBLIC_KEY
  wireguard_ip: 10.0.0.1

../pillar/wireguard.sls

# -*- coding: utf-8 -*-
# vim: ft=yaml
---
wireguard:
  tofs:
    # For testing purposes
    source_files:
      wireguard-config-file-interface-wg0-config:
        - 'wireguard.conf.jinja'

  # Background:
  interfaces:
    wg0:
      Interface:
        # If this is not set, we will generate the private key
        # (together with the public key) and set it via PostUp
        PrivateKey: {{ pillar.get('wireguard_data')['private_key'] }}
        ListenPort: 40000
        Address: {{ pillar.get('wireguard_data')['wireguard_ip'] }}
      Peers:
        # We name the peers so we can automatically exclude them
        # on the node with the same minion ID.
        # It's also easy to alter the dicts via salt.pillar.stack.
        blah:
          PublicKey: PEER_PUBLIC_KEY
          AllowedIPs: 10.0.0.0/16
          Endpoint: HOSTNAME:40000

Kitchen Logs

...
       [DEBUG   ] Reading configuration from /tmp/kitchen/etc/salt/minion
       [DEBUG   ] Using cached minion ID from /tmp/kitchen/etc/salt/minion_id: 5fa263d2a61c
       [DEBUG   ] Configuration file path: /tmp/kitchen/etc/salt/minion
       [WARNING ] Insecure logging configuration detected! Sensitive data may be logged.
       [DEBUG   ] Grains refresh requested. Refreshing grains.
       [DEBUG   ] Reading configuration from /tmp/kitchen/etc/salt/minion
       [DEBUG   ] LazyLoaded zfs.is_supported
       [DEBUG   ] Determining pillar cache
       [DEBUG   ] LazyLoaded jinja.render
       [DEBUG   ] LazyLoaded yaml.render
       [DEBUG   ] compile template: /tmp/kitchen/srv/pillar/top.sls
       [DEBUG   ] Jinja search path: ['/tmp/kitchen/srv/pillar', '/tmp/kitchen/srv/spm/pillar']
       [PROFILE ] Time (in seconds) to render '/tmp/kitchen/srv/pillar/top.sls' using 'jinja' renderer: 0.008135318756103516
       [DEBUG   ] Rendered data from file: /tmp/kitchen/srv/pillar/top.sls:
       ---
       base:
         "*":
         - wireguard_data
         - wireguard
       
       [DEBUG   ] Results of YAML rendering: 
       OrderedDict([('base', OrderedDict([('*', ['wireguard_data', 'wireguard'])]))])
       [PROFILE ] Time (in seconds) to render '/tmp/kitchen/srv/pillar/top.sls' using 'yaml' renderer: 0.0004165172576904297
       [DEBUG   ] LazyLoaded confirm_top.confirm_top
       [DEBUG   ] LazyLoaded compound_match.match
       [DEBUG   ] compound_match: 5fa263d2a61c ? *
       [DEBUG   ] LazyLoaded glob_match.match
       [DEBUG   ] compound_match 5fa263d2a61c ? "*" => "True"
       [DEBUG   ] compile template: /tmp/kitchen/srv/pillar/wireguard_data.sls
       [DEBUG   ] Jinja search path: ['/tmp/kitchen/srv/pillar', '/tmp/kitchen/srv/spm/pillar']
       [PROFILE ] Time (in seconds) to render '/tmp/kitchen/srv/pillar/wireguard_data.sls' using 'jinja' renderer: 0.0014007091522216797
       [DEBUG   ] Rendered data from file: /tmp/kitchen/srv/pillar/wireguard_data.sls:
       wireguard_data:
         private_key: TEST_PRIVATE_KEY
         public_key: TEST_PUBLIC_KEY
         wireguard_ip: 10.0.0.1
       
       
       [DEBUG   ] Results of YAML rendering: 
       OrderedDict([('wireguard_data', OrderedDict([('private_key', 'TEST_PRIVATE_KEY'), ('public_key', 'TEST_PUBLIC_KEY'), ('wireguard_ip', '10.0.0.0')]))])
       [PROFILE ] Time (in seconds) to render '/tmp/kitchen/srv/pillar/wireguard_data.sls' using 'yaml' renderer: 0.0005438327789306641
       [DEBUG   ] compile template: /tmp/kitchen/srv/pillar/wireguard.sls
       [DEBUG   ] Jinja search path: ['/tmp/kitchen/srv/pillar', '/tmp/kitchen/srv/spm/pillar']
       [ERROR   ] Rendering exception occurred
       Traceback (most recent call last):
         File "/usr/lib/python3/dist-packages/salt/utils/templates.py", line 394, in render_jinja_tmpl
           output = template.render(**decoded_context)
         File "/usr/lib/python3/dist-packages/jinja2/asyncsupport.py", line 76, in render
           return original_render(self, *args, **kwargs)
         File "/usr/lib/python3/dist-packages/jinja2/environment.py", line 1008, in render
           return self.environment.handle_exception(exc_info, True)
         File "/usr/lib/python3/dist-packages/jinja2/environment.py", line 780, in handle_exception
           reraise(exc_type, exc_value, tb)
         File "/usr/lib/python3/dist-packages/jinja2/_compat.py", line 37, in reraise
           raise value.with_traceback(tb)
         File "<template>", line 19, in top-level template code
       jinja2.exceptions.UndefinedError: 'None' has no attribute 'private_key'
       
       During handling of the above exception, another exception occurred:
       
       Traceback (most recent call last):
         File "/usr/lib/python3/dist-packages/salt/utils/templates.py", line 169, in render_tmpl
           output = render_str(tmplstr, context, tmplpath)
         File "/usr/lib/python3/dist-packages/salt/utils/templates.py", line 404, in render_jinja_tmpl
           buf=tmplstr)
       salt.exceptions.SaltRenderError: Jinja variable 'None' has no attribute 'private_key'
       [CRITICAL] Rendering SLS 'wireguard' failed, render error:
       Jinja variable 'None' has no attribute 'private_key'
       Traceback (most recent call last):
         File "/usr/lib/python3/dist-packages/salt/utils/templates.py", line 394, in render_jinja_tmpl
           output = template.render(**decoded_context)
         File "/usr/lib/python3/dist-packages/jinja2/asyncsupport.py", line 76, in render
           return original_render(self, *args, **kwargs)
         File "/usr/lib/python3/dist-packages/jinja2/environment.py", line 1008, in render
           return self.environment.handle_exception(exc_info, True)
         File "/usr/lib/python3/dist-packages/jinja2/environment.py", line 780, in handle_exception
           reraise(exc_type, exc_value, tb)
         File "/usr/lib/python3/dist-packages/jinja2/_compat.py", line 37, in reraise
           raise value.with_traceback(tb)
         File "<template>", line 19, in top-level template code
       jinja2.exceptions.UndefinedError: 'None' has no attribute 'private_key'
       
       During handling of the above exception, another exception occurred:
       
       Traceback (most recent call last):
         File "/usr/lib/python3/dist-packages/salt/pillar/__init__.py", line 745, in render_pstate
           **defaults)
         File "/usr/lib/python3/dist-packages/salt/template.py", line 101, in compile_template
           ret = render(input_data, saltenv, sls, **render_kwargs)
         File "/usr/lib/python3/dist-packages/salt/renderers/jinja.py", line 70, in render
           **kws)
         File "/usr/lib/python3/dist-packages/salt/utils/templates.py", line 169, in render_tmpl
           output = render_str(tmplstr, context, tmplpath)
         File "/usr/lib/python3/dist-packages/salt/utils/templates.py", line 404, in render_jinja_tmpl
           buf=tmplstr)
       salt.exceptions.SaltRenderError: Jinja variable 'None' has no attribute 'private_key'
       [CRITICAL] Pillar render error: Rendering SLS 'wireguard' failed. Please see master log for details.

NinjaSomething avatar Jun 10 '21 00:06 NinjaSomething

It's been on my list to dig in to kitchen-salt to try to make it support this as well. We use https://github.com/jgraichen/salt-tower for this same use case (referencing pillars from other pillars) but testing is a little complicated at the moment. I'm also not sure if testing ext_pillars is supported by kitchen-salt yet but from quick searches through the codebase I think probably not.

raddessi avatar Jun 10 '21 15:06 raddessi

My goal isn't to test the ext_pillars. Those are python scripts that can be tested with a normal unit test.
I want to test the regular pillars that use data from ext_pillars as an input. What I really want is a mechanism for mocking ext_pillars.

If 'tests/pillars/wireguard_data.sls' is processed first and added to the pillars in the same way an ext_pillar would be, then the regular pillar '../pillar/wireguard.sls' will have access to the data from the 'ext_pillar' and can be tested successfully.

NinjaSomething avatar Jun 11 '21 13:06 NinjaSomething

If you already use ext_pillar, you can simply 'push' the same salt/salt-solo configuration to your Kitchen instances. You can overpass kitchen-salt limited directives pushing a salt-master-like configuration file.

We use pillarstack as an ext_pillar, but alone and this is what we use (extract):

# kitchen.yml
salt_minion_config_template: ./test/config/salt-solo.conf

# test/config/salt-solo.conf
# like a master conffile
file_roots:
  - /first/path

ext_pillar:
  - stack:
      - /path/to/stack/conf

daks avatar Jun 14 '21 15:06 daks