Minion not picking up multiple pillar sources - salt-stack

I have a problem where a minion isn't picking up both sources of pillar information, but instead only picking up to the last source referred to. For an example the following is my /srv/pillar/top.sls:
base:
'client.id':
- users.support
- users.dev
The content of my /srv/pillar/users/support.sls is as follows:
users:
- name: supportname
fullname: Name of Support user
uid: 1001
groups:
- sudo
- support
The content of my /srv/pillar/users/dev.sls is as follows:
users:
- name: devname
fullname: Name of Dev user
uid: 1002
groups:
- dev
When calling salt 'client.id' pillar.items it will only show the last specified pillar (for this example, only dev information would be shown). If I was to switch the order the opposite content is shown. I'm really stumped as to what could be causing this.
Any help would be very much appreciated.
Many thanks,
David

Currently, SaltStack has a limited merging strategy for pillars [1]. In your case, the users key is defined as a list. Lists can't be merged in pillars, so the last parsed pillar wins. That's what you see.
However, dicts are merged, provided the keys are different. You may use this for your need:
/srv/pillar/users/support.sls:
users:
supportname:
fullname: Name of Support user
uid: 1001
groups:
- sudo
- support
/srv/pillar/users/dev.sls:
users:
devname:
fullname: Name of Dev user
uid: 1002
groups:
- dev
You'll end with a users dictionary containing two entries: supportname and devname. You can then loop on it with for username, userdef in salt['pillar.get']('users', {}).iteritems(), for example.
[1] https://docs.saltstack.com/en/latest/topics/pillar/#pillar-namespace-merges

Related

JSON API Standard

I have a doubt what is a better option when using json api standard and communication between backend and frontend. I need only one attribute from author association - „username” and other stuff should be hidden for user that fetch this
Case a)
data: [
{
id: „100”,
type: „resource1”,
attributes: {…},
relationships: {author: {data: {id: „10”, type: „author”}}}
}
],
included: [
{
id: „10”,
type: „author”,
attributes: {username: „name”},
relationships: {resources1: {data: [{id: „100”, type: „resource1”}]}}
}
]
Case b)
data: [
{
id: „100”,
type: „resource1”,
attributes: {authorName: „name”, …},
relationships: {author: {data: {id: „10”, type: „author”}}}
}
],
included: []
Case a) looks semantic but there serve much more information in payload
Case b) is faster to get what I want from author (one attribute „username” and this is added in additional attribute: „authorName”), so also don’t need to pleas with associations in frontend side.
Any thoughts which is better practice and why?
Strictly speaking both case a and case b are valid per JSON:API specification.
In case a username is an attribute of author resource. In case b authorName is an attribute of resource1. author resource may have a username attribute in case b as well. In that case you have duplicated state.
I would recommend to only use duplicated state if you have very good reasons. Duplicated state increases complexity - both on server- as well as client-side. Keeping both attributes in sync comes with high costs. E.g. you need to update a client that resource1 changed after a successful update request, which affected the username of author resource. And the client need to parse that response and update the local cache.
There are some reasons, in which duplicating state pays off for good reasons. Calculated values, which would require a client to fetch many resources to calculate them, is a typical example. E.g. you may decide to introduce a averageRating attribute on a product resource because without a client would need to fetch all related ratings of a product only to calculate it.
Trying to reduce payload size is nearly never a good reason to accept the increased complexity. If you consider compressing and package sizes at network level, the raw payload size often doesn't make a big difference.

In Firebase, shall I separate the posts and user data that is updated on a regular basis (favorites, votes...) from the main collection?

