1
# Copyright (c) 2010-2011 OpenStack, LLC.
3
# Licensed under the Apache License, Version 2.0 (the "License");
4
# you may not use this file except in compliance with the License.
5
# You may obtain a copy of the License at
7
# http://www.apache.org/licenses/LICENSE-2.0
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
18
from paste.deploy import appconfig
23
from swift.account.server import DATADIR as account_server_data_dir
24
from swift.container.server import DATADIR as container_server_data_dir
25
from swift.common.db import AccountBroker, ContainerBroker
26
from swift.common.utils import renamer, get_logger, readconf, mkdirs, \
27
TRUE_VALUES, remove_file
28
from swift.common.constraints import check_mount
29
from swift.common.daemon import Daemon
32
class DatabaseStatsCollector(Daemon):
34
Extract storage stats from account databases on the account
37
Any subclasses must define the function get_data.
40
def __init__(self, stats_conf, stats_type, data_dir, filename_format):
41
super(DatabaseStatsCollector, self).__init__(stats_conf)
42
self.stats_type = stats_type
43
self.data_dir = data_dir
44
self.filename_format = filename_format
45
self.devices = stats_conf.get('devices', '/srv/node')
46
self.mount_check = stats_conf.get('mount_check',
47
'true').lower() in TRUE_VALUES
48
self.target_dir = stats_conf.get('log_dir', '/var/log/swift')
49
mkdirs(self.target_dir)
50
self.logger = get_logger(stats_conf,
51
log_route='%s-stats' % stats_type)
53
def run_once(self, *args, **kwargs):
54
self.logger.info(_("Gathering %s stats" % self.stats_type))
56
self.find_and_process()
57
self.logger.info(_("Gathering %s stats complete (%0.2f minutes)") %
58
(self.stats_type, (time.time() - start) / 60))
61
raise Exception('Not Implemented')
63
def find_and_process(self):
64
src_filename = time.strftime(self.filename_format)
65
working_dir = os.path.join(self.target_dir,
66
'.%-stats_tmp' % self.stats_type)
67
shutil.rmtree(working_dir, ignore_errors=True)
69
tmp_filename = os.path.join(working_dir, src_filename)
70
hasher = hashlib.md5()
72
with open(tmp_filename, 'wb') as statfile:
73
for device in os.listdir(self.devices):
74
if self.mount_check and not check_mount(self.devices,
77
_("Device %s is not mounted, skipping.") % device)
79
db_dir = os.path.join(self.devices, device, self.data_dir)
80
if not os.path.exists(db_dir):
82
_("Path %s does not exist, skipping.") % db_dir)
84
for root, dirs, files in os.walk(db_dir, topdown=False):
85
for filename in files:
86
if filename.endswith('.db'):
87
db_path = os.path.join(root, filename)
88
line_data = self.get_data(db_path)
90
statfile.write(line_data)
91
hasher.update(line_data)
93
src_filename += hasher.hexdigest()
94
renamer(tmp_filename, os.path.join(self.target_dir, src_filename))
96
shutil.rmtree(working_dir, ignore_errors=True)
99
class AccountStatsCollector(DatabaseStatsCollector):
101
Extract storage stats from account databases on the account
105
def __init__(self, stats_conf):
106
super(AccountStatsCollector, self).__init__(stats_conf, 'account',
107
account_server_data_dir,
110
def get_data(self, db_path):
112
Data for generated csv has the following columns:
113
Account Hash, Container Count, Object Count, Bytes Used
116
broker = AccountBroker(db_path)
117
if not broker.is_deleted():
118
info = broker.get_info()
119
line_data = '"%s",%d,%d,%d\n' % (info['account'],
120
info['container_count'],
121
info['object_count'],
126
class ContainerStatsCollector(DatabaseStatsCollector):
128
Extract storage stats from container databases on the container
132
def __init__(self, stats_conf):
133
super(ContainerStatsCollector, self).__init__(stats_conf, 'container',
134
container_server_data_dir,
135
'container-stats-%Y%m%d%H_')
137
def get_data(self, db_path):
139
Data for generated csv has the following columns:
140
Account Hash, Container Name, Object Count, Bytes Used
143
broker = ContainerBroker(db_path)
144
if not broker.is_deleted():
145
info = broker.get_info()
146
encoded_container_name = urllib.quote(info['container'])
147
line_data = '"%s","%s",%d,%d\n' % (
149
encoded_container_name,
150
info['object_count'],