Salt: Order in top.sls file is not respected for pillar data in local mode

Created on 8 Jun 2015  路  25Comments  路  Source: saltstack/salt

My pillar setup looks like this:

In the minion.conf the pillar_roots config looks like this:

pillar_roots:
  lib:
    - /srv/salt/salt-lib/pillar
  base:
    - /srv/salt/pillar

My pillar top.sls file in /srv/salt/pillar/top.sls looks like this:

lib:
  '*':
    - main

base:
  '*':
    - basic

The main.sls file in /srv/salt/salt-lib/pillar/ contains:

test:
  setting: myvalue-main

The basic.sls file in /srv/salt/pillar/ contains:

test:
  setting: myvalue-override

When I now run

sudo salt-call --local pillar.get test:setting

the output is:

local:
    myvalue-main

The expected output would be:

local:
    myvalue-override

The salt version is 2014.7.1

Is this related to #1432 ?

Aluminium Bug CS-R2 CS-S2 Core Pillar ZD phase-execute severity-medium status-to-do

Most helpful comment

Any idea when this will get fixed? It was marked bug, high severity 2.5 years ago.
It would immensely simplify many of my pillars if this worked.

All 25 comments

@astehlik, does this also happen on 2015.5.2?

Just tested it with 2015.5.2, the value is still not overwritten :(

Have you changed the value of pillar_source_merging_strategy in the master config? I think the default might not do what you want. You could try pillar_source_merging_strategy: overwrite. http://docs.saltstack.com/en/latest/ref/configuration/master.html#pillar-source-merging-strategy

I have the same issue, but I think this is a known issue since the documentation says "Remember: conflicting keys will be overwritten in a non-deterministic manner!": http://docs.saltstack.com/en/develop/topics/pillar/index.html#pillar-namespace-merges

It would be great if the order could be preserved when pillar files are read and merged so that conflicting keys will be overwritten in a deterministic manner (last wins).

@jfindlay I tried the settings pillar_source_merging_strategy with the default smart setting and the overwrite setting. The result is still myvalue-main.

I looked at 2015.5.5 and 2015.8.0 and the result is the same.

The source of the problem seems to be preserving the order of environments in pillar/__init__.py: It starts out with self._get_envs() returning a standard set of environments defined as the pillars in pillar_root, and continues throughout the file with collections.defaultdict, for example in merge_tops(). While the pillars within each environment are ordered, the environments themselves are not ordered.

The behaviour I would expect: A deterministic order of the top files to be read (as listed in pillar_roots?), and then processing the environments as listed in each top file.

My workaround is now to have an external pillar to override values, as all external pillars override pillar_roots as a default (unless ext_pillar_first is specified). Any external pillar will do:

ext_pillar:
  - cmd_yaml:
      command: cat /srv/salt/pillar/basic.sls

@ahus1, thanks for the info.

Just to clarify not only a problem in local mode.

As @ahus1 points out it has to do with dict usages instead of ordereddict.

So #19332 with the comment that order is as declared is only true within an environment.

Use-case:
Single pillar top.sls
last environment is called vagrant and has a grain matching on virtual:VirtualBox
when pillar is rendered the prod environment is rendered last and overwrites the vagrant pillar data.

For my use-case changing 3 dict to ordereddict got my desired behaviour.

ZD-2198

Any idea when this will get fixed? It was marked bug, high severity 2.5 years ago.
It would immensely simplify many of my pillars if this worked.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

If this issue is closed prematurely, please leave a comment and we will gladly reopen the issue.

This shouldn't be closed. The problem still exists. It would make pillar data management much easier.

@whytewolf Can you reopen please.

@notpeter @wwalker I can reopen. I must have missed the stalebot email last month.

Thank you for updating this issue. It is no longer marked as stale.

Thank you for updating this issue. It is no longer marked as stale.

https://docs.saltstack.com/en/latest/topics/pillar/#pillar-namespace-flattening

Implies that merging would work. The example doesn't say that it is non-deterministic if both dictionaries contain the same key.

Can we add a note in the mean time to the docs?

@barbaricyawps let's look at a doc change here.

@sagetherage a doc fix is a good first step and a stopgap. Is there any way to actually get the code to be deterministic?

Coming up on 5 years, seems like we should have something better than a doc fix. :(

the doc fix is only a portion yes, but something that may be done by a separate person so was asking, merely

There are several things going on here and the team needs to research what exactly is happening now, we can only commit to the research for now.

This patch seems to fix the pillar order problem for me on 2019.2.7. Based on https://github.com/saltstack/salt/pull/37190/commits/59657b12eb0f2a9d03891260b531036eb066c175

--- salt/pillar/__init__.py.orig    2020-12-30 13:31:20.840940457 -0800
+++ salt/pillar/__init__.py 2020-12-30 13:34:18.585825693 -0800
@@ -498,9 +498,10 @@ class Pillar(object):
         '''
         Pull the file server environments out of the master options
         '''
-        envs = set(['base'])
+        envs = ['base']
         if 'pillar_roots' in self.opts:
-            envs.update(list(self.opts['pillar_roots']))
+            envs.extend([x for x in list(self.opts['pillar_roots'])
+                          if x not in envs])
         return envs

     def get_tops(self):

@mkirkland4874 Thanks! Looks like a good fix. Want to take a stab at a PR?

I can do that. The above patch is for the 2019.2 branch--would you actually pull that into 2019.2 or do you want a master branch patch. __get_envs_ in master seems to be slightly different (i.e., _envs = set(['base'])_ in 2019.2 is _envs = {"base"}_ in master)

@mkirkland4874 against the master branch please.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

j0nes2k picture j0nes2k  路  52Comments

chrismoos picture chrismoos  路  54Comments

Deshke picture Deshke  路  60Comments

tjyang picture tjyang  路  98Comments

sjorge picture sjorge  路  73Comments