How do I set a list as value for a salt grain? - salt-stack

How exactly can I use salt.modules.grains.set) to configure a grain which is a list?
Concretely I want to configure the grain roles to be a list of roles
roles:
- k8s_node
- my_role
I know I could configure the grains-file, but I explicitly would like to know how to achieve this via the command mentioned above.
I tried different things, none worked. Example
sudo salt $node grains.set "roles" k8s_node,my_role
node:
----------
changes:
----------
roles:
k8s_node,my_role
comment:
result:
True

I ultimately figured, you can use [xxx]. So
sudo salt $node grains.set "roles" [k8s_node,my_role]
node:
----------
changes:
----------
roles:
- k8s_node
- my_role
comment:
result:
True

Related

What "resource: |" does mean in routes.yaml?

I'm trying to figure out with Sylius routing, based on Symfony framework. I found that code
sylius_admin_channel:
resource: |
alias: sylius.channel
section: admin
templates: "#SyliusAdmin\\Crud"
except: ['show']
redirect: update
grid: sylius_admin_channel
permission: true
vars:
all:
subheader: sylius.ui.configure_channels_available_in_your_store
templates:
form: "#SyliusAdmin/Channel/_form.html.twig"
index:
icon: share alternate
type: sylius.resource
But I could not find any information what is it | for resource. Any help?
Thanks.
It's the YAML syntax for a multi-line string (that preserves newlines).
So sylius_admin_channel is a mapping that has two keys (resource and type) whose values are both string types.
It can be confusing to see in this instance because the string happens to also be valid YAML. I edited your question to include syntax highlighting for YAML which makes this a little more obvious, visually.
If I didn't know any better, I would have guessed that the | is there in error and resource should actually have a mapping type for its value. If you remove the |, then same symbols that were within that string still produce valid YAML for the whole file, but the value of resource would be a mapping, rather than a string.
Notice the difference in syntax highlighting, compared to the yaml in the question with the | removed:
sylius_admin_channel:
resource:
alias: sylius.channel
section: admin
templates: "#SyliusAdmin\\Crud"
except: ['show']
redirect: update
grid: sylius_admin_channel
permission: true
vars:
all:
subheader: sylius.ui.configure_channels_available_in_your_store
templates:
form: "#SyliusAdmin/Channel/_form.html.twig"
index:
icon: share alternate
type: sylius.resource

SaltStack: "require: previous_state" needed?

I have a sls script which was written by a college. The next state always requires the previous state.
Example:
apache:
service.running:
- name: apache2
- enable: True
...
apache_modules:
apache_module.enabled:
...
- require:
- pkg: apache
server.conf:
file.managed:
- name: /etc/apache2/sites-available/server.conf
...
- require:
- pkg: apache
apache_sites_enabled:
apache_site.enabled:
- names:
- server
- require:
- file: server.conf
Question: Is this "require" needed?
I guess it is not needed, since salt executes one state after the other.
I care for readabilty and would like to keep the file as small as possible.
Normally Salt executes states in the order in which they are specified, in 'imperative' order. In the same file, it means from top to bottom.
Require/Watch/Require_in/Watch_in and others can be used to assure a specific order between some states and changes this default "linear" order. This is the 'declarative' order.
See https://docs.saltstack.com/en/latest/ref/states/ordering.html#ordering-states and https://docs.saltstack.com/en/getstarted/config/requisites.html
I tend to absolutely use requisites between independent states (like formulas) when a specific order is needed, and sometimes I also write requisites in the same state file.

Reusing salt state snippets

In my salt state files I have several occurrences of a pattern which consists of defining a remote repository and importing a gpg key file definition, e.g.
import_packman_gpg_key:
cmd.run:
- name: rpm --import http://packman.inode.at/gpg-pubkey-1abd1afb.asc
- unless: rpm -q gpg-pubkey-1abd1afb-54176598
packman-essentials:
pkgrepo.managed:
- baseurl: http://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Tumbleweed/Essentials/
- humanname: Packman (Essentials)
- refresh: 1
require:
- cmd: import_packman_gpg_keygpg-pubkey-1abd1afb-54176598
I would like to abstract these away as a different state, e.g.
packman-essentials:
repo_with_key.managed:
- gpg_key_id: 1abd1afb-54176598
- gpg_key_src: http://packman.inode.at/gpg-pubkey-1abd1afb.asc
- repo_url: http://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Tumbleweed/Essentials/
- repo_name: Packman (Essentials)
which will in turn expand to the initial declarations above. I've looked into custom salt states ( see https://docs.saltstack.com/en/latest/ref/states/writing.html#example-state-module ) but I only found references on how to create one using Python. I'm looking for one which is based only on state definitions, as writing code for my specific problem looks overkill.
How can I create a custom state which reuses the template I've been using to manage package repositories?
This is what macros are for
Here is an example of simple macros for some heavily used by me constructs
However in your example, why do you cmd.run to import key?
pkgrepo.managed seems to support gpgkey option to download the key

How to join two Salt pillar files and merge data?

Is there any way to join two pillar files?
I have a users pillar. It's something like:
users:
joe:
sudouser: True
jack:
sudouser: False
Now I need different set of users for certain servers (ie. add some users to one server). So I create new pillar file:
users:
new_user:
sudouser: True
And assign this topfile to the server. But because the key is the same it would overwrite the first one. If I change it I would need to update the state file (which I really don't want). How should I approach this problem? Is there any way to tell salt to "merge" the files?
It is possible at least according to the latest Salt documentation about pillar (as of 5188d6c) which states:
With some care, the pillar namespace can merge content from multiple pillar files under a single key, so long as conflicts are avoided ...
I tested it under Salt Helium (2014.7.0) and it's working as expected.
Your Example
Pillar file user_set_a.sls:
users:
joe:
sudouser: True
jack:
sudouser: False
Pillar file user_set_b.sls:
users:
new_user:
sudouser: True
Run pillar.items to confirm that all users are merged under the same users key:
salt-call pillar.items
...
users:
----------
jack:
----------
sudouser:
False
joe:
----------
sudouser:
True
new_user:
----------
sudouser:
True
...
See also:
Example to include pillar files under sub-keys: https://serverfault.com/a/591501/134406
Short answer: you can't merge pillar data in this way.
Long answer: the pillar doesn't support the extend keyword the same way the state tree does, though there is some conversation on salt issue #3991. Unfortunately, there doesn't seem to be any real momentum with this at the moment and I'm not aware of any plans for this to be included in Helium.
Realistically, you'd be better off ensuring that your pillar data is distinct on a per-minion basis, and then you won't need to worry about collisions. You could optionally do something with YAML anchors and references, e.g.
# common/base users.sls
base_users: &base_users
user1:
foo: bar
user2:
baz: bat
# minion1.sls
{% include 'common/base_users.sls' %}
users:
<<: *base_users
user3:
qux: quux
# minion2.sls
{% include 'common/base_users.sls' %}
users:
<<: *base_users
user4:
corge: grault
Another potential (hacky) option is to use an external pillar module and do some sort of glob matching on pillar keys provided to the module, so you could basically have keys like merge-thing-abc123 and merge-thing-def456, using the merge prefix to group by thing and combine the data. I wouldn't really recommend this as it's a pretty blatant antipattern WRT pillar data (not to mention difficult to maintain).
For what it's worth, this is something that also frustrates me occasionally, but I end up deciding that some minimal data duplication is better than coming up with a workaround. Using the YAML references, this could potentially be a more agreeable option since technically you don't need to duplicate data, and is more easily maintainable. Granted, you end up polluting the pillar with extra unused keys (e.g. base_users), but in this particular case I'd consider that acceptable.
Hope this helps!
Edit: I may have spoke too soon; it looks as though includes are parsed prior to being injected into the including file, so anchors/references wouldn't work in that case. Looking into it, will update.
Edit 2: Just occurred to me that since both state and pillar files are essentially Python modules, they can be included with Jinja vs using pillar's include. So, instead of
include:
- common.base_users
you can do
{% include 'common/base_users.sls' %}
and then proceed to reference any anchors defined in the included document. Updated the original answer to illustrate this (verified to work).
The way I got around it is by changing the list values to a dict, for example
/srv/pillar/common/packages.sls
packages:
htop: { pkg=installed }
rsync: { pkg=removed }
wget: { pkg=installed }
/srv/pillar/servers/nycweb01.sls
packages:
nginx: { pkg=installed }
checking this servers pillar items you can see it combined the data from both the common pillar and per-node pillar,
salt-ssh nycweb01 pillar.items
nycweb01:
----------
packages:
----------
htop:
----------
pkg=installed:
None
nginx:
----------
pkg=installed:
None
rsync:
----------
pkg=removed:
None
wget:
----------
pkg=installed:
And from the state file, you can use both the pkg name and the pkg state(installed, removed, etc)

"You cannot define a mapping item when in a sequence" when running phpunit in symfony

I'm getting the following errors when I try to run phpunit on my symfony project:
$ phpunit -c app
1) [...]\DefaultControllerTest::testIndex
Symfony\Component\Config\Exception\FileLoaderLoadException: Cannot import resource "/srv/http/typeform/app/config/config.yml" from "/srv/http/typeform/app/config/config_dev.yml".
/srv/http/typeform/vendor/symfony/src/Symfony/Component/Config/Loader/FileLoader.php:89
[...]
/srv/http/typeform/vendor/symfony/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php:39
/srv/http/typeform/src/QuickyForm/PublicBundle/Tests/Controller/DefaultControllerTest.php:11
Caused by
Symfony\Component\Yaml\Exception\ParseException: You cannot define a mapping item when in a sequence in "\/srv\/http\/typeform\/app\/config\/config.yml"
/usr/share/pear/Symfony/Component/Yaml/Parser.php:116
[...]
/srv/http/typeform/app/bootstrap.php.cache:520
/srv/http/typeform/vendor/symfony/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php:39
/srv/http/typeform/src/QuickyForm/PublicBundle/Tests/Controller/DefaultControllerTest.php:11
It seems that it crash when I call static::createClient();
Here's my config_test.yml
imports:
- { resource: config_dev.yml }
The errors you are getting suggest that the app is failing to parse your 'config.yml' because "You cannot define a mapping item when in a sequence".
This means that in a yml file when defining array values you cannot provide both mapping entries in the form "key: value" and sequence entries in the form "- item" - all values must be either one or the other form.
So, this is ok:
group:
key: value
key: value
This is also ok:
group:
- item
- item
This is not ok:
group:
key: value
- item
The errors suggest that there is an occurrence of the last form in your config.yml, although if this is the case it ought to cause problems running your app in the browser and not just under phpunit.
Additionally, to redbirdo's answer, you should be aware that you might need to use - under the required tag's items. For example:
UserLogin:
type: "object"
required:
- email
- password
security:
basicAuth: [] .......

Resources