I have a basic app that look like a blog, with posts and users data in Firebase. It is coded in React native, Context API state management and TypeScript.
Users have to possibility to add posts in bookmarks, as well as like the posts.
They also have a partner who's bookmarks are visible from the user and have to be updated in real time. This could be managed by a cloud function or duplicated in a document the partner can access.
The informations needed on posts's lists (homepage) are title, imageUrl, bookmark (for the current user), category.
The informations needed on posts pages is the same, plus totalFavorites, liked, totalLikes, contentText, authorName, authorAvatarURL, authorTitle.
I'm trying to understand the pros and the cons of each of these structures:
1/ Monolithic
userData:
- name
- avatarURL
- title # for authors
- bookmarks:
- postId: timestamp
- ...
- partnerBookmarks:
- postId: timestamp
- ...
- likes: [postId, ...]
postData:
- title
- imageUrl
- category
- contentText
- authorRef: user
- totalLikes
- totalFavorites
This is pretty straigtforward but there is several concerns:
I need to be sure that Firestore will not transfert all the userData & postData each time a favorite or a like is added, because this is lots of data that is transfered while it don't change.
The data need to be separated in React Native context whatsoever to avoid rerendering evrything.
2/ Fragmented structure
userData: userUid
- name
- avatarURL
- title # for authors
bookmarks: userUid
- postId: timestamp
- ...
partnerBookmarks: userUid
- postId: timestamp
- ...
likes: userUid
- postId: true
- ...
postData: postId
- title
- category
- imageUrl
- contentText
- authorRef: user
postDataForLists: postId #Could also be generated by a cloud function to avoid duplicating
- title
- imageUrl
- category
postLikes: postId #Here, separating also enable a rule to prevent authors changing these fields.
- totalLikes
- totalFavorites
This structure separate concerns, yet since Firestore charge for each read operation so I'm also questionning it.
I'm new to Firebase and I would love to avoid design errors from the start. Please feel free to commment the structure and ask additional questions if needed.
Thanks
Well, I believe that this depends a lot on the way your app ends up behaving (and how users actually use your app).
But I believe that fragmented structures save up some reads, but ends up needing some composite indexes for specific interactions that you could end up using in your application. I believe that you could clear this inquiry on the cloud firestore documentation and watching the video content that they have over there, maybe it can help you figuring out the best approach for you.

FOS user bundle password validation

I'm trying to set up minimum character count limit for my users' password, using FOS User bundle, whether it is for registration or password reset
I've checked the documentation and searched on github issues / stackoverflow, but nothing is crystal clear to me. It seems that everyone has a different way to do this, and none seems to be matching my case.
First, I checked the documentation: https://symfony.com/doc/current/bundles/FOSUserBundle/overriding_validation.html
So I went to the validation.xml file and changed the plainpassword min size from 2 to 8:
<option name="min">8</option>
Yes, directly in the bundle. It was just to test. But it didn't changed anything
One of the way I found was to put an #Assert regex in the user entity, on the plainPassword field.
https://github.com/FriendsOfSymfony/FOSUserBundle/issues/986
Problem is: my passwords are encrypted, so I don't have any plain password field. Passwords get salted in the usersController upon registration, so this way fo doing is not applicable to my API, I believe.
So how would you achieve this in a quick and rather easy way?
Cheers!
As #IwanWijaya said you can follow the documentation
https://symfony.com/doc/3.3/bundles/override.html
src/Acme/UserBundle/Resources/config/validation.yml
FOS\UserBundle\Model\User:
properties:
plainPassword:
- NotBlank:
groups: [AcmeValidation]
- Length:
min: 6
minMessage: fos_user.password.short
groups: [AcmeValidation]

Making a Salt `onchanges` requisite dependent on what has changed

