diff --git a/management/backup.py b/management/backup.py index a47f54e8..bee97e4c 100755 --- a/management/backup.py +++ b/management/backup.py @@ -33,14 +33,14 @@ def backup_status(env): def reldate(date, ref, clip): if ref < date: return clip rd = dateutil.relativedelta.relativedelta(ref, date) - if rd.years > 1: return "%d years, %d months" % (rd.years, rd.months) - if rd.years == 1: return "%d year, %d months" % (rd.years, rd.months) - if rd.months > 1: return "%d months, %d days" % (rd.months, rd.days) - if rd.months == 1: return "%d month, %d days" % (rd.months, rd.days) - if rd.days >= 7: return "%d days" % rd.days - if rd.days > 1: return "%d days, %d hours" % (rd.days, rd.hours) - if rd.days == 1: return "%d day, %d hours" % (rd.days, rd.hours) - return "%d hours, %d minutes" % (rd.hours, rd.minutes) + if rd.years > 1: return "{:d} years, {:d} months".format(rd.years, rd.months) + if rd.years == 1: return "{:d} year, {:d} months".format(rd.years, rd.months) + if rd.months > 1: return "{:d} months, {:d} days".format(rd.months, rd.days) + if rd.months == 1: return "{:d} month, {:d} days".format(rd.months, rd.days) + if rd.days >= 7: return "{:d} days".format(rd.days) + if rd.days > 1: return "{:d} days, {:d} hours".format(rd.days, rd.hours) + if rd.days == 1: return "{:d} day, {:d} hours".format(rd.days, rd.hours) + return "{:d} hours, {:d} minutes".format(rd.hours, rd.minutes) # Get duplicity collection status and parse for a list of backups. def parse_line(line): @@ -130,7 +130,7 @@ def backup_status(env): # It still can't be deleted until it's old enough. est_deleted_on = max(est_time_of_next_full, first_date + datetime.timedelta(days=config["min_age_in_days"])) - deleted_in = "approx. %d days" % round((est_deleted_on-now).total_seconds()/60/60/24 + .5) + deleted_in = "approx. {:d} days".format(round((est_deleted_on-now).total_seconds()/60/60/24 + .5)) # When will a backup be deleted? Set the deleted_in field of each backup. saw_full = False @@ -346,7 +346,7 @@ def perform_backup(full_backup): shell('check_call', [ "/usr/bin/duplicity", "remove-older-than", - "%dD" % config["min_age_in_days"], + "{:d}D".format(config["min_age_in_days"]), "--verbosity", "error", "--archive-dir", backup_cache_dir, "--force", diff --git a/management/dns_update.py b/management/dns_update.py index 104aa615..d9bd82a4 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -459,7 +459,7 @@ def build_sshfp_records(): if not key.strip() or key[0] == "#": continue try: _host, keytype, pubkey = key.split(" ") - yield "%d %d ( %s )" % ( + yield "{:d} {:d} ( {} )".format( algorithm_number[keytype], 2, # specifies we are using SHA-256 on next line hashlib.sha256(base64.b64decode(pubkey)).hexdigest().upper(), diff --git a/management/mail_log.py b/management/mail_log.py index 8907342e..34bc7630 100755 --- a/management/mail_log.py +++ b/management/mail_log.py @@ -619,12 +619,12 @@ def print_time_table(labels, data, do_print=True): labels.insert(0, "hour") data.insert(0, [str(h) for h in range(24)]) - temp = "│ {:<%d} " % max(len(l) for l in labels) + temp = "│ {{:<{:d}}} ".format(max(len(l) for l in labels)) lines = [temp.format(label) for label in labels] for h in range(24): max_len = max(len(str(d[h])) for d in data) - base = "{:>%d} " % max(2, max_len) + base = "{{:>{:d}}} ".format(max(2, max_len)) for i, d in enumerate(data): lines[i] += base.format(d[h]) @@ -707,7 +707,7 @@ def print_user_table(users, data=None, sub_data=None, activity=None, latest=None if sub_data is not None: for l, d in sub_data: if d[row]: - lines.extend(('┬', f'│ {l}', '├─%s─' % (len(l) * '─'), '│')) + lines.extend(('┬', f'│ {l}', '├─{}─'.format(len(l) * '─'), '│')) max_len = 0 for v in list(d[row]): lines.append(f"│ {v}") @@ -753,7 +753,7 @@ def print_user_table(users, data=None, sub_data=None, activity=None, latest=None data_accum = [numstr(a) for a in data_accum] footer = str_temp.format("Totals:" if do_accum else " ") for row, (l, _) in enumerate(data): - temp = "{:>%d}" % max(5, len(l) + 1) + temp = "{{:>{:d}}}".format(max(5, len(l) + 1)) footer += temp.format(data_accum[row]) try: diff --git a/management/ssl_certificates.py b/management/ssl_certificates.py index db36234c..0f7105d9 100755 --- a/management/ssl_certificates.py +++ b/management/ssl_certificates.py @@ -602,7 +602,7 @@ def check_certificate(domain, ssl_certificate, ssl_private_key, warn_if_expiring ndays = (cert_expiration_date-now).days if not rounded_time or ndays <= 10: # Yikes better renew soon! - expiry_info = "The certificate expires in %d days on %s." % (ndays, cert_expiration_date.date().isoformat()) + expiry_info = "The certificate expires in {:d} days on {}.".format(ndays, cert_expiration_date.date().isoformat()) else: # We'll renew it with Lets Encrypt. expiry_info = f"The certificate expires on {cert_expiration_date.date().isoformat()}." diff --git a/management/status_checks.py b/management/status_checks.py index d465a098..a2e3a997 100755 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -122,15 +122,15 @@ def check_service(i, service, env): # IPv4 ok but IPv6 failed. Try the PRIVATE_IPV6 address to see if the service is bound to the interface. elif service["port"] != 53 and try_connect(env["PRIVATE_IPV6"]): - output.print_error("%s is running (and available over IPv4 and the local IPv6 address), but it is not publicly accessible at %s:%d." % (service['name'], env['PUBLIC_IPV6'], service['port'])) + output.print_error("{} is running (and available over IPv4 and the local IPv6 address), but it is not publicly accessible at {}:{:d}.".format(service['name'], env['PUBLIC_IPV6'], service['port'])) else: - output.print_error("%s is running and available over IPv4 but is not accessible over IPv6 at %s port %d." % (service['name'], env['PUBLIC_IPV6'], service['port'])) + output.print_error("{} is running and available over IPv4 but is not accessible over IPv6 at {} port {:d}.".format(service['name'], env['PUBLIC_IPV6'], service['port'])) # IPv4 failed. Try the private IP to see if the service is running but not accessible (except DNS because a different service runs on the private IP). elif service["port"] != 53 and try_connect("127.0.0.1"): - output.print_error("%s is running but is not publicly accessible at %s:%d." % (service['name'], env['PUBLIC_IP'], service['port'])) + output.print_error("{} is running but is not publicly accessible at {}:{:d}.".format(service['name'], env['PUBLIC_IP'], service['port'])) else: - output.print_error("%s is not running (port %d)." % (service['name'], service['port'])) + output.print_error("{} is not running (port {:d}).".format(service['name'], service['port'])) # Why is nginx not running? if not running and service["port"] in {80, 443}: @@ -140,7 +140,7 @@ def check_service(i, service, env): elif try_connect("127.0.0.1"): running = True else: - output.print_error("%s is not running (port %d)." % (service['name'], service['port'])) + output.print_error("{} is not running (port {:d}).".format(service['name'], service['port'])) # Flag if local DNS is not running. if not running and service["port"] == 53 and service["public"] is False: @@ -209,7 +209,7 @@ def check_software_updates(env, output): elif len(pkgs) == 0: output.print_ok("System software is up to date.") else: - output.print_error("There are %d software packages that can be updated." % len(pkgs)) + output.print_error("There are {:d} software packages that can be updated.".format(len(pkgs))) for p in pkgs: output.print_line("{} ({})".format(p["package"], p["version"])) @@ -223,7 +223,7 @@ def check_free_disk_space(rounded_values, env, output): st = os.statvfs(env['STORAGE_ROOT']) bytes_total = st.f_blocks * st.f_frsize bytes_free = st.f_bavail * st.f_frsize - disk_msg = "The disk has %.2f GB space remaining." % (bytes_free/1024.0/1024.0/1024.0) + disk_msg = "The disk has {:.2f} GB space remaining.".format(bytes_free/1024.0/1024.0/1024.0) if bytes_free > .3 * bytes_total: if rounded_values: disk_msg = "The disk has more than 30% free space." output.print_ok(disk_msg) diff --git a/setup/migrate.py b/setup/migrate.py index b60e434d..ee7346c9 100755 --- a/setup/migrate.py +++ b/setup/migrate.py @@ -196,7 +196,7 @@ def get_current_migration(): ver = 0 while True: next_ver = (ver + 1) - migration_func = globals().get("migration_%d" % next_ver) + migration_func = globals().get("migration_{:d}".format(next_ver)) if not migration_func: return ver ver = next_ver @@ -228,14 +228,14 @@ def run_migrations(): while True: next_ver = (ourver + 1) - migration_func = globals().get("migration_%d" % next_ver) + migration_func = globals().get("migration_{:d}".format(next_ver)) if not migration_func: # No more migrations to run. break print() - print("Running migration to Mail-in-a-Box #%d..." % next_ver) + print("Running migration to Mail-in-a-Box #{:d}...".format(next_ver)) try: migration_func(env) diff --git a/tests/fail2ban.py b/tests/fail2ban.py index 46ce9271..8f38cfa6 100644 --- a/tests/fail2ban.py +++ b/tests/fail2ban.py @@ -199,7 +199,7 @@ def run_test(testfunc, args, count, within_seconds, parallel): # Did we make enough requests within the limit? if (time.time()-start_time) > within_seconds: - raise Exception("Test failed to make %s requests in %d seconds." % (count, within_seconds)) + raise Exception("Test failed to make {} requests in {:d} seconds.".format(count, within_seconds)) # Wait a moment for the block to be put into place. time.sleep(4) diff --git a/tests/tls.py b/tests/tls.py index 18b6b7c4..89e1dae5 100644 --- a/tests/tls.py +++ b/tests/tls.py @@ -69,7 +69,7 @@ MOZILLA_CIPHERS_OLD = "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305 def sslyze(opts, port, ok_ciphers): # Print header. - header = ("PORT %d" % port) + header = ("PORT {:d}".format(port)) print(header) print("-" * (len(header))) @@ -83,7 +83,7 @@ def sslyze(opts, port, ok_ciphers): proxy_proc = None if proxy: connection_string = "localhost:10023" - proxy_proc = subprocess.Popen(["ssh", "-N", "-L10023:%s:%d" % (host, port), proxy]) + proxy_proc = subprocess.Popen(["ssh", "-N", "-L10023:{}:{:d}".format(host, port), proxy]) time.sleep(3) try: