Skip to content

Commit 63ef9ed

Browse files
author
Eric Peterson
committed
Merge pull request #6 from ckonstanski/master
Service dependencies
2 parents 5ff8f03 + 9debb52 commit 63ef9ed

File tree

3 files changed

+84
-43
lines changed

3 files changed

+84
-43
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
virtualenv

examples/nagios_.jinja2

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,10 @@
1-
{% set allowed_metaparams = ('alias',) %}
2-
{% set named_objects = ('host', 'hostgroup', 'servicegroup', 'contact', 'contactgroup', 'timeperiod', 'command') %}
3-
{% set object_name = resource_type[7:] %}
4-
{% set named_object = object_name in named_objects %}
5-
{% for resource in resources %}
6-
{% set envs_to_ignore = [] %}
7-
{% if resource.exported %}
8-
{% if "only-cross-site" not in resource.tags or localsite == "false" %}
9-
define {{ object_name }} {
10-
{% if named_object %}
11-
{{ object_name }}_name {{ resource.name }}
1+
define {{ dto.object_name }} {
2+
{% if dto.named_object %}
3+
{{ dto.object_name }}_name {{ dto.name }}
124
{% endif %}
13-
{% for key, value in resource.parameters.items() %}
14-
{% if key not in metaparams or key in allowed_metaparams %}
15-
{% if value is iterable and value is not string %}
16-
{{ key }} {{ value|join(", ") }}
17-
{% else %}
5+
{% for item in dto.parameters %}
6+
{% for key, value in item.iteritems() %}
187
{{ key }} {{ value }}
19-
{% set _ = envs_to_ignore.append((object_name ~ '_' ~ key)|upper) %}
20-
{% endif %}
21-
{% endif %}
228
{% endfor %}
23-
{% for name in env %}
24-
{% set nameparts = name.split('_') %}
25-
{% if nameparts[0]|lower == object_name %}
26-
{% if name not in envs_to_ignore %}
27-
{{ ("_".join(nameparts[1:]))|lower }} {{ env[name]|lower }}
28-
{% endif %}
29-
{% endif %}
309
{% endfor %}
3110
}
32-
{% endif %}
33-
{% endif %}
34-
{% endfor %}

puppetdb_stencil.py

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,35 @@
11
#!/usr/bin/env python
2+
23
"""
34
puppetdb-stencil is a tool to render puppet resources using templates.
45
"""
56

67
from __future__ import print_function
78
from __future__ import unicode_literals
8-
99
import argparse
1010
import logging
11+
import sys
1112
import os
1213
import pypuppetdb
1314
import jinja2
1415

15-
LOG = logging.getLogger('puppetdb_stencil')
16-
17-
METAPARAMS = ('require', 'before', 'subscribe', 'notify', 'audit', 'loglevel',
18-
'noop', 'schedule', 'stage', 'alias', 'tag')
1916

17+
LOG = logging.getLogger('puppetdb_stencil')
18+
METAPARAMS = ('require', 'before', 'subscribe', 'notify', 'audit', 'loglevel', 'noop', 'schedule', 'stage', 'alias', 'tag')
19+
ALLOWED_METAPARAMS = ('alias')
20+
NAMED_OBJECTS = ('host', 'hostgroup', 'servicegroup', 'servicedependency', 'contact', 'contactgroup', 'timeperiod', 'command')
2021
# Allow templates from anywhere on the filesystem
2122
LOADER = jinja2.FileSystemLoader(['.', '/'])
2223
EXTENSIONS = ['jinja2.ext.with_', 'jinja2.ext.loopcontrols']
23-
ENVIRONMENT = jinja2.Environment(trim_blocks=True, lstrip_blocks=True,
24-
loader=LOADER, extensions=EXTENSIONS)
24+
ENVIRONMENT = jinja2.Environment(trim_blocks=True, lstrip_blocks=True, loader=LOADER, extensions=EXTENSIONS)
25+
26+
27+
def is_resource_visible(resource, localsite):
28+
return resource.exported and (
29+
('only-cross-site' not in resource.tags and 'no-cross-site' not in resource.tags) or
30+
('only-cross-site' in resource.tags and 'no-cross-site' not in resource.tags and localsite == 'false') or
31+
('only-cross-site' not in resource.tags and 'no-cross-site' in resource.tags and localsite == 'true')
32+
)
2533

2634

2735
def render_resources(database, resource_type, localsite, template_names):
@@ -30,15 +38,73 @@ def render_resources(database, resource_type, localsite, template_names):
3038
database and rendered using the first template from template_names that can
3139
be loaded.
3240
"""
33-
resources = database.resources(resource_type)
41+
# database.resources() is a generator, but we need to iterate it twice, so make a copy
42+
r = database.resources(resource_type)
43+
resources = []
3444
try:
3545
template = ENVIRONMENT.select_template(template_names)
3646
except jinja2.TemplatesNotFound:
3747
LOG.error('No template found for {0}'.format(resource_type))
3848
else:
39-
return template.render(resource_type=resource_type,
40-
resources=resources, metaparams=METAPARAMS,
41-
env=os.environ, localsite=localsite)
49+
icinga_config = ''
50+
object_name = resource_type[7:]
51+
named_object = object_name in NAMED_OBJECTS
52+
service_dependencies = {}
53+
for resource in r:
54+
resources.append(resource)
55+
envs_to_ignore = []
56+
if is_resource_visible(resource, localsite):
57+
dto = {
58+
'object_name': object_name,
59+
'named_object': named_object,
60+
'name': resource.name,
61+
'parameters': []
62+
}
63+
# capture resource parameters from puppet
64+
for key, value in resource.parameters.items():
65+
if (key not in METAPARAMS or key in ALLOWED_METAPARAMS) and (isinstance(value, list)):
66+
dto['parameters'].append({key: ','.join(value)})
67+
else:
68+
dto['parameters'].append({key: value})
69+
envs_to_ignore.append((object_name + '_' + key).upper())
70+
# capture environment variable defaults
71+
for name in os.environ:
72+
nameparts = name.split('_')
73+
if nameparts[0].lower() == object_name and name not in envs_to_ignore:
74+
dto['parameters'].append({'_'.join(nameparts[1:]).lower(): os.environ[name].lower()})
75+
icinga_config += template.render(dto=dto)
76+
# collect child service dependencies under parent service_description
77+
for tag in resource.tags:
78+
if 'parent:' in tag:
79+
parent_service_description_list = tag.split(':')
80+
if len(parent_service_description_list) == 2:
81+
parent_service_description = parent_service_description_list[1]
82+
if parent_service_description not in service_dependencies:
83+
service_dependencies[parent_service_description] = []
84+
service_dependencies[parent_service_description].append(resource)
85+
# render service dependencies
86+
if len(service_dependencies) > 0:
87+
for item in service_dependencies:
88+
parent_service_description = item.replace('_', ' ')
89+
# lookup parent resource by its service_description
90+
for parent in resources:
91+
if is_resource_visible(parent, localsite):
92+
for key, value in parent.parameters.items():
93+
if key == 'service_description' and parent_service_description in value.lower():
94+
for child in service_dependencies[item]:
95+
dto = {
96+
'object_name': 'servicedependency',
97+
'parameters': [{
98+
'host_name': parent.parameters['host_name'],
99+
'service_description': parent.parameters['service_description'],
100+
'dependent_host_name': child.parameters['host_name'],
101+
'dependent_service_description': child.parameters['service_description'],
102+
'notification_failure_criteria': 'w,c,u,p',
103+
'execution_failure_criteria': 'w,c,u,p'
104+
}]
105+
}
106+
icinga_config += template.render(dto=dto)
107+
return icinga_config
42108

43109

44110
def main():
@@ -52,12 +118,9 @@ def main():
52118
parser.add_argument('--host', '-H', default='localhost')
53119
parser.add_argument('--port', '-p', default='8080')
54120
parser.add_argument('--localsite', '-l', default='true')
55-
56121
args = parser.parse_args()
57122
logging.basicConfig(level=logging.DEBUG if args.debug else logging.WARN)
58-
59123
database = pypuppetdb.connect(host=args.host, port=args.port)
60-
61124
for resource_type in args.resource_types:
62125
templates = ['{0}.jinja2'.format(resource_type)]
63126
if args.templates:
@@ -67,3 +130,4 @@ def main():
67130

68131
if __name__ == '__main__':
69132
main()
133+
sys.exit(0)

0 commit comments

Comments
 (0)