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
25
26
26
27
27
def render_resources (database , resource_type , localsite , template_names ):
@@ -30,15 +30,69 @@ def render_resources(database, resource_type, localsite, template_names):
30
30
database and rendered using the first template from template_names that can
31
31
be loaded.
32
32
"""
33
- resources = database .resources (resource_type )
33
+ # database.resources() is a generator, but we need to iterate it twice, so make a copy
34
+ r = database .resources (resource_type )
35
+ resources = []
34
36
try :
35
37
template = ENVIRONMENT .select_template (template_names )
36
38
except jinja2 .TemplatesNotFound :
37
39
LOG .error ('No template found for {0}' .format (resource_type ))
38
40
else :
39
- return template .render (resource_type = resource_type ,
40
- resources = resources , metaparams = METAPARAMS ,
41
- env = os .environ , localsite = localsite )
41
+ icinga_config = ''
42
+ object_name = resource_type [7 :]
43
+ named_object = object_name in NAMED_OBJECTS
44
+ service_dependencies = {}
45
+ for resource in r :
46
+ resources .append (resource )
47
+ envs_to_ignore = []
48
+ if resource .exported and ('only-cross-site' not in resource .tags or localsite == 'false' ):
49
+ dto = {}
50
+ dto ['object_name' ] = object_name
51
+ dto ['named_object' ] = named_object
52
+ dto ['name' ] = resource .name
53
+ dto ['parameters' ] = []
54
+ # capture resource parameters from puppet
55
+ for key , value in resource .parameters .items ():
56
+ if (key not in METAPARAMS or key in ALLOWED_METAPARAMS ) and (isinstance (value , list )):
57
+ dto ['parameters' ].append ({key : ',' .join (value )})
58
+ else :
59
+ dto ['parameters' ].append ({key : value })
60
+ envs_to_ignore .append ((object_name + '_' + key ).upper ())
61
+ # capture environment variable defaults
62
+ for name in os .environ :
63
+ nameparts = name .split ('_' )
64
+ if nameparts [0 ].lower () == object_name and name not in envs_to_ignore :
65
+ dto ['parameters' ].append ({'_' .join (nameparts [1 :]).lower (): os .environ [name ].lower ()})
66
+ icinga_config += template .render (dto = dto ) + '\n '
67
+ # collect child service dependencies under parent service_description
68
+ for tag in resource .tags :
69
+ if 'parent:' in tag :
70
+ parent_service_description_list = tag .split (':' )
71
+ if len (parent_service_description_list ) == 2 :
72
+ parent_service_description = parent_service_description_list [1 ]
73
+ if parent_service_description not in service_dependencies :
74
+ service_dependencies [parent_service_description ] = []
75
+ service_dependencies [parent_service_description ].append (resource )
76
+ # render service dependencies
77
+ if len (service_dependencies ) > 0 :
78
+ for item in service_dependencies :
79
+ parent_service_description = item .replace ('_' , ' ' )
80
+ # lookup parent resource by its service_description
81
+ for parent in resources :
82
+ if parent .exported and ('only-cross-site' not in parent .tags or localsite == 'false' ):
83
+ for key , value in parent .parameters .items ():
84
+ if key == 'service_description' and parent_service_description in value .lower ():
85
+ for child in service_dependencies [item ]:
86
+ dto = {}
87
+ dto ['object_name' ] = 'servicedependency'
88
+ dto ['parameters' ] = [{
89
+ 'host_name' : parent .parameters ['host_name' ],
90
+ 'service_description' : parent .parameters ['service_description' ],
91
+ 'dependent_host_name' : child .parameters ['host_name' ],
92
+ 'dependent_service_description' : child .parameters ['service_description' ]
93
+ }]
94
+ icinga_config += template .render (dto = dto ) + '\n '
95
+ return icinga_config
42
96
43
97
44
98
def main ():
@@ -52,12 +106,9 @@ def main():
52
106
parser .add_argument ('--host' , '-H' , default = 'localhost' )
53
107
parser .add_argument ('--port' , '-p' , default = '8080' )
54
108
parser .add_argument ('--localsite' , '-l' , default = 'true' )
55
-
56
109
args = parser .parse_args ()
57
110
logging .basicConfig (level = logging .DEBUG if args .debug else logging .WARN )
58
-
59
111
database = pypuppetdb .connect (host = args .host , port = args .port )
60
-
61
112
for resource_type in args .resource_types :
62
113
templates = ['{0}.jinja2' .format (resource_type )]
63
114
if args .templates :
@@ -67,3 +118,5 @@ def main():
67
118
68
119
if __name__ == '__main__' :
69
120
main ()
121
+ sys .exit (0 )
122
+
0 commit comments