How to capture the result of salt's execution module in SLS? - salt-stack

{% testVar = pillar['ServiceName'] %}
GetServiceId:
module.run:
- service.getsid:
- name: testVar
useServiceId:
- cmd.script:
- source: test/path/test.ps1
- args:
According to the doc https://docs.saltproject.io/en/latest/ref/modules/all/salt.modules.win_service.html#salt.modules.win_service.get_service_name , the execution module returns a string. How can I capture the string returned by "GetServiceId" and use it in "useServiceId"?

There are two ways, depending on which stage of the process the module should run.
During rendering (preferred):
useServiceId:
- cmd.script:
- source: salt://test/path/test.ps1
- args: "{{ salt["service.getsid"](pillar["ServiceName"]) }}"
During execution:
useServiceId:
- cmd.script:
- source: salt://test/path/test.ps1
- args: __slot__:salt:service.getsid({{ pillar["ServiceName"] }})
Note: assuming that the service name isn't secret in any way, it probably shouldn't be in pillar, and instead be loaded from some sort of map.jinja or variables.yaml in the state tree.

Related

How to add nested dictionary to dynamic host in Ansible

I have application details in respective vars like below. For example, myapp1 in "QA" environment would look like the below:
cat myapp1_QA.yml
---
APP_HOSTS:
- myapphost7:
- logs:
- /tmp/web/apphost7_access
- /tmp/web/apphost7_error
- myapphost9:
- logs:
- /tmp/web/apphost9_access
- /tmp/web/apphost9_error
- /tmp/web/apphost9_logs
WEB_HOSTS:
- mywebhost7:
- logs:
- /tmp/webserver/webhost7.pid
In this example I wish to create a dynamic host containing the 3 hosts
myapphost7
myapphost9
mywebhost7
and each host has variable log which can be looped to get the file paths:
Below is my ansible play:
---
- hosts: localhost
tasks:
- include_vars:
file: "{{ playbook_dir }}/{{ appname }}_{{ myenv }}.yml"
- name: Dsiplay dictionary data
debug:
msg: "{{ item[logs] }}"
loop: "{{ APP_HOSTS }}"
I get the below error:
ansible-playbook read.yml -e appname=myapp1 -e myenv=QA
TASK [Dsiplay dictionary data] *********************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'logs' is undefined\n\nThe error appears to be in '/root/read.yml': line 8, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Dsiplay dictionary data\n ^ here\n"}
My requirement is to store "myapphost7", "myapphost9", "mywebhost7" in group using add_hosts: hosts: while a variable logs: having the list of log files.
Note: if no hosts mywebhost7 is defined under WEB_HOSTS: or APP_HOSTS: then nothing should be added to the dynamic host.
Can you please suggest?

Ansible Generate List of Compliying hosts

I'm trying to generate a list with the information of hosts that match a certain condition (for instance, that NTP is synched for an inventory of Cisco devices). So that the ones matching that condition will be added to a list with say hostname and IP, for later generating a CSV.
Checking the condition is quite easy, but I'm struggling on how to generate this list.
Adding them to a list in a var doesn't seem wise, as it requires of serial execution of tasks per device.
Should I set a boolean fact for each device (i.e., ntp_synched, and then generate a list with the ansible_net_hostname and ansible_host of each device? How to do this?
- name: CHECK NTP STATUS
ios_command:
commands:
- show ntp status
register: ntp_status
- name: NTP NOT SYNCH
debug:
msg: "{{ [ansible_net_hostname] }}"
when: '"Clock is synchronized" not in ntp_status.stdout[0]'
For example, given the inventory for testing
host01 status="Clock is synchronized"
host02 status="Clock is synchronized"
host03 status="Clock is not synchronized"
Create the dictionary of the hosts and statuses
- hosts: all
tasks:
- command: "echo {{ status }}"
register: ntp_status
- set_fact:
host_status: "{{ dict(_hosts|zip(_stats)) }}"
vars:
_hosts: "{{ ansible_play_hosts }}"
_stats: "{{ ansible_play_hosts|
map('extract', hostvars, ['ntp_status','stdout'])|list }}"
run_once: true
gives
host_status:
host01: Clock is synchronized
host02: Clock is synchronized
host03: Clock is not synchronized
List the synchronized hosts
- debug:
msg: "{{ host_status|dict2items|
selectattr('value', 'search', 'Clock is synchronized')|
map(attribute='key')|list }}"
run_once: true
gives
msg:
- host01
- host02

Ansible include_vars into dictionary

