| 1 | from NSCP import Settings, Registry, Core, log, log_debug, log_error, status |
|---|
| 2 | import plugin_pb2 |
|---|
| 3 | from optparse import OptionParser |
|---|
| 4 | from sets import Set |
|---|
| 5 | import os |
|---|
| 6 | helper = None |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | def ttfix(string, def_val = ' '): |
|---|
| 10 | if not string or len(string) == 0: |
|---|
| 11 | return def_val |
|---|
| 12 | return string |
|---|
| 13 | |
|---|
| 14 | class 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 | |
|---|
| 47 | class 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 | |
|---|
| 57 | class command_container(object): |
|---|
| 58 | info = None |
|---|
| 59 | def __init__(self, info = None): |
|---|
| 60 | self.info = info.info |
|---|
| 61 | |
|---|
| 62 | class plugin_container(object): |
|---|
| 63 | info = None |
|---|
| 64 | def __init__(self, info = None): |
|---|
| 65 | self.info = info.info |
|---|
| 66 | |
|---|
| 67 | class 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 | |
|---|
| 283 | For older version please refer to [[wiki:/doc/configuration/0.3.x]] |
|---|
| 284 | |
|---|
| 285 | Configuration 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. |
|---|
| 286 | If 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 | |
|---|
| 288 | The configuration is as mentioned divided into sections (paths) each with a given name. |
|---|
| 289 | |
|---|
| 290 | The 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 = |
|---|
| 301 | NSClient++ 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 = |
|---|
| 322 | A 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 | |
|---|
| 341 | def __main__(args): |
|---|
| 342 | global helper |
|---|
| 343 | helper.main(args); |
|---|
| 344 | |
|---|
| 345 | def init(plugin_id, plugin_alias, script_alias): |
|---|
| 346 | global helper |
|---|
| 347 | helper = DocumentationHelper(plugin_id, plugin_alias, script_alias) |
|---|
| 348 | |
|---|
| 349 | def shutdown(): |
|---|
| 350 | None |
|---|
| 351 | |
|---|
| 352 | |
|---|