File: check_oldest_completion.py

package info (click to toggle)
swift-tools 0.0.24
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 184 kB
  • sloc: python: 1,105; sh: 168; makefile: 14
file content (122 lines) | stat: -rw-r--r-- 3,489 bytes parent folder | download
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())