mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
pillar_ldap: Fix cryptic errors when config file fails to load
This fixes an UnboundLocalError when the jinja templating or yaml loading fails. It also re-adds some previously-deleted crucial documentation regarding the `search_order` option. Finally, it fixes some incorrectly-formatted RST and makes the result a example python data structure. We still need "split mode" documentation, but this was left undone with a TODO telling the user to reference a docstring that isn't visible in the docs.
This commit is contained in:
parent
65c3ba7ff1
commit
0175a8687c
1 changed files with 99 additions and 60 deletions
|
@ -50,60 +50,76 @@ possible to reference grains within the configuration.
|
|||
to trick the master into returning secret data.
|
||||
Use only the 'id' grain which is verified through the minion's key/cert.
|
||||
|
||||
|
||||
Map Mode
|
||||
--------
|
||||
|
||||
The ``it-admins`` configuration below returns the Pillar ``it-admins`` by:
|
||||
|
||||
- filtering for:
|
||||
- members of the group ``it-admins``
|
||||
- objects with ``objectclass=user``
|
||||
- returning the data of users (``mode: map``), where each user is a dictionary
|
||||
containing the configured string or list attributes.
|
||||
- members of the group ``it-admins``
|
||||
- objects with ``objectclass=user``
|
||||
- returning the data of users, where each user is a dictionary containing the
|
||||
configured string or list attributes.
|
||||
|
||||
**Configuration:**
|
||||
|
||||
Configuration
|
||||
*************
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
salt-users:
|
||||
server: ldap.company.tld
|
||||
port: 389
|
||||
tls: true
|
||||
dn: 'dc=company,dc=tld'
|
||||
binddn: 'cn=salt-pillars,ou=users,dc=company,dc=tld'
|
||||
bindpw: bi7ieBai5Ano
|
||||
referrals: false
|
||||
anonymous: false
|
||||
mode: map
|
||||
dn: 'ou=users,dc=company,dc=tld'
|
||||
filter: '(&(memberof=cn=it-admins,ou=groups,dc=company,dc=tld)(objectclass=user))'
|
||||
attrs:
|
||||
- cn
|
||||
- displayName
|
||||
- givenName
|
||||
- sn
|
||||
lists:
|
||||
- memberOf
|
||||
server: ldap.company.tld
|
||||
port: 389
|
||||
tls: true
|
||||
dn: 'dc=company,dc=tld'
|
||||
binddn: 'cn=salt-pillars,ou=users,dc=company,dc=tld'
|
||||
bindpw: bi7ieBai5Ano
|
||||
referrals: false
|
||||
anonymous: false
|
||||
mode: map
|
||||
dn: 'ou=users,dc=company,dc=tld'
|
||||
filter: '(&(memberof=cn=it-admins,ou=groups,dc=company,dc=tld)(objectclass=user))'
|
||||
attrs:
|
||||
- cn
|
||||
- displayName
|
||||
- givenName
|
||||
- sn
|
||||
lists:
|
||||
- memberOf
|
||||
|
||||
**Result:**
|
||||
search_order:
|
||||
- salt-users
|
||||
|
||||
.. code-block:: yaml
|
||||
Result
|
||||
******
|
||||
|
||||
salt-users:
|
||||
- cn: cn=johndoe,ou=users,dc=company,dc=tld
|
||||
displayName: John Doe
|
||||
givenName: John
|
||||
sn: Doe
|
||||
memberOf:
|
||||
- cn=it-admins,ou=groups,dc=company,dc=tld
|
||||
- cn=team01,ou=groups,dc=company
|
||||
- cn: cn=janedoe,ou=users,dc=company,dc=tld
|
||||
displayName: Jane Doe
|
||||
givenName: Jane
|
||||
sn: Doe
|
||||
memberOf:
|
||||
- cn=it-admins,ou=groups,dc=company,dc=tld
|
||||
- cn=team02,ou=groups,dc=company
|
||||
.. code-block:: python
|
||||
|
||||
{
|
||||
'salt-users': [
|
||||
{
|
||||
'cn': 'cn=johndoe,ou=users,dc=company,dc=tld',
|
||||
'displayName': 'John Doe'
|
||||
'givenName': 'John'
|
||||
'sn': 'Doe'
|
||||
'memberOf': [
|
||||
'cn=it-admins,ou=groups,dc=company,dc=tld',
|
||||
'cn=team01,ou=groups,dc=company'
|
||||
]
|
||||
},
|
||||
{
|
||||
'cn': 'cn=janedoe,ou=users,dc=company,dc=tld',
|
||||
'displayName': 'Jane Doe',
|
||||
'givenName': 'Jane',
|
||||
'sn': 'Doe',
|
||||
'memberOf': [
|
||||
'cn=it-admins,ou=groups,dc=company,dc=tld',
|
||||
'cn=team02,ou=groups,dc=company'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
|
@ -117,7 +133,7 @@ from salt.exceptions import SaltInvocationError
|
|||
|
||||
# Import third party libs
|
||||
import yaml
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
import jinja2
|
||||
try:
|
||||
import ldap # pylint: disable=W0611
|
||||
HAS_LDAP = True
|
||||
|
@ -143,10 +159,9 @@ def _render_template(config_file):
|
|||
Render config template, substituting grains where found.
|
||||
'''
|
||||
dirname, filename = os.path.split(config_file)
|
||||
env = Environment(loader=FileSystemLoader(dirname))
|
||||
env = jinja2.Environment(loader=jinja2.FileSystemLoader(dirname))
|
||||
template = env.get_template(filename)
|
||||
config = template.render(__grains__)
|
||||
return config
|
||||
return template.render(__grains__)
|
||||
|
||||
|
||||
def _config(name, conf):
|
||||
|
@ -180,18 +195,18 @@ def _result_to_dict(data, result, conf, source):
|
|||
For example, search result:
|
||||
|
||||
{ saltKeyValue': ['ntpserver=ntp.acme.local', 'foo=myfoo'],
|
||||
'saltList': ['vhost=www.acme.net', 'vhost=www.acme.local' }
|
||||
'saltList': ['vhost=www.acme.net', 'vhost=www.acme.local'] }
|
||||
|
||||
is written to the pillar data dictionary as:
|
||||
|
||||
{ 'ntpserver': 'ntp.acme.local', 'foo': 'myfoo',
|
||||
'vhost': ['www.acme.net', 'www.acme.local' }
|
||||
'vhost': ['www.acme.net', 'www.acme.local'] }
|
||||
'''
|
||||
attrs = _config('attrs', conf) or []
|
||||
lists = _config('lists', conf) or []
|
||||
# TODO:
|
||||
# deprecate the default 'mode: split' and make the more
|
||||
# straightforward 'mode: dict' the new default
|
||||
# straightforward 'mode: map' the new default
|
||||
mode = _config('mode', conf) or 'split'
|
||||
if mode == 'map':
|
||||
data[source] = []
|
||||
|
@ -271,20 +286,44 @@ def ext_pillar(minion_id, # pylint: disable=W0613
|
|||
'''
|
||||
Execute LDAP searches and return the aggregated data
|
||||
'''
|
||||
if os.path.isfile(config_file):
|
||||
try:
|
||||
config = _render_template(config_file) or {}
|
||||
opts = yaml.safe_load(config) or {}
|
||||
opts['conf_file'] = config_file
|
||||
except Exception as err:
|
||||
import salt.log
|
||||
msg = 'Error parsing configuration file: {0} - {1}'
|
||||
if salt.log.is_console_configured():
|
||||
log.warning(msg.format(config_file, err))
|
||||
else:
|
||||
print(msg.format(config_file, err))
|
||||
config_template = None
|
||||
try:
|
||||
config_template = _render_template(config_file)
|
||||
except jinja2.exceptions.TemplateNotFound:
|
||||
log.debug('pillar_ldap: missing configuration file %s', config_file)
|
||||
except Exception:
|
||||
log.debug('pillar_ldap: failed to render template for %s',
|
||||
config_file, exc_info=True)
|
||||
|
||||
if not config_template:
|
||||
# We don't have a config file
|
||||
return {}
|
||||
|
||||
try:
|
||||
opts = yaml.safe_load(config_template) or {}
|
||||
opts['conf_file'] = config_file
|
||||
except Exception as err:
|
||||
import salt.log
|
||||
msg = 'pillar_ldap: error parsing configuration file: {0} - {1}'
|
||||
if salt.log.is_console_configured():
|
||||
log.warning(msg.format(config_file, err))
|
||||
else:
|
||||
print(msg.format(config_file, err))
|
||||
return {}
|
||||
else:
|
||||
log.debug('Missing configuration file: {0}'.format(config_file))
|
||||
if not isinstance(opts, dict):
|
||||
log.warning(
|
||||
'pillar_ldap: %s is invalidly formatted, must be a YAML '
|
||||
'dictionary. See the documentation for more information.',
|
||||
config_file
|
||||
)
|
||||
return {}
|
||||
|
||||
if 'search_order' not in opts:
|
||||
log.warning(
|
||||
'pillar_ldap: search_order missing from configuration. See the '
|
||||
'documentation for more information.'
|
||||
)
|
||||
|
||||
data = {}
|
||||
for source in opts['search_order']:
|
||||
|
|
Loading…
Add table
Reference in a new issue