source: nscp/scripts/python/docs.py @ 393a00f

0.4.2
Last change on this file since 393a00f was 393a00f, checked in by Michael Medin <michael@…>, 11 months ago
  • Improved settings API with new protocolbuffers command (available from python)
  • Improved registration API with new protocolbuffers command (available from python)
  • Created new python documentation module docs.py
  • Improved command line syntax so executable commands now take an optional module prefix
  • Property mode set to 100644
File size: 11.5 KB
Line 
1from NSCP import Settings, Registry, Core, log, log_debug, log_error, status
2import plugin_pb2
3from optparse import OptionParser
4from sets import Set
5import os
6helper = None
7
8
9def ttfix(string, def_val = ' '):
10        if not string or len(string) == 0:
11                return def_val
12        return string
13
14class root_container(object):
15        paths = {}
16        commands = {}
17        plugins = {}
18        def __init__(self):
19                self.paths = {}
20                self.commands = {}
21                self.plugins = {}
22
23        def append_key(self, info):
24                path = info.node.path
25                if path in self.paths:
26                        self.paths[path].append_key(info)
27                else:
28                        p = path_container()
29                        p.append_key(info)
30                        self.paths[path] = p
31               
32        def append_path(self, info):
33                path = info.node.path
34                if not path in self.paths:
35                        self.paths[path] = path_container(info)
36
37        def append_command(self, info):
38                name = info.name
39                if not name in self.commands:
40                        self.commands[name] = command_container(info)
41
42        def append_plugin(self, info):
43                name = info.name
44                if not name in self.plugins:
45                        self.plugins[name] = plugin_container(info)
46
47class path_container(object):
48        keys = {}
49        info = None
50        def __init__(self, info = None):
51                self.keys = {}
52                self.info = info.info
53               
54        def append_key(self, info):
55                self.keys[info.node.key] = info
56
57class command_container(object):
58        info = None
59        def __init__(self, info = None):
60                self.info = info.info
61
62class plugin_container(object):
63        info = None
64        def __init__(self, info = None):
65                self.info = info.info
66
67class DocumentationHelper(object):
68        plugin_id = None
69        plugin_alias = None
70        script_alias = None
71        conf = None
72        registry = None
73        dir = None
74        trac_path = None
75       
76        def __init__(self, plugin_id, plugin_alias, script_alias):
77                self.plugin_id = plugin_id
78                self.plugin_alias = plugin_alias
79                self.script_alias = script_alias
80                self.conf = Settings.get(self.plugin_id)
81                self.registry = Registry.get(self.plugin_id)
82               
83        def build_inventory_request(self, path = '/', recursive = True, keys = False):
84                message = plugin_pb2.SettingsRequestMessage()
85                message.header.version = plugin_pb2.Common.VERSION_1
86                payload = message.payload.add()
87                payload.type = 4
88                payload.inventory.node.path = path
89                payload.inventory.recursive_fetch = recursive
90                payload.inventory.fetch_keys = keys
91                payload.inventory.fetch_paths = not keys
92                payload.inventory.descriptions = True
93                return message.SerializeToString()
94       
95        def build_command_request(self, type = 1):
96                message = plugin_pb2.RegistryRequestMessage()
97                message.header.version = plugin_pb2.Common.VERSION_1
98                payload = message.payload.add()
99                payload.type = 2
100                payload.inventory.fetch_all = True
101                payload.inventory.type.append(type)
102                return message.SerializeToString()
103
104        def get_paths(self):
105                (code, data) = self.conf.query(self.build_inventory_request())
106                if code == 1:
107                        message = plugin_pb2.SettingsResponseMessage()
108                        message.ParseFromString(data)
109                        for payload in message.payload:
110                                if payload.type == 4:
111                                        return payload.inventory
112                return []
113
114        def get_keys(self, path):
115                (code, data) = self.conf.query(self.build_inventory_request(path, False, True))
116                if code == 1:
117                        message = plugin_pb2.SettingsResponseMessage()
118                        message.ParseFromString(data)
119                        for payload in message.payload:
120                                if payload.type == 4:
121                                        return payload.inventory
122                return []
123
124        def get_commands(self):
125                (code, data) = self.registry.query(self.build_command_request(1))
126                if code == 1:
127                        message = plugin_pb2.RegistryResponseMessage()
128                        message.ParseFromString(data)
129                        for payload in message.payload:
130                                if payload.type == 2:
131                                        return payload.inventory
132                return []
133
134        def get_plugins(self):
135                (code, data) = self.registry.query(self.build_command_request(4))
136                if code == 1:
137                        message = plugin_pb2.RegistryResponseMessage()
138                        message.ParseFromString(data)
139                        for payload in message.payload:
140                                if payload.type == 2:
141                                        return payload.inventory
142                return []
143
144        def get_info(self):
145                root = root_container()
146                for p in self.get_paths():
147                        root.append_path(p)
148                        for k in self.get_keys(p.node.path):
149                                root.append_key(k)
150                for p in self.get_commands():
151                        root.append_command(p)
152                for p in self.get_plugins():
153                        root.append_plugin(p)
154                return root
155               
156        def generate_trac_config_path(self, p, pinfo, module = None):
157                string = ''
158                if not module or module in pinfo.info.plugin:
159                        string += '=== %s ===\n'%pinfo.info.title
160                        string += '%s\n\n'%(pinfo.info.description)
161                        string += "'''Section:''' %s\n\n"%(p)
162                        first = True
163                        for (k,kinfo) in pinfo.keys.iteritems():
164                                if not module or module in pinfo.info.plugin:
165                                        if not kinfo.info.advanced:
166                                                if first:
167                                                        string += "'''Keys:'''\n"
168                                                        string += "||'''Key'''||'''Title'''||'''Description'''\n"
169                                                        first = False
170                                                string += '||%s||%s ||%s \n'%(ttfix(k), ttfix(kinfo.info.title), ttfix(kinfo.info.description))
171                        if not first:
172                                string += '\n\n'
173                        first = True
174                        for (k,kinfo) in pinfo.keys.iteritems():
175                                if not module or module in pinfo.info.plugin:
176                                        if kinfo.info.advanced:
177                                                if first:
178                                                        string += "'''Advanced Keys:'''\n"
179                                                        string += "||'''Key'''||'''Title'''||'''Description'''\n"
180                                                        first = False
181                                                string += '||%s||%s ||%s \n'%(ttfix(k), ttfix(kinfo.info.title), ttfix(kinfo.info.description, "'''TODO'''"))
182                        if not first:
183                                string += '\n\n'
184                        string += "'''Sample:'''\n\n"
185                        string += "{{{\n"
186                        string += "# %s\n"%pinfo.info.title
187                        string += "# %s\n"%pinfo.info.description
188                        string += "[%s]\n"%p
189                        for (k,kinfo) in pinfo.keys.iteritems():
190                                if not module or module in pinfo.info.plugin:
191                                        string += "# %s\n"%kinfo.info.title
192                                        string += "# %s\n"%kinfo.info.description
193                                        string += "%s=%s\n"%(k, kinfo.info.default_value)
194
195                        string += "}}}\n"
196                        string += '\n'
197                        for (k,kinfo) in pinfo.keys.iteritems():
198                                if not module or module in pinfo.info.plugin:
199                                        string += "==== %s ====\n"%kinfo.info.title
200                                        string += "'''Description:''' %s\n\n"%kinfo.info.description
201                                        if kinfo.info.advanced:
202                                                string += "'''Advanced:''' (means it is not commonly used)\n\n"
203                                        string += "'''Key:''' %s\n\n"%k
204                                        if kinfo.info.default_value:
205                                                string += "'''Default value:''' %s\n\n"%kinfo.info.default_value
206                                        string += "'''Used by:''' "
207                                        first = True
208                                        for p in pinfo.info.plugin:
209                                                if first:
210                                                        first = False
211                                                else:
212                                                        string += ", "
213                                                string += "[[%s]]"%p
214                                        string += "\n\n"
215                                        string += "'''Sample:'''\n\n"
216                                        string += "{{{\n"
217                                        string += "# %s\n"%kinfo.info.title
218                                        string += "# %s\n"%kinfo.info.description
219                                        string += "[%s]\n"%p
220                                        string += "%s=%s\n"%(k, kinfo.info.default_value)
221                                        string += "}}}\n"
222                                        string += '\n'
223                return string
224
225               
226        def serialize_wiki(self, string, filename, wikiname):
227                if dir:
228                        if not os.path.exists(self.dir):
229                                os.makedirs(self.dir)
230                        f = open('%s/%s.wiki'%(self.dir, filename),"w")
231                        f.write(string)
232                        f.close()
233                        return "trac-admin %s wiki import %s %s.wiki\n"%(self.trac_path, wikiname, filename)
234                else:
235                        print string
236                        return "Generated output for: %s"%wikiname
237       
238        def generate_trac(self, dir, trac_path):
239                self.dir = dir
240                self.trac_path = trac_path
241                if not trac_path:
242                        trac_path = '/foo/bar'
243                docs = {}
244                root = self.get_info()
245                import_commands = ""
246               
247                for (module,minfo) in root.plugins.iteritems():
248                        string = ''
249                        string += '[[TracNav(TracNav/CC|nocollapse|noreorder)]]\n'
250                        string += '[[PageOutline]]\n'
251                        string += "= %s =\n"%minfo.info.title
252                        string += "%s\n\n"%minfo.info.description
253                        string += '== Queries (commands) ==\n'
254                        found = False
255                        for (c,cinfo) in root.commands.iteritems():
256                                if module in cinfo.info.plugin:
257                                        string += " * [[%s/%s|%s]]\n"%(module, cinfo.info.title, cinfo.info.title)
258                                        string += "   %s\n"%cinfo.info.description
259                                        found = True
260                        if not found:
261                                string += "No commands avalible in %s\n"%module
262                       
263                        string += "\n\n"
264                        string += '== Commands (executable) ==\n'
265                        string += "'''TODO:''' Add command list\n"
266                        string += "\n\n"
267                        string += '== Configuration ==\n'
268                        found = None
269                        for (p,pinfo) in root.paths.iteritems():
270                                found = self.generate_trac_config_path(p, pinfo, module)
271                                string += found
272
273                        if not found:
274                                string += "No configuration avalible for %s\n"%module
275                               
276                        import_commands += self.serialize_wiki(string, module, module)
277
278                all_config = """
279[[TracNav(TracNav/TOCDoc|nocollapse|noreorder)]]
280[[PageOutline]]
281= Configuration 0.4.x =
282
283For older version please refer to [[wiki:/doc/configuration/0.3.x]]
284
285Configuration is fairly simple and straight forward. But due to flexibility the actual file may be placed in many location and can even not be a file at all (for instance the registry). Regardless of which store you have for configuration the end result is the same. The configuration will const of a section (path) a key and a value. The path (section) is a hierarcical structure meaning you will find things like ''/foo/bar/baz'' or to make real examples ''/settings/NRPE/server''. This is similar to how it was in older version except there we would only have had NRPE in the path (section) name.
286If your configuration is in a file (and most likely it is) you can edit it using a normal text editor (such as notepad or vi). The file is usually called nsc.ini or nsclient.ini (but this can be changed).
287
288The configuration is as mentioned divided into sections (paths) each with a given name.
289
290The various sections are described in short below. The default configuration file has a lot of examples and comments so make sure you change this before you use NSClient++ as some of the examples might be potential security issues.
291                """
292                for (p,pinfo) in root.paths.iteritems():
293                        all_config += self.generate_trac_config_path(p, pinfo)
294                import_commands += self.serialize_wiki(all_config, "all-config", "doc/configuration/0.4.x")
295                       
296                       
297                all_commands = """
298[[TracNav(TracNav/CC|nocollapse)]]
299[[PageOutline]]
300= Modules =
301NSClient++ comes with a set of modules out of the box that perform various checks and functions. A list of the modules and their potential use is listed below.  Click each plug-in to see detailed command descriptions and how the various modules can be used.
302"""
303                for (module,minfo) in root.plugins.iteritems():
304                        all_commands += "== [[wiki:%s]] ==\n"%(module)
305                        all_commands += "'''%s''': %s\n\n"%(minfo.info.title, minfo.info.description)
306                        all_commands += '=== Queries (commands) ===\n'
307                        found = False
308                        for (c,cinfo) in root.commands.iteritems():
309                                if module in cinfo.info.plugin:
310                                        all_commands += " * [[%s/%s|%s]]\n"%(module, cinfo.info.title, cinfo.info.title)
311                                        all_commands += "   %s\n"%cinfo.info.description
312                                        found = True
313                        if not found:
314                                all_commands += "No commands avalible in [[%s]]\n"%module
315                       
316                        all_commands += "\n\n"
317                        all_commands += '=== Commands (executable) ===\n'
318                        all_commands += "'''TODO:''' Add command list\n"
319                        all_commands += "\n\n"
320                all_commands += """
321= All Commands =
322A list of all commands (alphabetically).
323[[ListTagged(check)]]
324"""
325                import_commands += self.serialize_wiki(all_commands, "all-commands", "CheckCommands")
326                               
327                print import_commands
328
329        def main(self, args):
330                parser = OptionParser(prog="N/A")
331                parser.add_option("-f", "--format", help="Generate format")
332                parser.add_option("-o", "--output", help="write report to FILE(s)")
333                parser.add_option("--trac-path", help="The path to track (used for importing wikis)")
334                (options, args) = parser.parse_args(args=args)
335                if options.format in ["trac"]:
336                        self.generate_trac(options.output, options.trac_path)
337                else:
338                        log("Invalid format: %s"%options.format)
339                        return
340
341def __main__(args):
342        global helper
343        helper.main(args);
344       
345def init(plugin_id, plugin_alias, script_alias):
346        global helper
347        helper = DocumentationHelper(plugin_id, plugin_alias, script_alias)
348
349def shutdown():
350        None
351
352
Note: See TracBrowser for help on using the repository browser.