mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 17:33:54 +00:00
Move pillar/pepa.py from develop to 2014.7
This commit is contained in:
parent
8fd9035c5f
commit
df43e60dd2
396
salt/pillar/pepa.py
Executable file → Normal file
396
salt/pillar/pepa.py
Executable file → Normal file
@ -1,15 +1,271 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
'''
|
'''
|
||||||
Configuration templating using Hierarchical substitution and Jinja.
|
Pepa
|
||||||
|
====
|
||||||
|
|
||||||
Documentation: https://github.com/mickep76/pepa
|
Configuration templating for SaltStack using Hierarchical substitution and Jinja.
|
||||||
|
|
||||||
|
Configuring Pepa
|
||||||
|
================
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
extension_modules: /srv/salt/ext
|
||||||
|
|
||||||
|
ext_pillar:
|
||||||
|
- pepa:
|
||||||
|
resource: host # Name of resource directory and sub-key in pillars
|
||||||
|
sequence: # Sequence used for hierarchical substitution
|
||||||
|
- hostname: # Name of key
|
||||||
|
name: input # Alias used for template directory
|
||||||
|
base_only: True # Only use templates from Base environment, i.e. no staging
|
||||||
|
- default:
|
||||||
|
- environment:
|
||||||
|
- location..region:
|
||||||
|
name: region
|
||||||
|
- location..country:
|
||||||
|
name: country
|
||||||
|
- location..datacenter:
|
||||||
|
name: datacenter
|
||||||
|
- roles:
|
||||||
|
- osfinger:
|
||||||
|
name: os
|
||||||
|
- hostname:
|
||||||
|
name: override
|
||||||
|
base_only: True
|
||||||
|
subkey: True # Create a sub-key in pillars, named after the resource in this case [host]
|
||||||
|
subkey_only: True # Only create a sub-key, and leave the top level untouched
|
||||||
|
|
||||||
|
pepa_roots: # Base directory for each environment
|
||||||
|
base: /srv/pepa/base # Path for base environment
|
||||||
|
dev: /srv/pepa/base # Associate dev with base
|
||||||
|
qa: /srv/pepa/qa
|
||||||
|
prod: /srv/pepa/prod
|
||||||
|
|
||||||
|
# Use a different delimiter for nested dictionaries, defaults to '..' since some keys may use '.' in the name
|
||||||
|
#pepa_delimiter: ..
|
||||||
|
|
||||||
|
# Supply Grains for Pepa, this should **ONLY** be used for testing or validation
|
||||||
|
#pepa_grains:
|
||||||
|
# environment: dev
|
||||||
|
|
||||||
|
# Supply Pillar for Pepa, this should **ONLY** be used for testing or validation
|
||||||
|
#pepa_pillars:
|
||||||
|
# saltversion: 0.17.4
|
||||||
|
|
||||||
|
# Enable debug for Pepa, and keep Salt on warning
|
||||||
|
#log_level: debug
|
||||||
|
|
||||||
|
#log_granular_levels:
|
||||||
|
# salt: warning
|
||||||
|
# salt.loaded.ext.pillar.pepa: debug
|
||||||
|
|
||||||
|
Pepa can also be used in Master-less SaltStack setup.
|
||||||
|
|
||||||
|
Command line
|
||||||
|
============
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
usage: pepa.py [-h] [-c CONFIG] [-d] [-g GRAINS] [-p PILLAR] [-n] [-v]
|
||||||
|
hostname
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
hostname Hostname
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-c CONFIG, --config CONFIG
|
||||||
|
Configuration file
|
||||||
|
-d, --debug Print debug info
|
||||||
|
-g GRAINS, --grains GRAINS
|
||||||
|
Input Grains as YAML
|
||||||
|
-p PILLAR, --pillar PILLAR
|
||||||
|
Input Pillar as YAML
|
||||||
|
-n, --no-color No color output
|
||||||
|
-v, --validate Validate output
|
||||||
|
|
||||||
|
Templates
|
||||||
|
=========
|
||||||
|
|
||||||
|
Templates is configuration for a host or software, that can use information from Grains or Pillars. These can then be used for hierarchically substitution.
|
||||||
|
|
||||||
|
**Example File:** host/input/test_example_com.yaml
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
location..region: emea
|
||||||
|
location..country: nl
|
||||||
|
location..datacenter: foobar
|
||||||
|
environment: dev
|
||||||
|
roles:
|
||||||
|
- salt.master
|
||||||
|
network..gateway: 10.0.0.254
|
||||||
|
network..interfaces..eth0..hwaddr: 00:20:26:a1:12:12
|
||||||
|
network..interfaces..eth0..dhcp: False
|
||||||
|
network..interfaces..eth0..ipv4: 10.0.0.3
|
||||||
|
network..interfaces..eth0..netmask: 255.255.255.0
|
||||||
|
network..interfaces..eth0..fqdn: {{ hostname }}
|
||||||
|
cobbler..profile: fedora-19-x86_64
|
||||||
|
|
||||||
|
As you see in this example you can use Jinja directly inside the template.
|
||||||
|
|
||||||
|
**Example File:** host/region/amer.yaml
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
network..dns..servers:
|
||||||
|
- 10.0.0.1
|
||||||
|
- 10.0.0.2
|
||||||
|
time..ntp..servers:
|
||||||
|
- ntp1.amer.example.com
|
||||||
|
- ntp2.amer.example.com
|
||||||
|
- ntp3.amer.example.com
|
||||||
|
time..timezone: America/Chihuahua
|
||||||
|
yum..mirror: yum.amer.example.com
|
||||||
|
|
||||||
|
Each template is named after the value of the key using lowercase and all extended characters are replaced with underscore.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
osfinger: Fedora-19
|
||||||
|
|
||||||
|
**Would become:**
|
||||||
|
|
||||||
|
fedora_19.yaml
|
||||||
|
|
||||||
|
Nested dictionaries
|
||||||
|
===================
|
||||||
|
|
||||||
|
In order to create nested dictionaries as output you can use double dot **".."** as a delimiter. You can change this using "pepa_delimiter" we choose double dot since single dot is already used by key names in some modules, and using ":" requires quoting in the YAML.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
network..dns..servers:
|
||||||
|
- 10.0.0.1
|
||||||
|
- 10.0.0.2
|
||||||
|
network..dns..options:
|
||||||
|
- timeout:2
|
||||||
|
- attempts:1
|
||||||
|
- ndots:1
|
||||||
|
network..dns..search:
|
||||||
|
- example.com
|
||||||
|
|
||||||
|
**Would become:**
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
network:
|
||||||
|
dns:
|
||||||
|
servers:
|
||||||
|
- 10.0.0.1
|
||||||
|
- 10.0.0.2
|
||||||
|
options:
|
||||||
|
- timeout:2
|
||||||
|
- attempts:1
|
||||||
|
- ndots:1
|
||||||
|
search:
|
||||||
|
- example.com
|
||||||
|
|
||||||
|
Operators
|
||||||
|
=========
|
||||||
|
|
||||||
|
Operators can be used to merge/unset a list/hash or set the key as immutable, so it can't be changed.
|
||||||
|
|
||||||
|
=========== ================================================
|
||||||
|
Operator Description
|
||||||
|
=========== ================================================
|
||||||
|
merge() Merge list or hash
|
||||||
|
unset() Unset key
|
||||||
|
immutable() Set the key as immutable, so it can't be changed
|
||||||
|
imerge() Set immutable and merge
|
||||||
|
iunset() Set immutable and unset
|
||||||
|
=========== ================================================
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
network..dns..search..merge():
|
||||||
|
- foobar.com
|
||||||
|
- dummy.nl
|
||||||
|
owner..immutable(): Operations
|
||||||
|
host..printers..unset():
|
||||||
|
|
||||||
|
Validation
|
||||||
|
==========
|
||||||
|
|
||||||
|
Since it's very hard to test Jinja as is, the best approach is to run all the permutations of input and validate the output, i.e. Unit Testing.
|
||||||
|
|
||||||
|
To facilitate this in Pepa we use YAML, Jinja and Cerberus <https://github.com/nicolaiarocci/cerberus>.
|
||||||
|
|
||||||
|
Schema
|
||||||
|
======
|
||||||
|
|
||||||
|
So this is a validation schema for network configuration, as you see it can be customized with Jinja just as Pepa templates.
|
||||||
|
|
||||||
|
This was designed to be run as a build job in Jenkins or similar tool. You can provide Grains/Pillar input using either the config file or command line arguments.
|
||||||
|
|
||||||
|
**File Example: host/validation/network.yaml**
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
network..dns..search:
|
||||||
|
type: list
|
||||||
|
allowed:
|
||||||
|
- example.com
|
||||||
|
|
||||||
|
network..dns..options:
|
||||||
|
type: list
|
||||||
|
allowed: ['timeout:2', 'attempts:1', 'ndots:1']
|
||||||
|
|
||||||
|
network..dns..servers:
|
||||||
|
type: list
|
||||||
|
schema:
|
||||||
|
regex: ^([0-9]{1,3}\\.){3}[0-9]{1,3}$
|
||||||
|
|
||||||
|
network..gateway:
|
||||||
|
type: string
|
||||||
|
regex: ^([0-9]{1,3}\\.){3}[0-9]{1,3}$
|
||||||
|
|
||||||
|
{% if network.interfaces is defined %}
|
||||||
|
{% for interface in network.interfaces %}
|
||||||
|
|
||||||
|
network..interfaces..{{ interface }}..dhcp:
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
network..interfaces..{{ interface }}..fqdn:
|
||||||
|
type: string
|
||||||
|
regex: ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-zA-Z]{2,6}$
|
||||||
|
|
||||||
|
network..interfaces..{{ interface }}..hwaddr:
|
||||||
|
type: string
|
||||||
|
regex: ^([0-9a-f]{1,2}\\:){5}[0-9a-f]{1,2}$
|
||||||
|
|
||||||
|
network..interfaces..{{ interface }}..ipv4:
|
||||||
|
type: string
|
||||||
|
regex: ^([0-9]{1,3}\\.){3}[0-9]{1,3}$
|
||||||
|
|
||||||
|
network..interfaces..{{ interface }}..netmask:
|
||||||
|
type: string
|
||||||
|
regex: ^([0-9]{1,3}\\.){3}[0-9]{1,3}$
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
Links
|
||||||
|
=====
|
||||||
|
|
||||||
|
For more examples and information see <https://github.com/mickep76/pepa>.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
__author__ = 'Michael Persson <michael.ake.persson@gmail.com>'
|
__author__ = 'Michael Persson <michael.ake.persson@gmail.com>'
|
||||||
__copyright__ = 'Copyright (c) 2013 Michael Persson'
|
__copyright__ = 'Copyright (c) 2013 Michael Persson'
|
||||||
__license__ = 'Apache License, Version 2.0'
|
__license__ = 'Apache License, Version 2.0'
|
||||||
__version__ = '0.6.4'
|
__version__ = '0.6.6'
|
||||||
|
|
||||||
# Import python libs
|
# Import python libs
|
||||||
import logging
|
import logging
|
||||||
@ -18,7 +274,7 @@ import glob
|
|||||||
import yaml
|
import yaml
|
||||||
import jinja2
|
import jinja2
|
||||||
import re
|
import re
|
||||||
|
from os.path import isfile, join
|
||||||
|
|
||||||
# Only used when called from a terminal
|
# Only used when called from a terminal
|
||||||
log = None
|
log = None
|
||||||
@ -32,6 +288,11 @@ if __name__ == '__main__':
|
|||||||
parser.add_argument('-g', '--grains', help='Input Grains as YAML')
|
parser.add_argument('-g', '--grains', help='Input Grains as YAML')
|
||||||
parser.add_argument('-p', '--pillar', help='Input Pillar as YAML')
|
parser.add_argument('-p', '--pillar', help='Input Pillar as YAML')
|
||||||
parser.add_argument('-n', '--no-color', action='store_true', help='No color output')
|
parser.add_argument('-n', '--no-color', action='store_true', help='No color output')
|
||||||
|
parser.add_argument('-v', '--validate', action='store_true', help='Validate output')
|
||||||
|
parser.add_argument('-q', '--query-api', action='store_true', help='Query Saltstack REST API for Grains')
|
||||||
|
parser.add_argument('--url', default='https://salt:8000', help='URL for SaltStack REST API')
|
||||||
|
parser.add_argument('-u', '--username', help='Username for SaltStack REST API')
|
||||||
|
parser.add_argument('-P', '--password', help='Password for SaltStack REST API')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
LOG_LEVEL = logging.WARNING
|
LOG_LEVEL = logging.WARNING
|
||||||
@ -64,23 +325,15 @@ __opts__ = {
|
|||||||
'pepa_roots': {
|
'pepa_roots': {
|
||||||
'base': '/srv/salt'
|
'base': '/srv/salt'
|
||||||
},
|
},
|
||||||
'pepa_delimiter': '..'
|
'pepa_delimiter': '..',
|
||||||
|
'pepa_validate': False
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
|
||||||
from os.path import isfile, join
|
|
||||||
HAS_OS_PATH = True
|
|
||||||
except ImportError:
|
|
||||||
HAS_OS_PATH = False
|
|
||||||
|
|
||||||
|
|
||||||
def __virtual__():
|
def __virtual__():
|
||||||
'''
|
'''
|
||||||
Only return if all the modules are available
|
Only return if all the modules are available
|
||||||
'''
|
'''
|
||||||
if not HAS_OS_PATH:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@ -150,16 +403,24 @@ def ext_pillar(minion_id, pillar, resource, sequence, subkey=False, subkey_only=
|
|||||||
entries = [inp[categ]]
|
entries = [inp[categ]]
|
||||||
|
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
|
results_jinja = None
|
||||||
results = None
|
results = None
|
||||||
fn = join(templdir, re.sub(r'\W', '_', entry.lower()) + '.yaml')
|
fn = join(templdir, re.sub(r'\W', '_', entry.lower()) + '.yaml')
|
||||||
if isfile(fn):
|
if isfile(fn):
|
||||||
log.info("Loading template: {0}".format(fn))
|
log.info("Loading template: {0}".format(fn))
|
||||||
template = jinja2.Template(open(fn).read())
|
template = jinja2.Template(open(fn).read())
|
||||||
output['pepa_templates'].append(fn)
|
output['pepa_templates'].append(fn)
|
||||||
data = key_value_to_tree(output)
|
|
||||||
data['grains'] = __grains__.copy()
|
try:
|
||||||
data['pillar'] = pillar.copy()
|
data = key_value_to_tree(output)
|
||||||
results = yaml.load(template.render(data))
|
data['grains'] = __grains__.copy()
|
||||||
|
data['pillar'] = pillar.copy()
|
||||||
|
results_jinja = template.render(data)
|
||||||
|
results = yaml.load(results_jinja)
|
||||||
|
except jinja2.UndefinedError, err:
|
||||||
|
log.error('Failed to parse JINJA template: {0}\n{1}'.format(fn, err))
|
||||||
|
except yaml.YAMLError, err:
|
||||||
|
log.error('Failed to parse YAML in template: {0}\n{1}'.format(fn, err))
|
||||||
else:
|
else:
|
||||||
log.info("Template doesn't exist: {0}".format(fn))
|
log.info("Template doesn't exist: {0}".format(fn))
|
||||||
continue
|
continue
|
||||||
@ -177,46 +438,36 @@ def ext_pillar(minion_id, pillar, resource, sequence, subkey=False, subkey_only=
|
|||||||
log.warning('Key {0} is immutable, changes are not allowed'.format(key))
|
log.warning('Key {0} is immutable, changes are not allowed'.format(key))
|
||||||
elif rkey in immutable:
|
elif rkey in immutable:
|
||||||
log.warning("Key {0} is immutable, changes are not allowed".format(rkey))
|
log.warning("Key {0} is immutable, changes are not allowed".format(rkey))
|
||||||
elif operator == 'merge()':
|
elif operator == 'merge()' or operator == 'imerge()':
|
||||||
log.debug("Merge key {0}: {1}".format(rkey, results[key]))
|
if operator == 'merge()':
|
||||||
if rkey in output and type(results[key]) != type(output[rkey]):
|
log.debug("Merge key {0}: {1}".format(rkey, results[key]))
|
||||||
log.warning('You can''t merge different types for key {0}'.format(rkey))
|
else:
|
||||||
|
log.debug("Set immutable and merge key {0}: {1}".format(rkey, results[key]))
|
||||||
|
immutable[rkey] = True
|
||||||
|
if rkey not in output:
|
||||||
|
log.error('Cant\'t merge key {0} doesn\'t exist'.format(rkey))
|
||||||
|
elif type(results[key]) != type(output[rkey]):
|
||||||
|
log.error('Can\'t merge different types for key {0}'.format(rkey))
|
||||||
elif type(results[key]) is dict:
|
elif type(results[key]) is dict:
|
||||||
output[rkey].update(results[key])
|
output[rkey].update(results[key])
|
||||||
elif type(results[key]) is list:
|
elif type(results[key]) is list:
|
||||||
output[rkey].extend(results[key])
|
output[rkey].extend(results[key])
|
||||||
else:
|
else:
|
||||||
log.warning('Unsupported type need to be list or dict for key {0}'.format(rkey))
|
log.error('Unsupported type need to be list or dict for key {0}'.format(rkey))
|
||||||
elif operator == 'unset()':
|
elif operator == 'unset()' or operator == 'iunset()':
|
||||||
log.debug("Unset key {0}".format(rkey))
|
if operator == 'unset()':
|
||||||
try:
|
log.debug("Unset key {0}".format(rkey))
|
||||||
|
else:
|
||||||
|
log.debug("Set immutable and unset key {0}".format(rkey))
|
||||||
|
immutable[rkey] = True
|
||||||
|
if rkey in output:
|
||||||
del output[rkey]
|
del output[rkey]
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
elif operator == 'immutable()':
|
elif operator == 'immutable()':
|
||||||
log.debug("Set immutable and substitute key {0}: {1}".format(rkey, results[key]))
|
log.debug("Set immutable and substitute key {0}: {1}".format(rkey, results[key]))
|
||||||
immutable[rkey] = True
|
immutable[rkey] = True
|
||||||
output[rkey] = results[key]
|
output[rkey] = results[key]
|
||||||
elif operator == 'imerge()':
|
|
||||||
log.debug("Set immutable and merge key {0}: {1}".format(rkey, results[key]))
|
|
||||||
immutable[rkey] = True
|
|
||||||
if rkey in output and type(results[key]) != type(output[rkey]):
|
|
||||||
log.warning('You can''t merge different types for key {0}'.format(rkey))
|
|
||||||
elif type(results[key]) is dict:
|
|
||||||
output[rkey].update(results[key])
|
|
||||||
elif type(results[key]) is list:
|
|
||||||
output[rkey].extend(results[key])
|
|
||||||
else:
|
|
||||||
log.warning('Unsupported type need to be list or dict for key {0}'.format(rkey))
|
|
||||||
elif operator == 'iunset()':
|
|
||||||
log.debug("Set immutable and unset key {0}".format(rkey))
|
|
||||||
immutable[rkey] = True
|
|
||||||
try:
|
|
||||||
del output[rkey]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
elif operator is not None:
|
elif operator is not None:
|
||||||
log.warning('Unsupported operator {0}, skipping key {1}'.format(operator, rkey))
|
log.error('Unsupported operator {0}, skipping key {1}'.format(operator, rkey))
|
||||||
else:
|
else:
|
||||||
log.debug("Substitute key {0}: {1}".format(key, results[key]))
|
log.debug("Substitute key {0}: {1}".format(key, results[key]))
|
||||||
output[key] = results[key]
|
output[key] = results[key]
|
||||||
@ -230,6 +481,8 @@ def ext_pillar(minion_id, pillar, resource, sequence, subkey=False, subkey_only=
|
|||||||
pillar_data[resource] = tree.copy()
|
pillar_data[resource] = tree.copy()
|
||||||
else:
|
else:
|
||||||
pillar_data = tree
|
pillar_data = tree
|
||||||
|
if __opts__['pepa_validate']:
|
||||||
|
pillar_data['pepa_keys'] = output.copy()
|
||||||
return pillar_data
|
return pillar_data
|
||||||
|
|
||||||
|
|
||||||
@ -298,8 +551,55 @@ if __name__ == '__main__':
|
|||||||
if args.pillar:
|
if args.pillar:
|
||||||
__pillar__.update(yaml.load(args.pillar))
|
__pillar__.update(yaml.load(args.pillar))
|
||||||
|
|
||||||
|
# Validate or not
|
||||||
|
if args.validate:
|
||||||
|
__opts__['pepa_validate'] = True
|
||||||
|
|
||||||
|
if args.query_api:
|
||||||
|
import requests
|
||||||
|
import getpass
|
||||||
|
|
||||||
|
username = args.username
|
||||||
|
password = args.password
|
||||||
|
if username is None:
|
||||||
|
username = raw_input('Username: ')
|
||||||
|
if password is None:
|
||||||
|
password = getpass.getpass()
|
||||||
|
|
||||||
|
log.info('Authenticate REST API')
|
||||||
|
auth = {'username': username, 'password': password, 'eauth': 'pam'}
|
||||||
|
request = requests.post(args.url + '/login', auth)
|
||||||
|
|
||||||
|
if not request.ok:
|
||||||
|
raise RuntimeError('Failed to authenticate to SaltStack REST API: {0}'.format(request.text))
|
||||||
|
|
||||||
|
response = request.json()
|
||||||
|
token = response['return'][0]['token']
|
||||||
|
|
||||||
|
log.info('Request Grains from REST API')
|
||||||
|
headers = {'X-Auth-Token': token, 'Accept': 'application/json'}
|
||||||
|
request = requests.get(args.url + '/minions/' + args.hostname, headers=headers)
|
||||||
|
|
||||||
|
result = request.json().get('return', [{}])[0]
|
||||||
|
if args.hostname not in result:
|
||||||
|
raise RuntimeError('Failed to get Grains from SaltStack REST API')
|
||||||
|
|
||||||
|
__grains__ = result[args.hostname]
|
||||||
|
# print yaml.safe_dump(__grains__, indent=4, default_flow_style=False)
|
||||||
|
|
||||||
# Print results
|
# Print results
|
||||||
result = ext_pillar(args.hostname, __pillar__, __opts__['ext_pillar'][loc]['pepa']['resource'], __opts__['ext_pillar'][loc]['pepa']['sequence'])
|
ex_subkey = False
|
||||||
|
ex_subkey_only = False
|
||||||
|
if 'subkey' in __opts__['ext_pillar'][loc]['pepa']:
|
||||||
|
ex_subkey = __opts__['ext_pillar'][loc]['pepa']['subkey']
|
||||||
|
if 'subkey_only' in __opts__['ext_pillar'][loc]['pepa']:
|
||||||
|
ex_subkey_only = __opts__['ext_pillar'][loc]['pepa']['subkey_only']
|
||||||
|
|
||||||
|
result = ext_pillar(args.hostname, __pillar__, __opts__['ext_pillar'][loc]['pepa']['resource'],
|
||||||
|
__opts__['ext_pillar'][loc]['pepa']['sequence'], ex_subkey, ex_subkey_only)
|
||||||
|
|
||||||
|
if __opts__['pepa_validate']:
|
||||||
|
validate(result, __opts__['ext_pillar'][loc]['pepa']['resource'])
|
||||||
|
|
||||||
yaml.dumper.SafeDumper.ignore_aliases = lambda self, data: True
|
yaml.dumper.SafeDumper.ignore_aliases = lambda self, data: True
|
||||||
if not args.no_color:
|
if not args.no_color:
|
||||||
|
Loading…
Reference in New Issue
Block a user