Browse Source

Generate nodepool logging configuration

Generate a logging configuration template for nodepool that splits
image-build logs out into separate files.

A tool to generate and maintain this file based on the nodepool
configuration is added.

The logging configuration template this tool creates is added
alongside the main configuration.  This is passed to the deployment
puppet module via a parameter.

Change-Id: I4723c68e5c83b536560e0a8bd7b73e312b46fc02
Depends-on: Iec77fb62c353d09186140b23912caf02225a643b
changes/36/164036/3
Ian Wienand 4 years ago
parent
commit
3bafd2c691

+ 2
- 0
modules/openstack_project/manifests/nodepool_prod.pp View File

@@ -5,6 +5,7 @@ class openstack_project::nodepool_prod(
5 5
   $mysql_password,
6 6
   $nodepool_ssh_private_key = '',
7 7
   $nodepool_template = 'openstack_project/nodepool/nodepool.yaml.erb',
8
+  $nodepool_logging_template = 'openstack_project/nodepool/nodepool.logging.conf.erb',
8 9
   $vhost_name = 'nodepool.openstack.org',
9 10
   $sysadmins = [],
10 11
   $statsd_host = '',
@@ -44,6 +45,7 @@ class openstack_project::nodepool_prod(
44 45
     scripts_dir               => $::project_config::nodepool_scripts_dir,
45 46
     elements_dir              => $::project_config::nodepool_elements_dir,
46 47
     require                   => $::project_config::config_dir,
48
+    logging_conf_template     => $nodepool_logging_template,
47 49
   }
48 50
 
49 51
   file { '/etc/nodepool/nodepool.yaml':

+ 1146
- 0
modules/openstack_project/templates/nodepool/nodepool.logging.conf.erb
File diff suppressed because it is too large
View File


+ 244
- 0
tools/nodepool_log_config.py View File

@@ -0,0 +1,244 @@
1
+#!/usr/bin/env python
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+
16
+"""Generate a sample logging configuration file
17
+
18
+use log_config_generator.generate_log_config() to generate a sample
19
+logging configuration file.
20
+
21
+The sample splits up the log output for general logging and image
22
+builds and applys some sensible rotation defaults.
23
+"""
24
+
25
+import argparse
26
+import logging
27
+import yaml
28
+
29
+# default paths and outputs
30
+MODULES_PATH = '../modules/openstack_project/templates/nodepool'
31
+CONFIG_FILE = MODULES_PATH + '/nodepool.yaml.erb'
32
+LOGGING_CONFIG_FILE = MODULES_PATH + '/nodepool.logging.conf.erb'
33
+LOG_DIR = '/var/log/nodepool'
34
+IMAGE_LOG_DIR = '<%= @image_log_document_root %>'
35
+
36
+
37
+_BASIC_FILE = """
38
+
39
+#
40
+# THIS FILE HAS BEEN AUTOGENERATED
41
+# Regenerate it with tools/nodepool_log_config.py
42
+#
43
+
44
+[loggers]
45
+keys=root,nodepool,requests,image,%(logger_titles)s
46
+
47
+[handlers]
48
+keys=console,debug,normal,image,%(handler_titles)s
49
+
50
+[formatters]
51
+keys=simple
52
+
53
+[logger_root]
54
+level=WARNING
55
+handlers=console
56
+
57
+[logger_requests]
58
+level=WARNING
59
+handlers=debug,normal
60
+qualname=requests
61
+
62
+[logger_nodepool]
63
+level=DEBUG
64
+handlers=debug,normal
65
+qualname=nodepool
66
+
67
+[logger_image]
68
+level=INFO
69
+handlers=image
70
+qualname=nodepool.image.build
71
+propagate=0
72
+
73
+[handler_console]
74
+level=WARNING
75
+class=StreamHandler
76
+formatter=simple
77
+args=(sys.stdout,)
78
+
79
+[handler_debug]
80
+level=DEBUG
81
+class=logging.handlers.TimedRotatingFileHandler
82
+formatter=simple
83
+args=('%(log_dir)s/debug.log', 'H', 8, 30,)
84
+
85
+[handler_normal]
86
+level=INFO
87
+class=logging.handlers.TimedRotatingFileHandler
88
+formatter=simple
89
+args=('%(log_dir)s/nodepool.log', 'H', 8, 30,)
90
+
91
+[handler_image]
92
+level=INFO
93
+class=logging.handlers.TimedRotatingFileHandler
94
+formatter=simple
95
+args=('%(image_log_dir)s/image.log', 'H', 8, 30,)
96
+
97
+[formatter_simple]
98
+format=%%(asctime)s %%(levelname)s %%(name)s: %%(message)s
99
+datefmt=
100
+
101
+# ==== individual image loggers ====
102
+
103
+%(image_loggers_and_handlers)s"""
104
+
105
+_IMAGE_HANDLER = """
106
+[handler_%(title)s]
107
+level=INFO
108
+class=logging.handlers.TimedRotatingFileHandler
109
+formatter=simple
110
+args=('%(image_log_dir)s/%(filename)s', 'H', 8, 30,)
111
+"""
112
+
113
+_IMAGE_LOGGER = """
114
+[logger_%(title)s]
115
+level=INFO
116
+handlers=%(handler)s
117
+qualname=nodepool.image.build.%(qualname)s
118
+propagate=0
119
+"""
120
+
121
+
122
+def _get_providers_and_images(config_file):
123
+    ret = []
124
+    config = yaml.load(config_file)
125
+    for provider in config['providers']:
126
+        for image in provider['images']:
127
+            ret.append((provider['name'], image['name']))
128
+    logging.debug("Added %d providers & images" % len(ret))
129
+    return ret
130
+
131
+
132
+def _generate_logger_and_handler(image_log_dir, provider, image):
133
+    handler = _IMAGE_HANDLER % {
134
+        'image_log_dir': image_log_dir,
135
+        'title': '%s_%s' % (provider, image),
136
+        'filename': '%s.%s.log' % (provider, image),
137
+    }
138
+    logger = _IMAGE_LOGGER % {
139
+        'title': '%s_%s' % (provider, image),
140
+        'handler': '%s_%s' % (provider, image),
141
+        'qualname': '%s.%s' % (provider, image),
142
+    }
143
+
144
+    return {
145
+        'handler_title': '%s_%s' % (provider, image),
146
+        'logger_title': '%s_%s' % (provider, image),
147
+        'handler': handler,
148
+        'logger': logger,
149
+    }
150
+
151
+
152
+def generate_log_config(config, log_dir, image_log_dir, output):
153
+
154
+    """Generate a sample logging file
155
+
156
+    The logging output will have the correct formatters and handlers
157
+    to split all image-build logs out into separate files grouped by
158
+    provider.  e.g.
159
+
160
+    providers:
161
+      - name: foo
162
+        ...
163
+        - images:
164
+          - name: image1
165
+            ...
166
+          - name: image2
167
+            ...
168
+      - name: moo
169
+        ...
170
+        - images:
171
+          - name: image1
172
+            ...
173
+          - name: image2
174
+            ...
175
+
176
+    Will result in log files (in `image_log_dir`) of foo.image1.log,
177
+    foo.image2.log, moo.image1.log, moo.image2.log
178
+
179
+    :param config: input config file
180
+    :param log_dir: directory for main log file
181
+    :param image_log_dir: directory for image build logs
182
+    :param output: open file handle to output sample configuration to
183
+
184
+    """
185
+
186
+    loggers_and_handlers = []
187
+    logging.debug("Reading config file %s" % config.name)
188
+    for (provider, image) in _get_providers_and_images(config):
189
+        loggers_and_handlers.append(
190
+            _generate_logger_and_handler(image_log_dir, provider, image))
191
+
192
+    logger_titles = []
193
+    handler_titles = []
194
+    image_loggers_and_handlers = ""
195
+    for item in loggers_and_handlers:
196
+        logger_titles.append(item['logger_title'])
197
+        handler_titles.append(item['handler_title'])
198
+        image_loggers_and_handlers += item['logger'] + item['handler']
199
+
200
+    final_output = _BASIC_FILE % {
201
+        'log_dir': log_dir,
202
+        'image_log_dir': image_log_dir,
203
+        'logger_titles': ','.join(logger_titles),
204
+        'handler_titles': ','.join(handler_titles),
205
+        'image_loggers_and_handlers': image_loggers_and_handlers,
206
+    }
207
+
208
+    logging.debug("Writing output to %s" % output.name)
209
+    output.write(final_output)
210
+    output.flush()
211
+    logging.debug("Done!")
212
+
213
+
214
+def main():
215
+
216
+    parser = argparse.ArgumentParser()
217
+    parser.add_argument('-d', '--debug', action='store_true',
218
+                        help="Enable debugging")
219
+    parser.add_argument('-c', '--config', default=CONFIG_FILE,
220
+                        help="Config file to read in "
221
+                        "(default: %s)" % CONFIG_FILE,
222
+                        type=argparse.FileType('r'))
223
+    parser.add_argument('-o', '--output', default=LOGGING_CONFIG_FILE,
224
+                        help="Output file "
225
+                        "(default: %s)" % LOGGING_CONFIG_FILE,
226
+                        type=argparse.FileType('w'))
227
+    parser.add_argument('-l', '--log-dir', default=LOG_DIR,
228
+                        help="Output directory for logs "
229
+                        "(default: %s)" % LOG_DIR)
230
+    parser.add_argument('-i', '--image-log-dir', default=IMAGE_LOG_DIR,
231
+                        help="Output directory for image logs "
232
+                        "(default: %s)" % IMAGE_LOG_DIR)
233
+    args = parser.parse_args()
234
+
235
+    logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO)
236
+
237
+    generate_log_config(args.config,
238
+                        args.log_dir,
239
+                        args.image_log_dir,
240
+                        args.output)
241
+
242
+
243
+if __name__ == "__main__":
244
+    main()

Loading…
Cancel
Save