6
from landscape.lib.fetch import fetch, HTTPCodeError, PyCurlError, FetchError
7
from landscape.lib.monitor import CoverageMonitor
8
from landscape.lib.network import get_active_device_info
9
from landscape.monitor.plugin import MonitorPlugin
12
class SwiftDeviceInfo(MonitorPlugin):
14
persist_name = "swift-device-info"
16
def __init__(self, interval=300, monitor_interval=60 * 60,
17
create_time=time.time,
18
swift_config="/etc/swift/object-server.conf",
19
swift_ring="/etc/swift/object.ring.gz"):
20
self.run_interval = interval
21
self._monitor_interval = monitor_interval
22
self._create_time = create_time
24
self._get_network_devices = get_active_device_info
25
self._swift_config = swift_config # If exists, we are a swift node
26
self._swift_ring = swift_ring # To discover swift recon port
27
self._swift_recon_url = None
28
self._create_time = create_time
29
self._swift_device_info = []
30
self._swift_device_info_to_persist = []
33
def register(self, registry):
34
super(SwiftDeviceInfo, self).register(registry)
35
self._monitor = CoverageMonitor(self.run_interval, 0.8,
36
"swift device info snapshot",
37
create_time=self._create_time)
38
self.registry.reactor.call_every(self._monitor_interval,
40
self.registry.reactor.call_on("stop", self._monitor.log, priority=2000)
41
self.call_on_accepted("swift-device-info", self.send_messages, True)
43
def create_swift_device_info_message(self):
44
if self._swift_device_info:
45
message = {"type": "swift-device-info",
46
"swift-device-info": self._swift_device_info}
47
self._swift_device_info_to_persist = self._swift_device_info[:]
48
self._swift_device_info = []
52
def send_messages(self, urgent=False):
53
message = self.create_swift_device_info_message()
55
logging.info("Queueing message with updated swift device info.")
56
d = self.registry.broker.send_message(message, urgent=urgent)
57
d.addCallback(lambda x: self.persist_swift_info())
60
self.registry.broker.call_if_accepted("swift-device-info",
63
def persist_swift_info(self):
64
for swift_device_info in self._swift_device_info_to_persist:
65
device_name = swift_device_info["device"]
66
key = (self.persist_name, device_name)
67
self._persist.set(key, swift_device_info)
68
self._swift_device_info_to_persist = None
69
# This forces the registry to write the persistent store to disk
70
# This means that the persistent data reflects the state of the
79
current_swift_devices = self._get_swift_devices()
80
current_device_names = []
81
for swift_info in current_swift_devices:
82
device_name = swift_info["device"]
83
current_device_names.append(device_name)
84
key = (self.persist_name, device_name)
85
prev_swift_info = self._persist.get(key)
86
if not prev_swift_info or prev_swift_info != swift_info:
87
if swift_info not in self._swift_device_info:
88
self._swift_device_info.append(swift_info)
90
# Get all persisted devices and remove those that no longer exist
91
persisted_devices = self._persist.get(self.persist_name)
93
for device_name in persisted_devices.keys():
94
if device_name not in current_device_names:
95
self._persist.remove((self.persist_name, device_name))
97
def _get_swift_devices(self):
98
config_file = self._swift_config
99
# Check if a swift storage config file is available. No need to run
100
# if we know that we're not on a swift monitor node anyway.
101
if not os.path.exists(config_file):
102
# There is no config file - it's not a swift storage machine.
105
"This does not appear to be a swift storage server. '%s' "
106
"plugin has been disabled." % self.persist_name)
109
# Extract the swift service URL from the ringfile and cache it.
110
if self._swift_recon_url is None:
111
ring = self._get_ring()
115
network_devices = self._get_network_devices()
116
local_ips = [device["ip_address"] for device in network_devices]
118
# Grab first swift service with an IP on this host
119
for dev in ring.devs:
120
if dev and dev["ip"] in local_ips:
121
self._swift_recon_url = "http://%s:%d/recon/diskusage" % (
122
dev['ip'], dev['port'])
125
if self._swift_recon_url is None:
128
"Local swift service not found. '%s' plugin has "
129
"been disabled." % self.persist_name)
132
recon_disk_info = self._get_swift_disk_usage()
133
# We don't care about avail and free figures because we track
134
# free_space for mounted devices in free-space messages
135
return [{"device": "/dev/%s" % device["device"],
136
"mounted": device["mounted"]} for device in recon_disk_info]
138
def _get_swift_disk_usage(self):
140
Query the swift storage usage data by parsing the curled recon data
141
from http://localhost:<_swift_service_port>/recon/diskusage.
142
Lots of recon data for the picking described at:
143
http://docs.openstack.org/developer/swift/admin_guide.html
147
content = self._fetch(self._swift_recon_url)
148
except HTTPCodeError, error:
150
"Swift service is running without swift-recon enabled.")
151
except (FetchError, PyCurlError), error:
153
"Swift service not available at %s. %s." %
154
(self._swift_recon_url, str(error)))
155
if error_message is not None:
157
logging.error("%s '%s' plugin has been disabled." % (
158
error_message, self.persist_name))
164
swift_disk_usages = json.loads(content) # list of device dicts
165
return swift_disk_usages
168
"""Return ring-file object from self._swift_ring location"""
169
if not os.path.exists(self._swift_ring):
171
"Swift ring files are not available yet.")
174
from swift.common.ring import Ring
178
"Swift python common libraries not found. '%s' plugin has "
179
"been disabled." % self.persist_name)
181
return Ring(self._swift_ring)