In my ansible playbook, I read a list of directories into a list. I then want to read a "config.yml" file from each of these directories and put their content into dictionary, so that I can reference the config-data via the directory name from that dictionary.
The first part is no problem, but I cannot get the second part to work:
Step 1, load directories:
- name: Include directories
include_vars:
file: /main-config.yml
name: config
Step 2, load configs from directories:
- name: load deploymentset configurations
include_vars:
file: /path/{{ item }}/config.yml
name: "allconfs.{{ item }}" ## << This is the problematic part
with_items:
- "{{ config.dirs }}"
I tried different things like "allconfs['{{ item }}'], but none seemed to work. The playbook completed successfully, but the data was not in the dictionary.
I also tried defining the outer dictionary beforehand, but that did not work either.
The config files themselves are very simple:
/main-config.yml:
dirs:
- dir1
- dir2
- dir3
/path/dir1/config.yml:
some_var: "some_val"
another_var: "another val"
I want to be able to then access the values of the config.yml files like this:
{{ allconfs.dir1.some_var }}
UPDATE to try Konstantins approach:
- name: load deploymentset configurations
include_vars:
file: /repo/deploymentsets/{{ item }}/config.yml
name: "default_config"
with_items:
- "{{ config.deploymentsets }}"
register: default_configs
- name: combine configs
set_fact:
default_configs: "{{ dict(default_configs.results | json_query('[].[item, ansible_facts.default_config]')) }}"
Error message:
fatal: [127.0.0.1]: FAILED! => {"failed": true, "msg": "Unexpected templating type error occurred on ({{ dict(default_configs.results | json_query('[].[item, ansible_facts.default_config]')) }}): <lambda>() takes exactly 0 arguments (1 given)"}
Here is a piece of code from one of my projects with similar functionality:
- name: Load config defaults
include_vars:
file: "{{ item }}.yml"
name: "default_config"
with_items: "{{ config_files }}"
register: default_configs
tags:
- configuration
- name: Combine configs into one dict
# Здесь мы делаем словарь вида
# default_configs:
# config_name_1: { default_config_object }
# config_name_2: { default_config_object }
# config_name_3: { default_config_object }
# ...
set_fact:
default_configs: "{{ dict(default_configs.results | json_query('[].[item, ansible_facts.default_config]')) }}"
tags:
- configuration
default_config is a dummy var to temporary load var data.
The trick is to use register: default_configs with include_vars and parse it with the following task stripping out unnecessary fields.
AFAIK it isn't possible to create a single dictionary that encompasses multiple include_vars. From my testing it would create separate dictionaries for each included directory. Here's what you can do instead.
Remove allconfs. from your variable name.
- name: load deploymentset configurations
include_vars:
file: /path/{{ item }}/config.yml
name: "{{ item }}"
with_items:
- "{{ config.dirs }}"
You can then either access variables directly with
debug:
msg: "{{ dir1.some_var }}"
with_items: "{{ config.dirs }}"
Or if you need to loop through all variables in your included directories use this (hoisted from Ansible: how to construct a variable from another variable and then fetch it's value).
debug:
msg: "{{ hostvars[inventory_hostname][item].some_var }}"
with_items: "{{ config.dirs }}"

Salt: text file to variable and use the same variable in state file to find&replace

I've run into an issue I havent been able to solve:
I have a file(/etc/osci) that I use on all of my servers as an name for our monitoring(zabbix)
I've created a state file that pushes a template configuration file to the server and and reads the content of /etc/osci to a variable. The next step would be to use that same variable with 'file.replace' function to search for a string and replace it with the variable.
uusnimi=$(cat /etc/osci):
cmd.run
/etc/zabbix_agentd.conf:
file.managed:
- source: salt://base/streamingconf/zabbix/zabbix_agentd.conf
- mode: 644
change_hostname_zabbix:
file.replace:
- name: /etc/zabbix_agentd.conf
- pattern: 'Hostname='
- repl: 'Hostname=$uusnimi'
Now when executing the state file echoing the variable in the target server it provides me the right output:
echo $uusnimi
Server1
but for the life of me I can't figure out how to escape the last line of the above code so it would insert the value not the '$uusnimi' string
Use uusnimi as a jinja variable.
{% set uusnimi = salt['cmd.shell']('cat /etc/osci') %}
/etc/zabbix_agentd.conf:
file.managed:
- source: salt://base/streamingconf/zabbix/zabbix_agentd.conf
- mode: 644
change_hostname_zabbix:
file.replace:
- name: /etc/zabbix_agentd.conf
- pattern: 'Hostname='
- repl: 'Hostname={{ uusnimi }}'

Syntax error in SaltStack state file

I am newbie with SaltStack. I have an error in one of my first state files.
The state file is:
openvpn:
pkg.installed: []
/etc/openvpn:
file.recurse:
- source: salt://myvpn/openvpn-files
service.running: []
And the error: State 'openvpn' in SLS u'myvpn' is not formed as a list
Could you say me where is the fail?
I found the error. It can't define a state inside other state (/etc/openvpn: inside openvpn:)
I've fixed this way:
openvpn:
pkg.installed: []
file.recurse:
- name: /etc/openvpn
- source: salt://myvpn/openvpn-files
service.running: []

Resources