Bcfg2 uses an option parsing mechanism based on the Python argparse module. It does several very useful things that argparse does not:
One of the more important features of the option parser is its ability to automatically collect options from loaded components (e.g., Bcfg2 server plugins). Given the highly pluggable architecture of Bcfg2, this helps ensure two things:
For instance, assume a few plugins:
The plugins are used by the bcfg2-quux command, which itself takes two options: --plugins (which selects the plugins) and --test. The options would be selected at runtime, so for instance these would be valid:
bcfg2-quux --plugins Foo --foo --test
bcfg2-quux --plugins Foo,Bar --foo --bar --force
bcfg2-quux --plugins Bar --force
But this would not:
bcfg2-quux –plugins Foo –bar
The help message would reflect the options that are available to the default set of plugins. (For this reason, allowing component lists to be set in the config file is very useful; that way, usage messages reflect the components in the config file.)
Components (in this example, the plugins) can be classes or modules. There is no required interface for an option component. They may optionally have:
Options are collected through two primary mechanisms:
Since it is preferred to add components instead of just options, loading options at runtime is generally best accomplished by creating a container object whose only purpose is to hold options. For instance:
def foo():
# do stuff
class _OptionContainer(object):
options = [
Bcfg2.Options.BooleanOption("--foo", help="Enable foo")]
@staticmethod
def options_parsed_hook():
if Bcfg2.Options.setup.foo:
foo()
Bcfg2.Options.get_parser().add_component(_OptionContainer)
Simple object for storing attributes.
Implements equality by attribute names and values, and provides a simple string representation.
The base Bcfg2.Options.Option object represents an option. Unlike options in argparse, an Option object does not need to be associated with an option parser; it exists on its own.
Bases: object
Representation of an option that can be specified on the command line, as an environment variable, or in a config file. Precedence is in that order; that is, an option specified on the command line takes precendence over an option given by the environment, which takes precedence over an option specified in the config file.
See argparse.ArgumentParser.add_argument() for a full list of accepted parameters.
In addition to supporting all arguments and keyword arguments from argparse.ArgumentParser.add_argument(), several additional keyword arguments are allowed.
Parameters: |
|
---|
A dict of Bcfg2.Options.Parser -> argparse.Action that gives the actions that resulted from adding this option to each parser that it was added to. If this option cannot be specified on the command line (i.e., it only takes its value from the config file), then this will be empty.
Add this option to the given parser.
Parameters: | parser (Bcfg2.Options.Parser) – The parser to add the option to. |
---|---|
Returns: | argparse.Action |
The options by which this option can be called. (Coincidentally, this is also the list of arguments that will be passed to argparse.ArgumentParser.add_argument() when this option is added to a parser.) As a result, args can be tested to see if this argument can be given on the command line at all, or if it is purely a config file option.
The tuple giving the section and option name for this option in the config file
The current default value of this option
Set the default value of this option from the config file or from the environment.
Parameters: | cfp (ConfigParser.ConfigParser) – The config parser to get the option value from |
---|
Hook called at the end of early option parsing.
This can be used to save option values for macro fixup.
The environment variable that this option can take its value from
Finalize the default value for this option. This is used with actions (such as Bcfg2.Options.ComponentAction) that allow you to specify a default in a different format than its final storage format; this can be called after it has been determined that the default will be used (i.e., the option is not given on the command line or in the config file) to store the appropriate default value in the appropriate format.
Get the value of this option from the given ConfigParser.ConfigParser. If it is not found in the config file, the default is returned. (If there is no default, None is returned.)
Parameters: | cfp (ConfigParser.ConfigParser) – The config parser to get the option value from |
---|---|
Returns: | The default value |
fetch a value from the config file.
This is passed the config parser. Its result is passed to the type function for this option. It can be overridden to, e.g., handle boolean options.
fetch a value from the environment.
This is passed the raw value from the environment variable, and its result is passed to the type function for this option. It can be overridden to, e.g., handle boolean options.
List options contained in this option. This exists to provide a consistent interface with Bcfg2.Options.OptionGroup
A detailed description of this option that will be used in man pages.
A list of Bcfg2.Options.Parser objects to which this option has been added. (There will be more than one parser if this option is added to a subparser, for instance.)
Bases: Bcfg2.Options.Options.RepositoryMacroOption
Shortcut for options that expect a path argument.
Uses Bcfg2.Options.Types.path() to transform the argument into a canonical path. The type of a path option can also be overridden to return a file-like object. For example:
options = [
Bcfg2.Options.PathOption(
"--input", type=argparse.FileType('r'),
help="The input file")]
PathOptions also do translation of <repository> macros.
Bases: Bcfg2.Options.Options.Option
Shortcut for boolean options. The default is False, but this can easily be overridden:
options = [
Bcfg2.Options.PathOption(
"--dwim", default=True, help="Do What I Mean")]
fetch a value from the config file.
This is passed the config parser. Its result is passed to the type function for this option. It can be overridden to, e.g., handle boolean options.
Bases: Bcfg2.Options.Options.Option
Shortcut for positional arguments.
Bases: argparse.ArgumentParser
The Bcfg2 option parser. Most interfaces should not need to instantiate a parser, but should instead use Bcfg2.Options.get_parser() to get the parser that already exists.
See argparse.ArgumentParser for a full list of accepted parameters.
In addition to supporting all arguments and keyword arguments from argparse.ArgumentParser, several additional keyword arguments are allowed.
Parameters: |
|
---|
Add a component (and all of its options) to the parser.
Add a config file, which triggers a full reparse of all options.
Add an explicit list of options to the parser. When possible, prefer Bcfg2.Options.Parser.add_component() to add a whole component instead.
The argument list that was parsed.
Components that have been added to the parser
Option for specifying the path to the Bcfg2 config file
The namespace options will be stored in.
Options that have been added to the parser
Builtin options that apply to all commands
Parse options.
Parameters: | argv (list) – The argument list to parse. By default, sys.argv[1:] is used. This is stored in Bcfg2.Options.Parser.argv for reuse by Bcfg2.Options.Parser.reparse(). |
---|
Whether or not parsing has completed on all current options.
Reparse options after they have already been parsed.
Parameters: | argv (list) – The argument list to parse. By default, Bcfg2.Options.Parser.argv is reused. (I.e., the argument list that was initially parsed.) |
---|
Flag used in unit tests to disable actual config file reads
Get an existing Bcfg2.Options.Parser object.
A Parser is created at the module level when Bcfg2.Options is imported. If any arguments are given, then the existing parser is modified before being returned.
Parameters: |
|
---|---|
Returns: | Bcfg2.Options.Parser object |
Bases: exceptions.Exception
Base exception raised for generic option parser errors
Options can be grouped in various meaningful ways. This uses a variety of argparse functionality behind the scenes.
In all cases, options can be added to groups in-line by simply specifying them in the object group constructor:
options = [
Bcfg2.Options.ExclusiveOptionGroup(
Bcfg2.Options.Option(...),
Bcfg2.Options.Option(...),
required=True),
....]
Nesting object groups is supported in theory, but barely tested.
Bases: Bcfg2.Options.OptionGroups._OptionContainer
Generic option group that is used only to organize options. This uses argparse.ArgumentParser.add_argument_group() behind the scenes.
Parameters: |
|
---|
Bases: Bcfg2.Options.OptionGroups._OptionContainer
Option group that ensures that only one argument in the group is present. This uses argparse.ArgumentParser.add_mutually_exclusive_group() behind the scenes.
Parameters: |
|
---|
Bases: Bcfg2.Options.OptionGroups._OptionContainer
Option group that adds options in it to a subparser. This uses a lot of functionality tied to argparse Sub-commands.
The subcommand string itself is stored in the Bcfg2.Options.setup namespace as subcommand.
This is commonly used with Bcfg2.Options.Subcommand groups.
Parameters: |
|
---|
Bases: Bcfg2.Options.OptionGroups._OptionContainer, Bcfg2.Options.Options.Option
WildcardSectionGroups contain options that may exist in several different sections of the config that match a glob. It works by creating options on the fly to match the sections described in the glob. For example, consider:
options = [
Bcfg2.Options.WildcardSectionGroup(
Bcfg2.Options.Option(cf=("myplugin:*", "number"), type=int),
Bcfg2.Options.Option(cf=("myplugin:*", "description"))]
If the config file contained [myplugin:foo] and [myplugin:bar] sections, then this would automagically create options for each of those. The end result would be:
>>> Bcfg2.Options.setup
Namespace(myplugin_bar_description='Bar description', myplugin_myplugin_bar_number=2, myplugin_myplugin_foo_description='Foo description', myplugin_myplugin_foo_number=1, myplugin_sections=['myplugin:foo', 'myplugin:bar'])
All options must have the same section glob.
The options are stored in an automatically-generated destination given by:
<prefix><section>_<destination>
<destination> is the original dest of the option. <section> is the section that it’s found in. <prefix> is automatically generated from the section glob. (This can be overridden with the constructor.) Both <section> and <prefix> have had all consecutive characters disallowed in Python variable names replaced with underscores.
This group stores an additional option, the sections themselves, in an option given by <prefix>sections.
Parameters: |
|
---|
This library makes it easier to work with programs that have a large number of subcommands (e.g., bcfg2-info and bcfg2-admin).
The normal implementation pattern is this:
Bcfg2.Server.Admin provides a fairly simple implementation, where the CLI class subclasses the command registry:
class CLI(Bcfg2.Options.CommandRegistry):
def __init__(self):
Bcfg2.Options.CommandRegistry.__init__(self)
self.register_commands(globals().values(), parent=AdminCmd)
parser = Bcfg2.Options.get_parser(
description="Manage a running Bcfg2 server",
components=[self])
parser.add_options(self.subcommand_options)
parser.parse()
In this case, commands are collected from amongst all global variables (the most likely scenario), and they must be children of Bcfg2.Server.Admin.AdminCmd, which itself subclasses Bcfg2.Options.Subcommand.
Commands are defined by subclassing Bcfg2.Options.Subcommand. At a minimum, the Bcfg2.Options.Subcommand.run() method must be overridden, and a docstring written.
Bases: object
Base class for subcommands. This must be subclassed to create commands.
Specifically, you must override Bcfg2.Options.Subcommand.run(). You may want to override:
You should not need to override Bcfg2.Options.Subcommand.__call__() or Bcfg2.Options.Subcommand.usage().
A Subcommand subclass constructor must not take any arguments.
Additional aliases for the command. The contents of the list gets added to the default command name (the lowercased class name)
Longer help message
Whether or not to expose this command in an interactive cmd.Cmd shell, if one is used. (bcfg2-info uses one, bcfg2-admin does not.)
A logging.Logger that can be used to produce logging output for this command.
Whether or not to expose this command as command line parameter or only in an interactive cmd.Cmd shell.
Options this command takes
The Bcfg2.Options.Parser that will be used to parse options if this subcommand is called from an interactive cmd.Cmd shell.
Run the command.
Parameters: | setup (argparse.Namespace) – A namespace giving the options for this command. This must be used instead of Bcfg2.Options.setup because this command may have been called from an interactive cmd.Cmd shell, and thus has its own option parser and its own (private) namespace. setup is guaranteed to contain all of the options in the global Bcfg2.Options.setup namespace, in addition to any local options given to this command from the interactive shell. |
---|
Perform any necessary shutdown tasks for this command This is called to when the program exits (not when this command is finished executing).
Get the short usage message.
Bases: object
A CommandRegistry is used to register subcommands and provides a single interface to run them. It’s also used by Bcfg2.Options.Subcommands.Help to produce help messages for all available commands.
A dict of registered commands. Keys are the class names, lowercased (i.e., the command names), and values are instances of the command objects.
the help command
Register a single command.
Parameters: | cls_or_obj (type or Subcommand) – The command class or object to register |
---|---|
Returns: | An instance of cmdcls |
Register all subcommands in candidates against the Bcfg2.Options.CommandRegistry subclass given in registry. A command is registered if and only if:
Parameters: |
|
---|
Run the single command named in Bcfg2.Options.setup.subcommand, which is where Bcfg2.Options.Subparser groups store the subcommand.
Perform shutdown tasks.
This calls the shutdown method of the subcommand that was run.
A list of options that should be added to the option parser in order to handle registered subcommands.
Several custom argparse actions provide some of the option collection magic of Bcfg2.Options.
Bases: Bcfg2.Options.Actions.FinalizableAction
ConfigFileAction automatically loads and parses a supplementary config file (e.g., bcfg2-web.conf or bcfg2-lint.conf).
Bases: Bcfg2.Options.Actions.FinalizableAction
ComponentAction automatically imports classes and modules based on the value of the option, and automatically collects options from the loaded classes and modules. It cannot be used by itself, but must be subclassed, with either mapping or bases overridden. See Bcfg2.Options.PluginsAction for an example.
ComponentActions expect to be given a list of class names. If bases is overridden, then it will attempt to import those classes from identically named modules within the given bases. For instance:
class FooComponentAction(Bcfg2.Options.ComponentAction):
bases = ["Bcfg2.Server.Foo"]
class FooLoader(object):
options = [
Bcfg2.Options.Option(
"--foo",
type=Bcfg2.Options.Types.comma_list,
default=["One"],
action=FooComponentAction)]
If “–foo One,Two,Three” were given on the command line, then FooComponentAction would attempt to import Bcfg2.Server.Foo.One.One, Bcfg2.Server.Foo.Two.Two, and Bcfg2.Server.Foo.Three.Three. (It would also call Bcfg2.Options.Parser.add_component() with each of those classes as arguments.)
Note that, although ComponentActions expect lists of components (by default; this can be overridden by setting islist), you must still explicitly specify a type argument to the Bcfg2.Options.Option constructor to split the value into a list.
Note also that, unlike other actions, the default value of a ComponentAction option does not need to be the actual literal final value. (I.e., you don’t have to import Bcfg2.Server.Foo.One.One and set it as the default in the example above; the string “One” suffices.)
A list of parent modules where modules or classes should be imported from.
If fail_silently is True, then failures to import modules or classes will not be logged. This is useful when the default is to import everything, some of which are expected to fail.
By default, ComponentActions expect a list of components to load. If islist is False, then it will only expect a single component.
A mapping of <name> => <object> that components will be loaded from. This can be used to permit much more complex behavior than just a list of bases.
If module is True, then only the module will be loaded, not a class from the module. For instance, in the example above, FooComponentAction would attempt instead to import Bcfg2.Server.Foo.One, Bcfg2.Server.Foo.Two, and Bcfg2.Server.Foo.Three.
Bases: Bcfg2.Options.Actions.ComponentAction
Bcfg2.Options.ComponentAction subclass for loading Bcfg2 server plugins.
Bcfg2.Options provides a number of useful types for use as the type keyword argument to the Bcfg2.Options.Option constructor.
A generic path. ~ will be expanded with os.path.expanduser() and the absolute resulting path will be used. This does not ensure that the path exists.
Split a comma-delimited list, with optional whitespace around the commas.
Split a colon-delimited list. Whitespace is not allowed around the colons.
Given a username or numeric UID, get a numeric UID. The user must exist.
Bases: object
Common options used in multiple different contexts.
Client timeout
Daemonize process, storing PID
Default Path paranoid setting
Run interactively, prompting the user for each change
Server location
Communication password
Communication protocol
Set the path to the Bcfg2 repository
Path to SSL CA certificate
Log to syslog