(SaltStack) ID dog in SLS dog is not a dictionary - salt-stack

I have been trying to find a pattern (bcm2708_wdog) in the /etc/modules file and if it isnt there add it to the bottom. Every time I try this I get the "ID dog in SLS dog is not a dictionary". I have no idea what this means.
Here is the file:
dog:
- file.replace:
- name: /etc/modules
- pattern: 'bcm2708_wdog'
- append_if_not_found: True

It should probably look like this:
dog:
file.replace: # <--------this line was your problem.
- name: /etc/modules
- pattern: 'bcm2708_wdog'
- append_if_not_found: True
Lines beginning with "-" denote items in a list. In your version, you've defined the top-level "dog" element as a list containing a dictionary. Salt expects it to be a straight dictionary instead, hence the error.

Depending on your version, in 2018
You will get that message if wrote the state with just 'file.replace' without the "dog" on top.
file.replace:
- name: /etc/modules
- pattern: 'bcm2708_wdog'
- append_if_not_found: True

Related

DataDog - pass multiple fnmatch paterns to configuration

init_config:
instances:
- directory: /mnt/ftp/generic/Salesorder
pattern: '*_12_*.csv'
filegauges: true
dirtagname: history
- directory: /mnt/ftp/generic/Salesorder
pattern: '2021_*_*.csv'
filegauges: true
dirtagname: this-year
The directory contains multiple files with the next format YYYY_MM_SalesOrder.csv
How to use multiple patterns in a single instance?
This is not possible.
Only one instance per format.
This is what it is :/
Maybe in the future, there will be better options for DataDog.
init_config:
instances:
- directory: /mnt/ftp/generic/Salesorder
pattern: '*_12_*.csv'
filegauges: true
dirtagname: history
- directory: /mnt/ftp/generic/Salesorder
pattern: '2021_*_*.csv'
filegauges: true
dirtagname: this-year

salt attribute(key/value) replacement based on particular stanza

Using salt i want to find the attribute(key) and replace it with value based on specific stanza. The attribute(key) is present in multiple times in a file under different stanzas. I want to find my attribute under specific stanza and replace with value.
Example:
output.kafka:
# Boolean flag to enable or disable the output module.
enabled:
I need to find enabled: under output.kafka: and replace it with value. The enabled: attribute present multiple times in my file.
Thanks
Bala.
Salt has a few commands like file.line, file.replace and file.blockreplace that can modify an existing file, but I highly recommend managing the whole file using file.managed. It makes for a less brittle experience.
Here's an example based off your question:
Pillar top file:
cat /srv/pillar/top.sls
base:
'*':
- common
'minion01':
- minion01kafkasettings
Set our pillar data:
cat /srv/pillar/minion01kafkasettings.sls
kafka_output: True
Here's our filebeat template:
cat /srv/salt/filebeat.tmpl
output.kafka:
# Boolean flag to enable or disable the output module.
enabled: {{ pillar.get('kafka_output', True) }}
Here's the filebeat Salt sls file:
cat /srv/salt/filebeat.sls
the_filebeat_file:
file.managed:
- name: /etc/filebeat/filebeat.yml
- template: jinja
- user: root
- group: root
Then we can run the following:
Refresh our pillar data
salt 'minion01' saltutil.refresh_pillar
Then apply the sls file:
salt 'minion01' state.sls filebeat
I have another theory using file.seralize that might work but not in its current state, Maybe Dave could help.
{% set json_data = salt.cp.get_file_str('/etc/filebeat/filebeat.yml') | load_yaml %}
{% do json_data.update({'enabled': pillar.get('kafka_output', True) }) %}
update_config:
file.serialize:
- name: /etc/filebeat/filebeat.yml
- user: root
- group: root
- mode: 644
- formatter: yaml
- dataset: |
{{ json_data | yaml(False)| indent(8) }}
This state should load the whole configuration file then you can modify any of its values based on your pillar setting using the do statement in your case it could be
{% do json_data.update({'enabled': pillar.get('kafka_output', True) }) %}
The config file is populated but not as exepcted as the result will be as following:
'enabled: true
status: active
'
Note there are quotes and the yaml is not intended correctly, is there another way to make it work ? I will update this answer if I found any new results

