1
1
#!/usr/bin/env python
2
+
2
3
"""
3
4
puppetdb-stencil is a tool to render puppet resources using templates.
4
5
"""
5
6
6
7
from __future__ import print_function
7
8
from __future__ import unicode_literals
8
-
9
9
import argparse
10
10
import logging
11
+ import sys
11
12
import os
12
13
import pypuppetdb
13
14
import jinja2
14
15
15
- LOG = logging .getLogger ('puppetdb_stencil' )
16
-
17
- METAPARAMS = ('require' , 'before' , 'subscribe' , 'notify' , 'audit' , 'loglevel' ,
18
- 'noop' , 'schedule' , 'stage' , 'alias' , 'tag' )
19
16
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' )
20
21
# Allow templates from anywhere on the filesystem
21
22
LOADER = jinja2 .FileSystemLoader (['.' , '/' ])
22
23
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
+ )
25
33
26
34
27
35
def render_resources (database , resource_type , localsite , template_names ):
@@ -30,15 +38,73 @@ def render_resources(database, resource_type, localsite, template_names):
30
38
database and rendered using the first template from template_names that can
31
39
be loaded.
32
40
"""
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 = []
34
44
try :
35
45
template = ENVIRONMENT .select_template (template_names )
36
46
except jinja2 .TemplatesNotFound :
37
47
LOG .error ('No template found for {0}' .format (resource_type ))
38
48
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
42
108
43
109
44
110
def main ():
@@ -52,12 +118,9 @@ def main():
52
118
parser .add_argument ('--host' , '-H' , default = 'localhost' )
53
119
parser .add_argument ('--port' , '-p' , default = '8080' )
54
120
parser .add_argument ('--localsite' , '-l' , default = 'true' )
55
-
56
121
args = parser .parse_args ()
57
122
logging .basicConfig (level = logging .DEBUG if args .debug else logging .WARN )
58
-
59
123
database = pypuppetdb .connect (host = args .host , port = args .port )
60
-
61
124
for resource_type in args .resource_types :
62
125
templates = ['{0}.jinja2' .format (resource_type )]
63
126
if args .templates :
@@ -67,3 +130,4 @@ def main():
67
130
68
131
if __name__ == '__main__' :
69
132
main ()
133
+ sys .exit (0 )
0 commit comments