I want to execute a Salt state not always when changes happened in another state, but only for specific changes. This appears like I would have to make onchanges/onchanges_in dependent on the specific changes.
The respective bug report has been closed saying "this is totally resolved now that states have access to the running dict and the lowstate for a state run". However, I can find no documentation on that and hardly any explanation of what the "running dict" actually is.
So I guess the question could also be rephrased as "How do I access the 'running dict' in an onchanges requisite?", but I'm open to any solutions for the original problem. Thanks for your help!
Update: A comment asked for a specific example, so here is my use case: As most state modules, user.present may either update fields of an existing (user) object or create a new one. Then, I want to run a second state module if and only if a specific field has been changed and/or the object has just been created. In Ansible, for comparison, I would register a variable and access the module's result through it.
So, why would I want to do that?
Essentially, I want to create user accounts on Linux and have them be able to set their own password (when logged in via an SSH key). user.present supports empty_password for that purpose, but it doesn't play nicely with enforce_password. This means that after a password has been manually set, a repeated state run will clear that password again. One might even consider this a bug in Salt, but the interactions between the different user.present fields are convoluted and debatable.
My solution is to create the accounts first and run a module.run state executing shadow.del_password afterwards. This is realised through an onchanges_in requisite. However, password deletion should not be triggered for any change, but only when the user account is created, which is also the only case my user.present state touches the password at all. Otherwise, things like adding users to a group would clear their password. For that effect, I think I would have to look into the details of the user.present change.
Create user account for dummy:
user.present:
- name: dummy
- gid_from_name: True
- remove_groups: False
# TODO: This should be made more specific
- onchanges_in:
- module: Allow dummy to set a password
Allow dummy to set a password:
module.run:
- name: shadow.del_password
- m_name: dummy
# Make sure that this is not executed accidentally if no `onchanges_in` is present
- onchanges: []
- require:
- user: Create user account for dummy
I don't know about specific onchanges or the 'running dict', but, for your particular use case, you can use a condition to enable your password clearing state only when needed, such as:
Create user account for dummy:
user.present:
- name: dummy
- gid_from_name: True
- remove_groups: False
{% if salt['user.info']('dummy') == {} %}
# Only clear the password if the account didn't exist before
Allow dummy to set a password:
module.run:
- name: shadow.del_password
- m_name: dummy
- require:
- user: Create user account for dummy
{% endif %}
I think what you want to use in this case is module.wait, not module.run. module.wait by default will not do anything, unless asked by something else. Also, onchanges_in for some reason (I think this issue) doesn't play well with module.wait for me. I've tried watch_in and it did the job.
I've tried the following code and it seem to work just fine. It creates a user with an empty password and doesn't change anything if user is already there:
Create user account for dummy:
user.present:
- name: dummy
- gid_from_name: True
- remove_groups: False
# TODO: This should be made more specific
- watch_in:
- module: Allow dummy to set a password
Allow dummy to set a password:
module.wait:
- name: shadow.del_password
- m_name: dummy
- require:
- user: Create user account for dummy

SaltStack - map.jinja file cannot match on grain of type dictionary, am I defining grains incorrectly?

I'm using a map.jinja file in a state that uses grains.filter_by, matching on a grain w/ id 'role'. This is used to dynamically set the version of Java that an application uses. I know, weird, but that's how the system I inherited works today, so I'm setting it up as such in configuration management as step 1 to making things better. The map file has no problems at all on hosts with the grain value 'role' being a single item (which I believe is a list in yaml).
Example of the map file:
{% set java = salt['grains.filter_by']({
'default': {
'link_target': '/path/jdk1.7.0_03',
},
'appA': {
'link_target': '/path/jdk1.7.0_75',
},
'appB': {
'link_target': '/path/jdk1.6.0_06',
},
},
grain='role',
default='default'
)%}
Grain values for host w/ a dictionary of role values, I get the error on these hosts:
role:
----------
appA:
None
appC:
None
appD:
----------
someBool:
True
someVendor:
microsoft
someBool2:
False
someVendor2:
apple
type:
delayed
Grain values for hosts without a dictionary for grains, no error:
role:
appB
Error:
Data failed to compile:
----------
Rendering SLS 'base:java' failed: Jinja error: unhashable type: 'dict'
/var/cache/salt/minion/files/base/java/map.jinja(1):
---
{% set java = salt['grains.filter_by']({ <======================
Now, I'm pretty sure this is because my grain value with a dictionary of role values parses into yaml differently than my grain values that are a simple key:value pair.
I'm new to SaltStack and YAML, so I'm likely missing something trivial here. Am I getting too complex with my grain values? Do you have a fix or recommendation on a better way to do this?
Perhaps you should check the documentation of salt.modules.grains again.
So this is what I see :
salt.modules.grains.filter_by(lookup_dict, grain='os_family', merge=None, default='default', base=None)
lookup_dict -- A dictionary, keyed by a grain, containing a value or
values relevant to systems matching that grain. For example, a key
could be the grain for an OS and the value could the name of a package
on that particular OS.
It seems the dictionary value key must be a grain.

Resources