5
from landscape.plugin import PluginConfigError
6
from landscape.monitor.monitor import MonitorPlugin
9
class ProcessorInfo(MonitorPlugin):
10
"""Plugin captures information about the processor(s) in this machine.
12
This plugin runs once per client session. When processor
13
information is retrieved it's compared against the last known
14
processor information, which is saved in persistent storage. A
15
message is only put on the message queue if the latest processor
16
information differs from the last known processor information.
18
The information available from /proc/cpuinfo varies per platform.
19
For example, an Apple PowerMac Dual G5 doesn't contain a vendor ID
20
and provides the processor name in the 'cpu' field, as opposed to
21
the 'model name' field used on x86-based hardware. For reasons
22
such as this, the schema of the data reported by this plugin is
23
flexible. Only 'processor-id' and 'model' are guaranteed to be
26
In order to deal with the vagaries of parsing /proc/cpu
27
information on the various platforms we support, message
28
generation is deferred to per-platform message factories.
31
persist_name = "processor-info"
32
# Prevent the Plugin base-class from scheduling looping calls.
35
def __init__(self, delay=2, machine_name=None,
36
source_filename="/proc/cpuinfo"):
37
"""Initialize plugin with starting delay and source filename."""
39
self._source_filename = source_filename
41
if machine_name is None:
42
machine_name = os.uname()[4]
44
self._cpu_info_reader = self._create_cpu_info_reader(machine_name,
47
def _create_cpu_info_reader(self, machine_name, source_filename):
48
"""Return a message factory suitable for the specified machine name."""
49
for pair in message_factories:
50
regexp = re.compile(pair[0])
52
if regexp.match(machine_name):
53
return pair[1](source_filename)
55
raise PluginConfigError("A processor info reader for '%s' is not "
56
"available." % machine_name)
58
def register(self, registry):
59
"""Register this plugin with the specified plugin registry."""
60
super(ProcessorInfo, self).register(registry)
61
self.registry.reactor.call_later(self._delay, self.run)
62
self.registry.reactor.call_on("resynchronize", self._resynchronize)
63
self.call_on_accepted("processor-info", self.send_message, True)
65
def _resynchronize(self):
66
self.registry.persist.remove(self.persist_name)
68
def create_message(self):
69
"""Retrieve processor information and generate a message."""
70
return {"type": "processor-info",
71
"processors": self._cpu_info_reader.create_message()}
73
def send_message(self, urgent=False):
75
message = self.create_message()
77
for processor in message["processors"]:
78
key = ("processor", str(processor["processor-id"]))
79
cached_processor = self._persist.get(key)
80
if cached_processor is None:
82
self._update(cached_processor, processor)
85
if self._has_changed(cached_processor, processor):
86
self._update(cached_processor, processor)
90
logging.info("Queueing message with updated processor info.")
91
self.registry.broker.send_message(message, urgent=urgent)
93
def run(self, urgent=False):
94
"""Create a message and put it on the message queue."""
95
self.registry.broker.call_if_accepted("processor-info",
96
self.send_message, urgent)
98
def _has_changed(self, processor, message):
99
"""Returns true if processor details changed since the last read."""
100
if processor["model"] != message["model"]:
103
if processor["vendor"] != message.get("vendor", ""):
106
if processor["cache_size"] != message.get("cache-size", -1):
111
def _update(self, processor, message):
112
"""Update the processor details with current values."""
113
processor["id"] = message["processor-id"]
114
processor["model"] = message["model"]
115
processor["cache_size"] = message.get("cache-size", -1)
116
processor["vendor"] = message.get("vendor", "")
117
self._persist.set(("processor", str(message["processor-id"])),
121
class PowerPCMessageFactory:
122
"""Factory for ppc-based processors provides processor information."""
124
def __init__(self, source_filename):
125
"""Initialize reader with filename of data source."""
126
self._source_filename = source_filename
128
def create_message(self):
129
"""Returns a list containing information about each processor."""
131
file = open(self._source_filename)
137
parts = line.split(":", 1)
138
key = parts[0].strip()
140
if key == "processor":
141
current = {"processor-id": int(parts[1].strip())}
142
processors.append(current)
144
current["model"] = parts[1].strip()
151
class SparcMessageFactory:
152
"""Factory for sparc-based processors provides processor information."""
154
def __init__(self, source_filename):
155
"""Initialize reader with filename of data source."""
156
self._source_filename = source_filename
158
def create_message(self):
159
"""Returns a list containing information about each processor."""
162
file = open(self._source_filename)
165
regexp = re.compile("CPU(\d{1})+")
168
parts = line.split(":", 1)
169
key = parts[0].strip()
172
model = parts[1].strip()
173
elif regexp.match(key):
174
start, end = re.compile("\d+").search(key).span()
175
message = {"processor-id": int(key[start:end]),
177
processors.append(message)
184
class X86MessageFactory:
185
"""Factory for x86-based processors provides processor information."""
187
def __init__(self, source_filename):
188
"""Initialize reader with filename of data source."""
189
self._source_filename = source_filename
191
def create_message(self):
192
"""Returns a list containing information about each processor."""
194
file = open(self._source_filename)
200
parts = line.split(":", 1)
201
key = parts[0].strip()
203
if key == "processor":
204
current = {"processor-id": int(parts[1].strip())}
205
processors.append(current)
206
elif key == "vendor_id":
207
current["vendor"] = parts[1].strip()
208
elif key == "model name":
209
current["model"] = parts[1].strip()
210
elif key == "cache size":
211
value_parts = parts[1].split()
212
current["cache-size"] = int(value_parts[0].strip())
219
message_factories = [("ppc(64)?", PowerPCMessageFactory),
220
("sparc[64]", SparcMessageFactory),
221
("i[3-7]86|x86_64", X86MessageFactory)]