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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
"""This module provides the base class for Bcfg2 server plugins."""
import os
import logging
from Bcfg2.Utils import ClassName
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', 'set_debug']
#: How exposed XML-RPC functions should be dispatched to child
#: processes.
__child_rmi__ = __rmi__[:]
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 set_debug(self, debug):
""" Explicitly enable or disable debugging. This method is exposed
via XML-RPC.
:returns: bool - The new value of the debug flag
"""
self.debug_flag = debug
return debug
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
"""
return self.set_debug(not 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 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
#: Whether or not to automatically create a data directory for
#: this plugin
create = True
#: List of names of methods to be exposed as XML-RPC functions
__rmi__ = Debuggable.__rmi__
#: How exposed XML-RPC functions should be dispatched to child
#: processes, if :mod:`Bcfg2.Server.MultiprocessingCore` is in
#: use. Items ``__child_rmi__`` can either be strings (in which
#: case the same function is called on child processes as on the
#: parent) or 2-tuples, in which case the first element is the
#: name of the RPC function called on the parent process, and the
#: second element is the name of the function to call on child
#: processes. Functions that are not listed in the list will not
#: be dispatched to child processes, i.e., they will only be
#: called on the parent. A function must be listed in ``__rmi__``
#: in order to be exposed; functions listed in ``_child_rmi__``
#: but not ``__rmi__`` will be ignored.
__child_rmi__ = Debuggable.__child_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: :exc:`OSError` if adding a file monitor failed;
:class:`Bcfg2.Server.Plugin.exceptions.PluginInitError`
on other errors
.. autoattribute:: Bcfg2.Server.Plugin.base.Debuggable.__rmi__
"""
Debuggable.__init__(self, name=self.name)
self.Entries = {}
self.core = core
self.data = os.path.join(datastore, self.name)
if self.create and not os.path.exists(self.data):
self.logger.warning("%s: %s does not exist, creating" %
(self.name, self.data))
os.makedirs(self.data)
self.running = True
@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.debug_log("Shutting down %s plugin" % self.name)
self.running = False
def set_debug(self, debug):
self.debug_log("%s: debug = %s" % (self.name, self.debug_flag),
flag=True)
for entry in self.Entries.values():
if isinstance(entry, Debuggable):
entry.set_debug(debug)
return Debuggable.set_debug(self, debug)
def __str__(self):
return "%s Plugin" % self.__class__.__name__
|