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
|
"""
This script test if swiftsore server have oldest completion too old
"""
import sys
import socket
import eventlet
from swift.cli import recon
from swift.common.ring import RingBuilder
from urllib.parse import urlparse
from oslo_config import cfg
from datetime import datetime, timedelta
# Initialize Swift connection
swiftrecon = recon.SwiftRecon()
pool_size = 30
pool = eventlet.GreenPool(pool_size)
try:
builder = RingBuilder.load('/etc/swift/object.builder')
except Exception as e:
sys.exit(e)
# Initialize script arguments
CLI_OPTS = [
cfg.IntOpt('max_days', default='1', short='D',
help='Max days for oldest completion. \
Sum this with MAX_HOURS'),
cfg.IntOpt('max_hours', default='0', short='H',
help='Max hours for oldest completion. \
Sum this with MAX_DAYS'),
]
def display_days_hours_for(duration):
"""
Formatting a datetime object in correct sentence for display
param duration: datetime object
return: formatted string
"""
ret = "for more than"
if duration.days:
ret = f"{ret} {duration.days} days"
if duration.days and duration.seconds:
ret = f"{ret} and"
if duration.seconds:
ret = f"{ret} {int(duration.seconds / 3600)} hours"
return ret
def _prepare_config():
"""
Prepare the oslo config
return: oslo config object
"""
CONF = cfg.ConfigOpts()
CONF.register_cli_opts(CLI_OPTS)
return CONF
def get_hosts():
"""
Get a list of hosts ip and port
If script running in a switstore, he check only this server,
otherwise, he check all cluster
return: list off tuble with ip and port
"""
hosts = {}
devs = [d for d in builder.devs if d]
# If server have disk, use it, else use all swiftstore
ip = socket.gethostbyname(socket.gethostname())
devs_ip = [d for d in devs if d['ip'] == ip]
if devs_ip:
devs = devs_ip
for h in devs:
# filter only one ip and port by host
hosts[h['ip']] = h['port']
return set(hosts.items())
def analyze(max_oldest):
"""
Analyze all hosts
param max_oldest: the max oldest tolerate in datetime format
return: list of swiftstore with their oldest completion is > max_oldest
"""
hosts = get_hosts()
scout = recon.Scout(recon_type="replication/object", suppress_errors=True)
last_stats = []
for url, response, status, _ts_start, _ts_end \
in pool.imap(scout.scout, hosts):
if status == 200:
last = response.get('replication_last',
response.get('object_replication_last', 0))
oldest = (datetime.now()-datetime.fromtimestamp(last))
if oldest > max_oldest:
ip = urlparse(url).hostname
ho = socket.gethostbyaddr(ip)[0].split('.')[0]
last_stats.append((f"{ho}", oldest))
return last_stats
def main():
"""
Entry point for the script
"""
CONF = _prepare_config()
CONF(sys.argv[1:])
max_oldest = timedelta(days=CONF.max_days, hours=CONF.max_hours)
ls = analyze(max_oldest)
# Diplay result
print(f"### Swift oldest completions {display_days_hours_for(max_oldest)} \
: {len(ls)} swiftstores")
for host, ago in sorted(ls, key=lambda x: x[1], reverse=True):
print(f"- {host}: {display_days_hours_for(ago)}")
if __name__ == "__main__":
sys.exit(main())
|