One place for hosting & domains

      How To Test Your Ansible Deployment with InSpec and Kitchen


      The author selected the Diversity in Tech Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      InSpec is an open-source auditing and automated testing framework used to describe and test for regulatory concerns, recommendations, or requirements. It is designed to be human-readable and platform-agnostic. Developers can work with InSpec locally or using SSH, WinRM, or Docker to run testing, so it’s unnecessary to install any packages on the infrastructure that is being tested.

      Although with InSpec you can run tests directly on your servers, there is a potential for human error that could cause issues in your infrastructure. To avoid this scenario, developers can use Kitchen to create a virtual machine and install an OS of their choice on the machines where tests are running. Kitchen is a test runner, or test automation tool, that allows you to test infrastructure code on one or more isolated platforms. It also supports many testing frameworks and is flexible with a driver plugin architecture for various platforms such as Vagrant, AWS, DigitalOcean, Docker, LXC containers, etc.

      In this tutorial, you’ll write tests for your Ansible playbooks running on a DigitalOcean Ubuntu 18.04 Droplet. You’ll use Kitchen as the test-runner and InSpec for writing the tests. By the end of this tutorial, you’ll be able to test your Ansible playbook deployment.

      Prerequisites

      Before you begin with this guide, you’ll need a DigitalOcean account in addition to the following:

      Step 1 — Setting Up and Initializing Kitchen

      You’ve installed ChefDK as part of the prerequisites that comes packaged with kitchen. In this step, you’ll set up Kitchen to communicate with DigitalOcean.

      Before initializing Kitchen, you’ll create and move into a project directory. In this tutorial, we’ll call it ansible_testing_dir.

      Run the following command to create the directory:

      • mkdir ~/ansible_testing_dir

      And then move into it:

      Using gem install the kitchen-digitalocean package on your local machine. This allows you to tell kitchen to use the DigitalOcean driver when running tests:

      • gem install kitchen-digitalocean

      Within the project directory, you’ll run the kitchen init command specifying ansible_playbook as the provisioner and digitalocean as the driver when initializing Kitchen:

      • kitchen init --provisioner=ansible_playbook --driver=digitalocean

      You’ll see the following output:

      Output

      create kitchen.yml create chefignore create test/integration/default

      This has created the following within your project directory:

      • test/integration/default is the directory to which you’ll save your test files.

      • chefignore is the file you would use to ensure certain files are not uploaded to the Chef Infra Server, but you won’t be using it in this tutorial.

      • kitchen.yml is the file that describes your testing configuration: what you want to test and the target platforms.

      Now, you need to export your DigitalOcean credentials as environment variables to have access to create Droplets from your CLI. First, start with your DigitalOcean access token by running the following command:

      • export DIGITALOCEAN_ACCESS_TOKEN="YOUR_DIGITALOCEAN_ACCESS_TOKEN"

      You also need to get your SSH Key ID number; note that YOUR_DIGITALOCEAN_SSH_KEY_IDS must be the numeric ID of your SSH key, not the symbolic name. Using the DigitalOcean API, you can get the numeric ID of your keys with the following command:

      • curl -X GET https://api.digitalocean.com/v2/account/keys -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN"

      From this command you’ll see a list of your SSH Keys and related metadata. Read through the output to find the correct key and identify the ID number within the output:

      Output

      ... {"id":your-ID-number,"fingerprint":"fingerprint","public_key":"ssh-rsa your-ssh-key","name":"your-ssh-key-name" ...

      Note: If you would like to make your output more readable to obtain your numeric IDs, you can find and download jq based on your OS on the jq download page. Now, you can run the previous command piped into jq as following:

      • curl -X GET https://api.digitalocean.com/v2/account/keys -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN" | jq

      You’ll see your SSH Key information formatted similarly to:

      Output

      { "ssh_keys": [ { "id": YOUR_SSH_KEY_ID, "fingerprint": "2f:d0:16:6b", "public_key": "ssh-rsa AAAAB3NzaC1yc2 example@example.local", "name": "sannikay" } ], }

      Once you’ve identified your SSH numeric IDs, export them with the following command:

      • export DIGITALOCEAN_SSH_KEY_IDS="YOUR_DIGITALOCEAN_SSH_KEY_ID"

      You’ve initialized kitchen and set up the environment variables for your DigitalOcean credentials. Now you’ll move on to create and run tests on your DigitalOcean Droplets directly from the command line.

      Step 2 — Creating the Ansible Playbook

      In this step, you’ll create a playbook and roles that set up Nginx and Node.js on the Droplet created by kitchen in the next step. Your tests will be run against the playbook to ensure the conditions specified in the playbook are met.

      To begin, create a roles directory for both the Nginx and Node.js roles:

      • mkdir -p roles/{nginx,nodejs}/tasks

      This will create a directory structure as follows:

      roles
      ├── nginx
      │   └── tasks
      └── nodejs
          └── tasks
      

      Now, create a main.yml file in the roles/nginx/tasks directory using your preferred editor:

      • nano roles/nginx/tasks/main.yml

      In this file, create a task that sets up and starts Nginx by adding the following content:

      roles/nginx/tasks/main.yml

      ---
      - name: Update cache repositories and install Nginx
        apt:
          name: nginx
          update_cache: yes
      
      - name: Change nginx directory permission
        file:
          path: /etc/nginx/nginx.conf
          mode: 0750
      
      - name: start nginx
        service:
          name: nginx
          state: started
      

      Once you’ve added the content, save and exit the file.

      In roles/nginx/tasks/main.yml, you define a task that will update the cache repository of your Droplet, which is an equivalent of running the apt update command manually on a server. This task also changes the Nginx configuration file permissions and starts the Nginx service.

      You are also going to create a main.yml file in roles/nodejs/tasks to define a task that sets up Node.js:

      • nano roles/nodejs/tasks/main.yml

      Add the following tasks to this file:

      roles/nodejs/tasks/main.yml

      ---
      - name: Update caches repository
        apt:
          update_cache: yes
      
      - name: Add gpg key for NodeJS LTS
        apt_key:
          url: "https://deb.nodesource.com/gpgkey/nodesource.gpg.key"
          state: present
      
      - name: Add the NodeJS LTS repo
        apt_repository:
          repo: "deb https://deb.nodesource.com/node_{{ NODEJS_VERSION }}.x {{ ansible_distribution_release }} main"
          state: present
          update_cache: yes
      
      - name: Install Node.js
        apt:
          name: nodejs
          state: present
      
      

      Save and exit the file when you’re finished.

      In roles/nodejs/tasks/main.yml, you first define a task that will update the cache repository of your Droplet. Then with the next task you add the GPG key for Node.js that serves as a means of verifying the authenticity of the Node.js apt repository. The final two tasks add the Node.js apt repository and install Node.js.

      Now you’ll define your Ansible configurations, such as variables, the order in which you want your roles to run, and super user privilege settings. To do this, you’ll create a file named playbook.yml, which serves as an entry point for Kitchen. When you run your tests, Kitchen starts from your playbook.yml file and looks for the roles to run, which are your roles/nginx/tasks/main.yml and roles/nodejs/tasks/main.yml files.

      Run the following command to create playbook.yml:

      Add the following content to the file:

      ansible_testing_dir/playbook.yml

      ---
       - hosts: all
         become: true
         remote_user: ubuntu
         vars:
          NODEJS_VERSION: 8
      

      Save and exit the file.

      You’ve created the Ansible playbook roles that you’ll be running your tests against to ensure conditions specified in the playbook are met.

      Step 3 — Writing Your InSpec Tests

      In this step, you’ll write tests to check if Node.js is installed on your Droplet. Before writing your test, let’s look at the format of an example InSpec test. As with many test frameworks, InSpec code resembles a natural language. InSpec has two main components, the subject to examine and the subject’s expected state:

      block A

      describe '<entity>' do
        it { <expectation> }
      end
      

      In block A, the keywords do and end define a block. The describe keyword is commonly known as test suites, which contain test cases. The it keyword is used for defining the test cases.

      <entity> is the subject you want to examine, for example, a package name, service, file, or network port. The <expectation> specifies the desired result or expected state, for example, Nginx should be installed or should have a specific version. You can check the InSpec DSL documentation to learn more about the InSpec language.

      Another example InSpec test block:

      block B

      control 'Can be anything unique' do  
        impact 0.7                         
        title 'A human-readable title'     
        desc  'An optional description'
        describe '<entity>' do             
          it { <expectation> }
        end
      end
      

      The difference between block A and block B is the control block. The control block is used as a means of regulatory control, recommendation or requirement. The control block has a name; usually a unique ID, metadata such as desc, title, impact, and finally group together related describe block to implement the checks.

      desc, title, and impact define metadata that fully describe the importance of the control, its purpose, with a succinct and complete description. impact defines a numeric value that ranges from 0.0 to 1.0 where 0.0 to <0.01 is classified as no impact, 0.01 to <0.4 is classified as low impact, 0.4 to <0.7 is classified as medium impact, 0.7 to <0.9 is classified as high impact, 0.9 to 1.0 is classified as critical control.

      Now to implement a test. Using the syntax of block A, you’ll use InSpec’s package resource to test if Node.js is installed on the system. You’ll create a file named sample.rb in your test/integration/default directory for your tests.

      Create sample.rb:

      • nano test/integration/default/sample.rb

      Add the following to your file:

      test/integration/default/sample.rb

      describe package('nodejs') do
        it { should be_installed }
      end
      

      Here your test is using the package resource to check Node.js is installed.

      Save and exit the file when you’re finished.

      To run this test, you need to edit kitchen.yml to specify the playbook you created earlier and to add to your configurations.

      Open your kitchen.yml file:

      • nano ansible_testing_dir/kitchen.yml

      Replace the content of kitchen.yml with the following:

      ansible_testing_dir/kitchen.yml

      ---
      driver:
        name: digitalocean
      
      provisioner:
        name: ansible_playbook
        hosts: test-kitchen
        playbook: ./playbook.yml
      
      verifier:
        name: inspec
      
      platforms:
        - name: ubuntu-18
          driver_config:
            ssh_key: PATH_TO_YOUR_PRIVATE_SSH_KEY
            tags:
              - inspec-testing
            region: fra1
            size: 1gb
            private_networking: false
          verifier:
            inspec_tests:
              - test/integration/default
      suites:
        - name: default
      
      

      The platform options include the following:

      • name: The image you’re using.
      • driver_config: Your DigitalOcean Droplet configuration. You’re specifying the following options for the driver_config:

        • ssh_key: Path to YOUR_PRIVATE_SSH_KEY. Your YOUR_PRIVATE_SSH_KEY is located in the directory you specified when creating your ssh key.
        • tags: The tags associated with your Droplet.
        • region: The region where you want your Droplet to be hosted.
        • size: The memory you want your Droplet to have.
      • verifier: This defines that the project contains InSpec tests.

        • The inspec_tests part specifies that the tests exist under the project test/integration/default directory.

      Note that the name and region use abbreviations. You can check on the test-kitchen documentation for the abbreviations you can use.

      Once you’ve added your configuration, save and exit the file.

      Run the kitchen test command to run the test. This will check to see if Node.js is installed—this will purposefully fail because you don’t currently have the Node.js role in your playbook.yml file:

      You’ll see output similar to the following:

      Output: failing test results

      -----> Starting Kitchen (v1.24.0) -----> Cleaning up any prior instances of <default-ubuntu-18> -----> Destroying <default-ubuntu-18>... DigitalOcean instance <145268853> destroyed. Finished destroying <default-ubuntu-18> (0m2.63s). -----> Testing <default-ubuntu-18> -----> Creating <default-ubuntu-18>... DigitalOcean instance <145273424> created. Waiting for SSH service on 138.68.97.146:22, retrying in 3 seconds [SSH] Established (ssh ready) Finished creating <default-ubuntu-18> (0m51.74s). -----> Converging <default-ubuntu-18>... $$$$$$ Running legacy converge for 'Digitalocean' Driver -----> Installing Chef Omnibus to install busser to run tests PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [localhost] PLAY RECAP ********************************************************************* localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Downloading files from <default-ubuntu-18> Finished converging <default-ubuntu-18> (0m55.05s). -----> Setting up <default-ubuntu-18>... $$$$$$ Running legacy setup for 'Digitalocean' Driver Finished setting up <default-ubuntu-18> (0m0.00s). -----> Verifying <default-ubuntu-18>... Loaded tests from {:path=>". ansible_testing_dir.test.integration.default"} Profile: tests from {:path=>"ansible_testing_dir/test/integration/default"} (tests from {:path=>"ansible_testing_dir.test.integration.default"}) Version: (not specified) Target: ssh://root@138.68.97.146:22 System Package nodejs × should be installed expected that System Package nodejs is installed Test Summary: 0 successful, 1 failure, 0 skipped >>>>>> ------Exception------- >>>>>> Class: Kitchen::ActionFailed >>>>>> Message: 1 actions failed. >>>>>> Verify failed on instance <default-ubuntu-18>. Please see .kitchen/logs/default-ubuntu-18.log for more details >>>>>> ---------------------- >>>>>> Please see .kitchen/logs/kitchen.log for more details >>>>>> Also try running `kitchen diagnose --all` for configuration 4.54s user 1.77s system 5% cpu 2:02.33 total

      The output notes that your test is failing because you don’t have Node.js installed on the Droplet you provisioned with kitchen. You’ll fix your test by adding the nodejs role to your playbook.yml file and run the test again.

      Edit the playbook.yml file to include the nodejs role:

      Add the following highlighted lines to your file:

      ansible_testing_dir/playbook.yml

      ---
       - hosts: all
         become: true
         remote_user: ubuntu
         vars:
          NODEJS_VERSION: 8
      
         roles:
          - nodejs
      

      Save and close the file.

      Now, you’ll rerun the test using the kitchen test command:

      You’ll see the following output:

      Output

      ...... Target: ssh://root@46.101.248.71:22 System Package nodejs ✔ should be installed Test Summary: 1 successful, 0 failures, 0 skipped Finished verifying <default-ubuntu-18> (0m4.89s). -----> Destroying <default-ubuntu-18>... DigitalOcean instance <145512952> destroyed. Finished destroying <default-ubuntu-18> (0m2.23s). Finished testing <default-ubuntu-18> (2m49.78s). -----> Kitchen is finished. (2m55.14s) 4.86s user 1.77s system 3% cpu 2:56.58 total

      Your test now passes because you have Node.js installed using the nodejs role.

      Here is a summary of what Kitchen is doing in the Test Action:

      • Destroys the Droplet if it exists
      • Creates the Droplet
      • Converges the Droplet
      • Verifies the Droplet with InSpec
      • Destroys the Droplet

      Kitchen will abort the run on your Droplet if it encounters any issues. This means if your Ansible playbook fails, InSpec won’t run and your Droplet won’t be destroyed. This gives you a chance to inspect the state of the instance and fix any issues. The behavior of the final destroy action can be overridden if desired. Check out the CLI help for the --destroy flag by running the kitchen help test command.

      You’ve written your first tests and run them against your playbook with one instance failing before fixing the issue. Next you’ll extend your test file.

      Step 4 — Adding Test Cases

      In this step, you’ll add more test cases to your test file to check if Nginx modules are installed on your Droplet and the configuration file has the right permissions.

      Edit your sample.rb file to add more test cases:

      • nano test/integration/default/sample.rb

      Add the following test cases to the end of the file:

      test/integration/default/sample.rb

      . . .
      control 'nginx-modules' do
        impact 1.0
        title 'NGINX modules'
        desc 'The required NGINX modules should be installed.'
        describe nginx do
          its('modules') { should include 'http_ssl' }
          its('modules') { should include 'stream_ssl' }
          its('modules') { should include 'mail_ssl' }
        end
      end
      
      control 'nginx-conf' do
        impact 1.0
        title 'NGINX configuration'
        desc 'The NGINX config file should owned by root, be writable only by owner, and not writeable or and readable by others.'
        describe file('/etc/nginx/nginx.conf') do
          it { should be_owned_by 'root' }
          it { should be_grouped_into 'root' }
          it { should_not be_readable.by('others') }
          it { should_not be_writable.by('others') }
          it { should_not be_executable.by('others') }
        end
      end
      

      These test cases check that the nginx-modules on your Droplet include http_ssl, stream_ssl, and mail_ssl. You are also checking for /etc/nginx/nginx.conf file permissions.

      You are using both the it and its keywords to define your test. The keyword its is only used to access properties of the resources. For example, modules is a property of nginx.

      Save and exit the file once you’ve added the test cases.

      Now run the kitchen test command to test again:

      You’ll see the following output:

      Output

      ... Target: ssh://root@104.248.131.111:22 ↺ nginx-modules: NGINX modules ↺ The `nginx` binary not found in the path provided. × nginx-conf: NGINX configuration (2 failed) × File /etc/nginx/nginx.conf should be owned by "root" expected `File /etc/nginx/nginx.conf.owned_by?("root")` to return true, got false × File /etc/nginx/nginx.conf should be grouped into "root" expected `File /etc/nginx/nginx.conf.grouped_into?("root")` to return true, got false ✔ File /etc/nginx/nginx.conf should not be readable by others ✔ File /etc/nginx/nginx.conf should not be writable by others ✔ File /etc/nginx/nginx.conf should not be executable by others System Package nodejs ✔ should be installed Profile Summary: 0 successful controls, 1 control failure, 1 control skipped Test Summary: 4 successful, 2 failures, 1 skipped

      You’ll see that some of the tests are failing. You’re going to fix those by adding the nginx role to your playbook file and rerunning the test. In the failing test, you’re checking for nginx modules and file permissions that are currently not present on your server.

      Open your playbook.yml file:

      • nano ansible_testing_dir/playbook.yml

      Add the following highlighted line to your roles:

      ansible_testing_dir/playbook.yml

      ---
      - hosts: all
        become: true
        remote_user: ubuntu
        vars:
        NODEJS_VERSION: 8
      
        roles:
        - nodejs
        - nginx
      

      Save and close the file when you’re finished.

      Then run your tests again:

      You’ll see the following output:

      Output

      ... Target: ssh://root@104.248.131.111:22 ✔ nginx-modules: NGINX version ✔ Nginx Environment modules should include "http_ssl" ✔ Nginx Environment modules should include "stream_ssl" ✔ Nginx Environment modules should include "mail_ssl" ✔ nginx-conf: NGINX configuration ✔ File /etc/nginx/nginx.conf should be owned by "root" ✔ File /etc/nginx/nginx.conf should be grouped into "root" ✔ File /etc/nginx/nginx.conf should not be readable by others ✔ File /etc/nginx/nginx.conf should not be writable by others ✔ File /etc/nginx/nginx.conf should not be executable by others System Package nodejs ✔ should be installed Profile Summary: 2 successful controls, 0 control failures, 0 controls skipped Test Summary: 9 successful, 0 failures, 0 skipped

      After adding the nginx role to the playbook all your tests now pass. The output shows that the http_ssl, stream_ssl, and mail_ssl modules are installed on your Droplet and the right permissions are set for the configuration file.

      Once you’re finished, or you no longer need your Droplet, you can destroy it by running the kitchen destroy command to delete it after running your tests:

      Following this command you’ll see output similar to:

      Output

      -----> Starting Kitchen (v1.24.0) -----> Destroying <default-ubuntu-18>... Finished destroying <default-ubuntu-18> (0m0.00s). -----> Kitchen is finished. (0m5.07s) 3.79s user 1.50s system 82% cpu 6.432 total

      You’ve written tests for your playbook, run the tests, and fixed the failing tests to ensure all the tests are passing. You’re now set up to create a virtual environment, write tests for your Ansible Playbook, and run your test on the virtual environment using Kitchen.

      Conclusion

      You now have a flexible foundation for testing your Ansible deployment, which allows you to test your playbooks before running on a live server. You can also package your test into a profile. You can use profiles to share your test through Github or the Chef Supermarket and easily run it on a live server.

      For more comprehensive details on InSpec and Kitchen, refer to the official InSpec documentation and the official Kitchen documentation.



      Source link

      Test Salt States Locally with KitchenSalt


      Updated by Linode Written by Linode

      KitchenSalt allows you to use Test Kitchen to test your Salt configurations locally without a Salt master or minions. In this guide you will install KitchenSalt and use Docker to test a Salt state. This guide was created using a system running Ubuntu 18.04.

      Before You Begin

      • You will need root access to your computer, or a user account with sudo privilege. For more information on privileges, see our Users and Groups guide.
      • Install Git on your local computer, if it is not already installed.
      • Update your system packages.

      Install rbenv and Ruby

      Kitchen runs on Ruby. The following commands will install the Ruby version controller rbenv, set rbenv in your PATH, and install Ruby via rbenv.

      1. Install the packages necessary for rbenv:

        sudo apt install libssl-dev libreadline-dev zlib1g-dev bzip2 gcc make git ruby-dev
        
      2. Clone the rbenv git repository and set up your PATH:

        sudo git clone git://github.com/rbenv/rbenv.git /usr/local/rbenv
        sudo mkdir /usr/local/rbenv/plugins
        sudo git clone git://github.com/rbenv/ruby-build.git /usr/local/rbenv/plugins/ruby-build
        sudo tee /etc/profile.d/rbenv.sh <<< 'export PATH="/usr/local/rbenv/plugins/ruby-build/bin:/usr/local/rbenv/bin:$PATH"'
        sudo tee -a /etc/profile.d/rbenv.sh <<< 'source <(rbenv init -)'
        
      3. Reload your system’s profile so that the rbenv commands are added to your PATH:

        source /etc/profile
        

        You can also restart your shell session so the PATH changes take effect.

      4. Install Ruby:

        rbenv install 2.5.1
        

      Install Docker

      These steps install Docker Community Edition (CE) using the official Ubuntu repositories. To install on another distribution, see the official installation page.

      1. Remove any older installations of Docker that may be on your system:

        sudo apt remove docker docker-engine docker.io
        
      2. Make sure you have the necessary packages to allow the use of Docker’s repository:

        sudo apt install apt-transport-https ca-certificates curl software-properties-common
        
      3. Add Docker’s GPG key:

        curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
        
      4. Verify the fingerprint of the GPG key:

        sudo apt-key fingerprint 0EBFCD88
        

        You should see output similar to the following:

        pub   4096R/0EBFCD88 2017-02-22
              Key fingerprint = 9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
        uid                  Docker Release (CE deb) <docker@docker.com>
        sub   4096R/F273FCD8 2017-02-22
        
      5. Add the stable Docker repository:

        sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
        
      6. Update your package index and install Docker CE:

        sudo apt update
        sudo apt install docker-ce
        
      7. Add your limited Linux user account to the docker group:

        sudo usermod -aG docker exampleuser
        

        You will need to restart your shell session for this change to take effect.

      8. Check that the installation was successful by running the built-in “Hello World” program:

        docker run hello-world
        

      Install KitchenSalt

      1. Install the bundler gem:

        sudo gem install bundler
        
      2. Create a Gemfile in your working directory and add the kitchen-salt, kitchen-docker, and kitchen-sync gems:

        Gemfile
        1
        2
        3
        4
        5
        6
        
        #Gemfile
        source 'https://rubygems.org'
        
        gem 'kitchen-salt'
        gem 'kitchen-docker'
        gem 'kitchen-sync'

        kitchen-sync is used to copy files to Docker containers more quickly.

      3. Install the gems with bundler:

        sudo bundle install
        

      Create a Sample .sls File

      For testing purposes, create a Salt state file that installs NGINX and ensures that it is running. In a text editor, create an nginx.sls file in your working directory and add the following lines:

      nginx.sls
      1
      2
      3
      4
      5
      6
      7
      8
      
      nginx:
        pkg:
          - installed
        service.running:
          - enable: True
          - reload: True
          - watch:
            - pkg: nginx

      Configure kitchen.yml

      1. Now, write the Kitchen configuration file, beginning with the provisioner section. Copy the following lines into a kitchen.yml file in your working directory.

        kitchen.yml
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        
        provisioner:
          name: salt_solo
          salt_install: bootstrap
          is_file_root: true
          require_chef: false
          state_top:
            base:
              "*":
                - nginx
        
        ...

        This section defines salt_solo as the provisioner, which will allow Kitchen to use Salt without a Salt master. In this section Salt is installed via the bootstrap script by setting salt_install: bootstrap, the Salt file root is mapped to the directory where .kitchen.yml is located by setting is_file_root: true, and Chef is disabled by setting require_chef: false. Instead of providing a top file for Salt states, the top file is declared inline. This section is also where Salt pillar files are added. For reference, they are added under the provisioner block:

        kitchen.yml
        1
        2
        3
        4
        5
        6
        7
        8
        9
        
        provisioner:
        ...
          pillars:
            top.sls:
              base:
                "*":
                  - nginx_pillar
          pillars_from_files:
            nginx_pillar.sls: nginx.pillar
      2. Next, configure the driver section:

        kitchen.yml
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        
        ...
        
        driver:
          name: docker
          user_sudo: false
          privileged: true
          forward:
            - 80
        
        ...

        This section declares Docker as the driver, though you could also use Vagrant. Kitchen does not need to use sudo to build the Docker containers, so user_sudo is set to false. privileged is set to true to ensure that the containers run systemd as the exec command. The Docker container will forward traffic to the host on port 80.

      3. Configure the platforms section:

        kitchen.yml
        1
        2
        3
        4
        5
        6
        7
        8
        
        ...
        
        platforms:
          - name: ubuntu
            driver_config:
              run_command: /lib/systemd/systemd
        
        ...

        This section defines which platform Docker will run. By default Docker will run the latest version of that platform. Because different platforms place systemd in different locations, the driver_config section is used to point to the systemd install path of that platform. More than one platform can be defined.

      4. Configure the suites section:

        kitchen.yml
        1
        2
        3
        4
        5
        6
        7
        8
        
        ...
        
        suites:
          - name: oxygen
            provisioner:
              salt_bootstrap_options: -X -p git stable 2018.3
        
        ...

        suites defines which software suite Kitchen will test against. In this context, Kitchen will test against the Oxygen release of Salt. More than one suite can be defined.

      5. Lastly, the transport section allows us to specify the use of kitchen-sync for transferring files:

        kitchen.yml
        1
        2
        3
        4
        
        ...
        
        transport:
          name: sftp
      6. You can now test your Salt configuration with Kitchen. Type the following command to run the test:

        kitchen test
        

        This command will create, converge, and then destroy the test instance. If completed successfully, the final terminal output will be:

          
        -----> Kitchen is finished. (13m32.13s)
        
        

        For a more granular approach to running your test, you can use the individual commands in series:

        kitchen list
        kitchen create
        kitchen converge
        kitchen destroy
        

      Using a Verifier and Next Steps

      Though it is beyond the scope of this article, Kitchen allows for more robust testing than just checking a Salt configuration. You can write tests in bash using Bats, in Ruby using Minitest, Rspec, Serverspec and Inspec, or if you’re more familiar with Python you can use pytest.

      As an example, you can add the following code to your kitchen.yaml to verify your tests using the Inspec gem:

      kitchen.yml
      1
      2
      3
      4
      
      ...
      
      verifier:
        name: inspec

      For more information on writing tests, visit the links in the More Information section below.

      More Information

      You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

      Find answers, ask questions, and help others.

      This guide is published under a CC BY-ND 4.0 license.



      Source link