How to delete an inherit property from yaml config?

I have a yaml file like this:
local: &local
image: xxx
# *tons of config*
ci:
<<: *local
image: # delete
build: .
I want ci to inherit all values from local, except the image.
Is there a way to "delete" this value?
No there isn't a way to mark a key for deletion in a YAML file. You can only overwrite existing values.
And the latter is what you do, you associate the empty scalar as value to the key image as if you would have written:
image: null # delete
There are two things you can do: post-process or make a base mapping in your YAML file.
If you want to post-process, you associate a special unique value to image, or a specially tagged object, and after loading recursively walk over the tree to remove key-value pairs with this special value. Whether you can already do this during parsing, using hooks or overwriting some of its methods, depends on the parser.
Using a base mapping requires less work, but is more intrusive to the YAML file:
localbase: &lb
# *tons of config*
local: &local
image: xxx
ci:
<<: *lb
build: .
If you do the former you should note that if you use a parsers that preserve the "merge-hierarchy" on round-tripping (like my ruamel.yaml parser can do) it is not enough to delete the key-value pair, in that case the original from local would come back. Other parsers that simply resolve this at load time don't have this issue.
For properties that accept a list of values, you can send [] as value.
For example in docker-compose you don't want to inherit ports:
service_1: &service_1
# some other properties.
ports:
- "49281:22"
- "8876:8000"
# some other properties
image: some_image:latest
service_2:
<<: *service_1
ports: [] # it removes ports values.
image: null # it removes image value.

Using Inline Yaml Formatting over multiple lines?

I'm trying to create a YAML file for use with nose-testconfig with data like this:
"Computers":
"Brand: "Dell"
"Cost": 500
"IP": "194.66.82.11"
"Brand: "HP"
"Cost": 600
"IP": "194.66.82.13"
"Brand: "Asus"
"Cost": 550
"IP": "194.66.82.15"
The problem I'm having is that each of the repeated items just get overwritten. I need to have it be a list of lists of dictionaries, however I don't know how to make that work. I can't just use the inline formatting with brackets and braces because the actual data I'm working with has a lot more data in each dictionary, so the lines would be way too long.
Is there a way to format this in a way that keeps each list of dictionaries separate?
What I think you want is this:
Computers:
- Brand: Dell
Cost: 500
IP: 194.66.82.11
- Brand: HP
Cost: 600
IP: 194.66.82.13
- Brand: Asus
Cost: 550
IP: 194.66.82.15
This represents a mapping ("dictionary") with one key, "Computers," whose value is a sequence ("list") having three items, each of which is a mapping with the three keys "Brand," "Cost", and "IP."
In JavaScript, for example, it would deserialize to this structure:
{ Computers:
[ { Brand: "Dell",
Cost: 500,
IP: "192.66.82.11"
},
{ Brand: "HP",
Cost: 600,
IP: "192.168.82.13"
},
{ Brand: "Asus",
Cost: 550,
IP: "192.168.82.15"
}
]
}
P.S. You'll notice I removed the quotation marks. Quotation marks are an antipattern in YAML—there are very few situations where they're necessary (for example, if you wanted "500" to be deserialized as a string instead of a number) and they add a lot of line noise, defeating the purpose of YAML, which is ease of reading and editing.
P.P.S. A utility I find hugely useful is this Online YAML Parser, which will show you the result, in either JSON or Python notation, of any YAML input as you type.
What you should do if you are unsure about how your YAML for a certain construct should look is create the construction in your programming language of choice (for which there should be no such uncertainty), and then dump it. E.g. in Python:
import sys
import ruamel.yaml
data = dict(Computers=[
dict(Brand="Dell", Cost=500, IP="194.66.82.11"),
dict(Brand="HP", Cost=600, IP="194.66.82.13"),
dict(Brand="Asus", Cost=550, IP="194.66.82.15"),
])
yaml = YAML()
yaml.dump(data, sys.stdout)
gives you:
Computers:
- IP: 194.66.82.11
Brand: Dell
Cost: 500
- IP: 194.66.82.13
Brand: HP
Cost: 600
- IP: 194.66.82.15
Brand: Asus
Cost: 550
What you see is that quotes around simple scalars are unnecessary (but they are allowed according to the specification, so it is perfectly OK to put them in). You also see that you missed putting a list in your YAML file (which in block mode is indicated by the - dashed items).
Using this way it is easy to determine for yourself how your data should be formatted to be valid YAML. For some parsers you need to try with block or non-flow style formatting to get a better readable result, for ruamel.yaml (of which I am the author) block style is default as it is, IMO, more readable.
Please note that keys for mappings in YAML are by definition unordered, although ruamel.yaml can preserve these for you in roundtrip mode

