1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
"""This module provides the base class for Bcfg2 server plugins."""
import os
import logging
class Debuggable(object):
""" Mixin to add a debugging interface to an object and expose it
via XML-RPC on :class:`Bcfg2.Server.Plugin.base.Plugin` objects """
#: List of names of methods to be exposed as XML-RPC functions
__rmi__ = ['toggle_debug']
def __init__(self, name=None):
"""
:param name: The name of the logger object to get. If none is
supplied, the full name of the class (including
module) will be used.
:type name: string
.. autoattribute:: __rmi__
"""
if name is None:
name = "%s.%s" % (self.__class__.__module__,
self.__class__.__name__)
self.debug_flag = False
self.logger = logging.getLogger(name)
def toggle_debug(self):
""" Turn debugging output on or off. This method is exposed
via XML-RPC.
:returns: bool - The new value of the debug flag
"""
self.debug_flag = not self.debug_flag
self.debug_log("%s: debug_flag = %s" % (self.__class__.__name__,
self.debug_flag),
flag=True)
return self.debug_flag
def debug_log(self, message, flag=None):
""" Log a message at the debug level.
:param message: The message to log
:type message: string
:param flag: Override the current debug flag with this value
:type flag: bool
:returns: None
"""
if (flag is None and self.debug_flag) or flag:
self.logger.error(message)
class ClassName(object):
""" This very simple descriptor class exists only to get the name
of the owner class. This is used because, for historical reasons,
we expect every plugin to have a ``name`` attribute that is in
almost all cases the same as the ``__class__.__name__`` attribute
of the plugin object. This makes that more dynamic so that each
plugin isn't repeating its own name. """
def __get__(self, inst, owner):
return owner.__name__
class Plugin(Debuggable):
""" The base class for all Bcfg2 Server plugins. """
#: The name of the plugin.
name = ClassName()
#: The email address of the plugin author.
__author__ = 'bcfg-dev@mcs.anl.gov'
#: Plugin is experimental. Use of this plugin will produce a log
#: message alerting the administrator that an experimental plugin
#: is in use.
experimental = False
#: Plugin is deprecated and will be removed in a future release.
#: Use of this plugin will produce a log message alerting the
#: administrator that an experimental plugin is in use.
deprecated = False
#: Plugin conflicts with the list of other plugin names
conflicts = []
#: Plugins of the same type are processed in order of ascending
#: sort_order value. Plugins with the same sort_order are sorted
#: alphabetically by their name.
sort_order = 500
#: List of names of methods to be exposed as XML-RPC functions
__rmi__ = Debuggable.__rmi__
def __init__(self, core, datastore):
"""
:param core: The Bcfg2.Server.Core initializing the plugin
:type core: Bcfg2.Server.Core
:param datastore: The path to the Bcfg2 repository on the
filesystem
:type datastore: string
:raises: :class:`Bcfg2.Server.Plugin.exceptions.PluginInitError`
.. autoattribute:: Bcfg2.Server.Plugin.base.Debuggable.__rmi__
"""
self.Entries = {}
self.core = core
self.data = os.path.join(datastore, self.name)
self.running = True
Debuggable.__init__(self, name=self.name)
@classmethod
def init_repo(cls, repo):
""" Perform any tasks necessary to create an initial Bcfg2
repository.
:param repo: The path to the Bcfg2 repository on the filesystem
:type repo: string
:returns: None
"""
os.makedirs(os.path.join(repo, cls.name))
def shutdown(self):
""" Perform shutdown tasks for the plugin
:returns: None """
self.running = False
def __str__(self):
return "%s Plugin" % self.__class__.__name__
|