Skip to content

Commit

Permalink
Add script which compares two minions
Browse files Browse the repository at this point in the history
Script can be used to compare pillars, highstates and grains for two minions,
or for two different snapshots of the salt states code.

To use it for pull request verification one can:

1) checkout destination branch to dirA,
2) checkout pull-request branch to dirB,
3) setup minion config /opt/minionA/minion to use states and pillars from dirA
4) setup minion config in /opt/minionB/minion to use states and pillars from dirB
5) put the same grains file into /opt/minionA/grains and /opt/minionB/grains
6) run the script

This way you'll get the difference given by the salt states code changes applied to the same minion (i.e. grains input)
  • Loading branch information
bookwar committed Jun 23, 2017
1 parent 97b7c16 commit 55418dc
Showing 1 changed file with 105 additions and 0 deletions.
105 changes: 105 additions & 0 deletions utils/compare_minions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env python

import salt.config
import salt.loader

import json
import json_delta

try:
from colorama import Fore, Back, Style, init
init()
except ImportError: # fallback so that the imported classes always exist
class ColorFallback():
def __getattr__(self, name):
return ''
Fore = Back = Style = ColorFallback()


def color_diff(diff):
"""Colorize lines in the diff generator object"""

for line in diff:
if line.startswith('+'):
yield Fore.GREEN + line + Fore.RESET
elif line.startswith('-'):
yield Fore.RED + line + Fore.RESET
else:
yield line


class Minion():

default_config = '/opt/{name}/minion'

def __init__(self, name=None, config=None, **salt_params):

if not config:
config = self.default_config.format(name=name)
self.config = config

self.salt_params = salt_params

__opts__ = salt.config.minion_config(self.config)
__grains__ = salt.loader.grains(__opts__)
__opts__['grains'] = __grains__
__utils__ = salt.loader.utils(__opts__)
self.salt = salt.loader.minion_mods(__opts__, utils=__utils__)

@property
def highstate(self):
return json.loads(json.dumps(self.salt['state.show_highstate'](**self.salt_params)))

@property
def pillar_items(self):
return json.loads(json.dumps(self.salt['pillar.items'](**self.salt_params)))

@property
def grains_items(self):
return json.loads(json.dumps(self.salt['grains.items']()))

def __str__(self):
return json.dumps(
{
"highstate": self.highstate,
"pillar_items": self.pillar_items,
"grains_items": self.grains_items,
},
indent=4
)


def compare_minions(minionA, minionB):
'''Generate colorized unified diff of two minions'''

comparable_properties = [
'highstate',
'pillar_items',
'grains_items',
]

diffs = {}
for key in comparable_properties:
diffs[key] = color_diff(
json_delta.udiff(
getattr(minionA, key),
getattr(minionB, key),
)
)

result = "\n".join(
[
"\n".join(
[key.upper(), "\n".join(value)]
) for key, value in diffs.items()
]
)
return result


if __name__ == "__main__":

minionA = Minion('minionA')
minionB = Minion('minionB')

print compare_minions(minionA, minionB)

0 comments on commit 55418dc

Please sign in to comment.