Is there a way to display only changes and errors

I have quite extensive salt config and I want to be able to see what has changed. If I just run salt '*' state.highstate I got the whole list with things that were present and not changed - like 3 to 4 screens of log. But I'd really like to see only things that changed in the last job.
It doesn't have to work for the salt call, it can also employ salt-run jobs.lookup_jid.
You can set state_verbose: False in /etc/salt/master or /etc/salt/minion.
If you want to shorten the output to one line per state, set state_output: terse.
You can also pass these filters on command line:
salt --state-output=terse '*' state.highstate
If you only want to see changes, you can use state-output=changes or state-output=mixed. The latter one will show more information on a failure.
See the following answers fore more detail: basepi, psarossy
We've also added state_output: mixed which will give you the same output as terse, except if there's a failure, in which case it will give you the more verbose output.
To actually answer the question, yes, there is an output filter for changes only:
salt '*' state.highstate --state-output=changes
This will display one liners for things that are in the right state and the proper output for the changes. ie:
<...>
Name: /etc/sudoers - Function: file.managed - Result: Clean
Name: /etc/timezone - Function: file.managed - Result: Clean
Name: /etc/pki/tls/certs/logstash-forwarder.crt - Function: file.managed - Result: Clean
Name: /etc/init.d/logstash-forwarder - Function: file.managed - Result: Clean
----------
ID: /etc/logstash-forwarder
Function: file.managed
Result: True
Comment: File /etc/logstash-forwarder updated
Started: 14:14:28.580950
Duration: 65.664 ms
Changes:
----------
diff:
---
+++
## -1,6 +1,6 ##
{
"network": {
- "servers": [ "10.0.0.104:5000" ],
+ "servers": [ "10.0.0.72:5000" ],
"timeout": 15,
"ssl ca": "/etc/pki/tls/certs/logstash-forwarder.crt"
},
Name: deb http://packages.elasticsearch.org/logstashforwarder/debian stable main - Function: pkgrepo.managed - Result: Clean
Name: logstash-forwarder - Function: pkg.installed - Result: Clean
<...>
There are 2 options, first is to change the state_output in master's configuration file, like mentioned in the accepted answer, and it also possible to override the state output in command line, like:
salt --state-output=mixed \* test.version
As of the following PR that was merged into Salt 2015.8.0 (https://github.com/saltstack/salt/pull/26962) it is now possible to toggle the state_verbose flag from command line when running highstate. This overrides the config you can set in /etc/salt/master that was mentioned in previous answers.
The following command should now display only the changes and errors from a highstate run salt '*' state.highstate --state-verbose=False
You can use the below to shorten the output in one line and then filter that output to show only the changes:
salt -v 'minion' state.highstate test=True --state-output=terse --state-verbose=False

Resources