generate.py 5.7 KB
Newer Older
1
from sbws.globals import (fail_hard, SBWS_SCALE_CONSTANT, TORFLOW_SCALING,
juga's avatar
juga committed
2
3
                          SBWS_SCALING, TORFLOW_BW_MARGIN, TORFLOW_ROUND_DIG,
                          DAY_SECS, NUM_MIN_RESULTS)
juga's avatar
juga committed
4
from sbws.lib.v3bwfile import V3BWFile
5
from sbws.lib.resultdump import load_recent_results_in_datadir
6
from argparse import ArgumentDefaultsHelpFormatter
7
import os
8
import logging
Matt Traudt's avatar
Matt Traudt committed
9
from sbws.util.timestamp import now_fname
10
11

log = logging.getLogger(__name__)
12
13


14
def gen_parser(sub):
15
16
    d = 'Generate a v3bw file based on recent results. A v3bw file is the '\
        'file Tor directory authorities want to read and base their '\
17
18
19
20
21
22
23
        'bandwidth votes on. '\
        'To avoid inconsistent reads, configure tor with '\
        '"V3BandwidthsFile /path/to/latest.v3bw". '\
        '(latest.v3bw is an atomically created symlink in the same '\
        'directory as output.) '\
        'If the file is transferred to another host, it should be written to '\
        'a temporary path, then renamed to the V3BandwidthsFile path.'
24
    p = sub.add_parser('generate', description=d,
25
                       formatter_class=ArgumentDefaultsHelpFormatter)
26
27
28
    p.add_argument('--output', default=None, type=str,
                   help='If specified, write the v3bw here instead of what is'
                   'specified in the configuration')
29
30
31
32
    # The reason for --scale-constant defaulting to 7500 is because at one
    # time, torflow happened to generate output that averaged to 7500 bw units
    # per relay. We wanted the ability to try to be like torflow. See
    # https://lists.torproject.org/pipermail/tor-dev/2018-March/013049.html
juga's avatar
juga committed
33
    p.add_argument('--scale-constant', default=SBWS_SCALE_CONSTANT, type=int,
34
35
                   help='When scaling bw weights, scale them using this const '
                   'multiplied by the number of measured relays')
36
    p.add_argument('--scale-sbws', action='store_true',
37
38
39
40
                   help='If specified, do not use bandwidth values as they '
                   'are, but scale them such that we have a budget of '
                   'scale_constant * num_measured_relays = bandwidth to give '
                   'out, and we do so proportionally')
41
42
    p.add_argument('-t', '--scale-torflow', action='store_const',
                   default=True, const=False,
43
44
                   help='If specified, do not use bandwidth values as they '
                   'are, but scale them in the way Torflow does.')
45
46
47
    p.add_argument('-w', '--raw', action='store_true',
                   help='If specified, do use bandwidth raw measurements '
                   'without any scaling.')
48
49
    p.add_argument('-m', '--torflow-bw-margin', default=TORFLOW_BW_MARGIN,
                   type=float,
juga's avatar
juga committed
50
                   help="Cap maximum bw when scaling as Torflow. ")
juga's avatar
juga committed
51
52
53
    p.add_argument('-r', '--torflow-round-digs', default=TORFLOW_ROUND_DIG,
                   type=int,
                   help="Number of most significant digits to round bw "
juga's avatar
juga committed
54
                        "when scaling as Torflow.")
juga's avatar
juga committed
55
    p.add_argument('-p', '--secs-recent', default=None, type=int,
juga's avatar
juga committed
56
57
                   help="How many secs in the past are results being "
                        "still considered. Note this value will supersede "
juga's avatar
juga committed
58
                        "data_period in the configuration.")
juga's avatar
juga committed
59
    p.add_argument('-a', '--secs-away', default=DAY_SECS, type=int,
juga's avatar
juga committed
60
                   help="How many secs results have to be away from each "
juga's avatar
juga committed
61
                        "other.")
juga's avatar
juga committed
62
    p.add_argument('-n', '--min-num', default=NUM_MIN_RESULTS, type=int,
juga's avatar
juga committed
63
                   help="Mininum number of a results to consider them.")
juga's avatar
juga committed
64
65
66
    p.add_argument('-l', '--rm-link', action='store_true',
                   help='If specified, remove latest.v3bw link when there '
                        'are no relays to include in it.')
67
68


69
def main(args, conf):
70
    os.makedirs(conf.getpath('paths', 'v3bw_dname'), exist_ok=True)
71

72
    datadir = conf.getpath('paths', 'datadir')
73
    if not os.path.isdir(datadir):
74
        fail_hard('%s does not exist', datadir)
75
    if args.scale_constant < 1:
76
        fail_hard('--scale-constant must be positive')
77
78
    if args.torflow_bw_margin < 0:
        fail_hard('toflow-bw-margin must be major than 0.')
79
80
    if args.scale_sbws:
        scaling_method = SBWS_SCALING
81
    elif args.raw:
82
        scaling_method = None
83
84
    else:
        scaling_method = TORFLOW_SCALING
85

86
    fresh_days = conf.getint('general', 'data_period')
87
88
    reset_bw_ipv4_changes = conf.getboolean('general', 'reset_bw_ipv4_changes')
    reset_bw_ipv6_changes = conf.getboolean('general', 'reset_bw_ipv6_changes')
89
    results = load_recent_results_in_datadir(
90
91
92
        fresh_days, datadir, success_only=True,
        on_changed_ipv4=reset_bw_ipv4_changes,
        on_changed_ipv6=reset_bw_ipv6_changes)
Matt Traudt's avatar
Matt Traudt committed
93
    if len(results) < 1:
94
        log.warning('No recent results, so not generating anything. (Have you '
Matt Traudt's avatar
Matt Traudt committed
95
                    'ran sbws scanner recently?)')
Matt Traudt's avatar
Matt Traudt committed
96
        return
juga's avatar
juga committed
97
    state_fpath = conf.getpath('paths', 'state_fname')
juga's avatar
juga committed
98
99
    consensus_path = os.path.join(conf.getpath('tor', 'datadir'),
                                  "cached-consensus")
100
    bw_file = V3BWFile.from_results(results, state_fpath, args.scale_constant,
101
                                    scaling_method,
juga's avatar
juga committed
102
                                    torflow_cap=args.torflow_bw_margin,
juga's avatar
juga committed
103
104
105
                                    torflow_round_digs=args.torflow_round_digs,
                                    secs_recent=args.secs_recent,
                                    secs_away=args.secs_away,
juga's avatar
juga committed
106
107
                                    min_num=args.min_num,
                                    consensus_path=consensus_path)
108

109
110
    output = args.output or \
        conf.getpath('paths', 'v3bw_fname').format(now_fname())
juga's avatar
juga committed
111
    bw_file.write(output, args.rm_link)
juga's avatar
juga committed
112
    bw_file.info_stats