From aaed8aff7c425c8ac2a15e584e24317da327f5e4 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 24 Sep 2015 16:47:32 +0200 Subject: Merge is now run by shell script tools/merge. tools/merge run merge_fetch.py, merge_backup.py, merge_sth.py and merge_dist.py sequentially. TODO: test backupquorum != 0 --- Makefile | 10 ++-- tools/merge | 8 ++++ tools/merge.py | 38 ---------------- tools/merge_backup.py | 58 +++++++++++++++++++++--- tools/merge_dist.py | 102 +++++++++++++++++++++-------------------- tools/merge_fetch.py | 48 +++++++++++++++----- tools/merge_sth.py | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/mergetools.py | 55 ++++++++++++++++++++-- tools/testcase1.py | 4 +- 9 files changed, 331 insertions(+), 115 deletions(-) create mode 100755 tools/merge delete mode 100755 tools/merge.py mode change 100644 => 100755 tools/merge_backup.py mode change 100644 => 100755 tools/merge_dist.py mode change 100644 => 100755 tools/merge_fetch.py create mode 100755 tools/merge_sth.py diff --git a/Makefile b/Makefile index 2f823e5..92d4577 100644 --- a/Makefile +++ b/Makefile @@ -76,7 +76,7 @@ tests-start: tests-run: @(cd $(INSTDIR) && python ../tools/testcase1.py https://localhost:8080/ tests/keys/logkey.pem tests/httpsca/demoCA/cacert.pem) || (echo "Tests failed" ; false) - @diff -r -x nursery -x verifiedsize catlfish/tests/mergedb catlfish/tests/mergedb-secondary || (echo "Merge databases not matching" ; false) + @diff -r -x nursery -x verifiedsize -x fetched -x sth -x verified.\* catlfish/tests/mergedb catlfish/tests/mergedb-secondary || (echo "Merge databases not matching" ; false) @(cd $(INSTDIR) && python ../tools/check-sth.py --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem https://localhost:8080/) || (echo "Check failed" ; false) @(cd $(INSTDIR) && python ../tools/fetchallcerts.py $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Verification failed" ; false) @(cd $(INSTDIR) && rm -f submittedcerts) @@ -89,8 +89,8 @@ tests-run: @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/pre1.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false) @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/pre2.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false) @(cd $(INSTDIR) && python ../tools/storagegc.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-1.cfg) || (echo "GC failed" ; false) - @(cd $(INSTDIR) && python ../tools/merge.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false) - @diff -r -x nursery -x verifiedsize catlfish/tests/mergedb catlfish/tests/mergedb-secondary || (echo "Merge databases not matching" ; false) + @(cd $(INSTDIR) && ../tools/merge --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false) + @diff -r -x nursery -x verifiedsize -x fetched -x sth -x verified.\* catlfish/tests/mergedb catlfish/tests/mergedb-secondary || (echo "Merge databases not matching" ; false) @(cd $(INSTDIR) && python ../tools/check-sth.py --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem https://localhost:8080/) || (echo "Check failed" ; false) @(cd $(INSTDIR) && rm -r fetchcertstore || true) @(cd $(INSTDIR) && mkdir fetchcertstore) @@ -148,8 +148,8 @@ tests-formatupgrade-prepare2: printf 0 > $(INSTDIR)/tests/mergedb-secondary/verifiedsize tests-formatupgrade-run2: - @(cd $(INSTDIR) && python ../tools/merge.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false) - @diff -r -x nursery -x verifiedsize catlfish/tests/mergedb catlfish/tests/mergedb-secondary || (echo "Merge databases not matching" ; false) + @(cd $(INSTDIR) && ../tools/merge --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false) + @diff -r -x nursery -x verifiedsize -x fetched -x sth -x verified.\* catlfish/tests/mergedb catlfish/tests/mergedb-secondary || (echo "Merge databases not matching" ; false) @(cd $(INSTDIR) && rm -r fetchcertstore-old || true) @(cd $(INSTDIR) && mkdir fetchcertstore-old) @(cd $(INSTDIR) && python ../tools/fetchallcerts.py $(BASEURL) --no-check-signature --store fetchcertstore-old --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Verification failed" ; false) diff --git a/tools/merge b/tools/merge new file mode 100755 index 0000000..e11ac93 --- /dev/null +++ b/tools/merge @@ -0,0 +1,8 @@ +#! /bin/sh + +BINDIR=$(dirname $0) + +$BINDIR/merge_fetch.py $@ +$BINDIR/merge_backup.py $@ +$BINDIR/merge_sth.py $@ +$BINDIR/merge_dist.py $@ diff --git a/tools/merge.py b/tools/merge.py deleted file mode 100755 index 212c171..0000000 --- a/tools/merge.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright (c) 2014-2015, NORDUnet A/S. -# See LICENSE for licensing information. - -import argparse -import yaml -import sys -from certtools import create_ssl_context -from merge_fetch import merge_fetch -from merge_backup import merge_backup -from merge_dist import merge_dist - -def main(): - parser = argparse.ArgumentParser(description="") - parser.add_argument('--config', help="System configuration", - required=True) - parser.add_argument('--localconfig', help="Local configuration", - required=True) - parser.add_argument("--nomerge", action='store_true', - help="Don't actually do merge") - parser.add_argument("--timing", action='store_true', - help="Print timing information") - args = parser.parse_args() - - config = yaml.load(open(args.config)) - localconfig = yaml.load(open(args.localconfig)) - paths = localconfig["paths"] - - create_ssl_context(cafile=paths["https_cacertfile"]) - - sth = merge_fetch(args, config, localconfig) - merge_backup(args, config, localconfig, sth) - merge_dist(args, config, localconfig, sth) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tools/merge_backup.py b/tools/merge_backup.py old mode 100644 new mode 100755 index 27c71a5..48197fc --- a/tools/merge_backup.py +++ b/tools/merge_backup.py @@ -7,12 +7,15 @@ import sys import base64 import select -from certtools import timing_point +from time import sleep +from certtools import timing_point, build_merkle_tree, write_file, \ + create_ssl_context from mergetools import chunks, backup_sendlog, get_logorder, \ get_verifiedsize, get_missingentriesforbackup, read_chain, \ - hexencode, setverifiedsize, sendentry_merge, verifyroot + hexencode, setverifiedsize, sendentry_merge, verifyroot, \ + get_nfetched, parse_args -def merge_backup(args, config, localconfig, sth_in): +def merge_backup(args, config, localconfig): paths = localconfig["paths"] own_key = (localconfig["nodename"], "%s/%s-private.pem" % (paths["privatekeys"], @@ -21,12 +24,17 @@ def merge_backup(args, config, localconfig, sth_in): mergedb = paths["mergedb"] chainsdir = mergedb + "/chains" logorderfile = mergedb + "/logorder" + currentsizefile = mergedb + "/fetched" timing = timing_point() - logorder = get_logorder(logorderfile) + nfetched = get_nfetched(currentsizefile, logorderfile) + logorder = get_logorder(logorderfile, nfetched) + tree_size = len(logorder) timing_point(timing, "get logorder") - (tree_size, root_hash, _) = sth_in + tree = build_merkle_tree(logorder) + root_hash = tree[-1][0] + timing_point(timing, "build tree") for secondary in secondaries: if secondary["name"] == config["primarymergenode"]: @@ -40,6 +48,7 @@ def merge_backup(args, config, localconfig, sth_in): timing_point(timing, "get verified size") print >>sys.stderr, "verified size", verifiedsize sys.stderr.flush() + entries = [base64.b64encode(entry) for entry in logorder[verifiedsize:]] print >>sys.stderr, "sending log:", sys.stderr.flush() @@ -57,7 +66,7 @@ def merge_backup(args, config, localconfig, sth_in): continue break if sendlogresult["result"] != "ok": - print >>sys.stderr, "sendlog:", sendlogresult + print >>sys.stderr, "backup_sendlog:", sendlogresult sys.exit(1) verifiedsize += len(chunk) print >>sys.stderr, verifiedsize, @@ -66,11 +75,13 @@ def merge_backup(args, config, localconfig, sth_in): timing_point(timing, "sendlog") print >>sys.stderr, "log sent" sys.stderr.flush() + missingentries = get_missingentriesforbackup(nodename, nodeaddress, own_key, paths) timing_point(timing, "get missing") print >>sys.stderr, "missing entries:", len(missingentries) sys.stderr.flush() + fetched_entries = 0 print >>sys.stderr, "fetching missing entries", sys.stderr.flush() @@ -81,7 +92,7 @@ def merge_backup(args, config, localconfig, sth_in): read_chain(chainsdir, ehash), ehash) if sendentryresult["result"] != "ok": - print >>sys.stderr, "send sth:", sendentryresult + print >>sys.stderr, "sendentry_merge:", sendentryresult sys.exit(1) fetched_entries += 1 if fetched_entries % 1000 == 0: @@ -90,6 +101,7 @@ def merge_backup(args, config, localconfig, sth_in): print >>sys.stderr sys.stderr.flush() timing_point(timing, "send missing") + verifyrootresult = verifyroot(nodename, nodeaddress, own_key, paths, tree_size) if verifyrootresult["result"] != "ok": @@ -102,7 +114,39 @@ def merge_backup(args, config, localconfig, sth_in): print >>sys.stderr, " expected", hexencode(root_hash) sys.exit(1) timing_point(timing, "verifyroot") + setverifiedsize(nodename, nodeaddress, own_key, paths, tree_size) + backuppath = mergedb + "/verified." + nodename + backupdata = {"tree_size": tree_size, + "sha256_root_hash": hexencode(root_hash)} + print >>sys.stderr, "DEBUG: writing to", backuppath, ":", backupdata + write_file(backuppath, backupdata) + if args.timing: print >>sys.stderr, timing["deltatimes"] sys.stderr.flush() + +def main(): + """ + Read logorder file up until what's indicated by fetched file and + build the tree. + + Distribute entries to all secondaries, write tree size and tree head + to backup. files as each secondary is verified to have + the entries. + + Sleep some and start over. + """ + args, config, localconfig = parse_args() + paths = localconfig["paths"] + create_ssl_context(cafile=paths["https_cacertfile"]) + + while True: + merge_backup(args, config, localconfig) + if args.interval is None: + break + print >>sys.stderr, "sleeping", args.interval, "seconds" + sleep(args.interval) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/merge_dist.py b/tools/merge_dist.py old mode 100644 new mode 100755 index bfc0e61..0e85984 --- a/tools/merge_dist.py +++ b/tools/merge_dist.py @@ -5,74 +5,56 @@ # See LICENSE for licensing information. import sys -import urllib2 -import base64 -import select -from certtools import timing_point, check_sth_signature, \ - create_sth_signature, get_public_key_from_file +import json +from time import sleep +from base64 import b64encode, b64decode +from certtools import timing_point, \ + create_ssl_context from mergetools import get_curpos, get_logorder, chunks, get_missingentries, \ - sendsth, hexencode, sendlog, sendentry, read_chain + sendsth, sendlog, sendentry, read_chain, parse_args -def merge_dist(args, config, localconfig, sth_in): +def merge_dist(args, config, localconfig, timestamp): paths = localconfig["paths"] own_key = (localconfig["nodename"], "%s/%s-private.pem" % (paths["privatekeys"], localconfig["nodename"])) frontendnodes = config["frontendnodes"] - signingnodes = config["signingnodes"] - ctbaseurl = config["baseurl"] - logpublickey = get_public_key_from_file(paths["logpublickey"]) mergedb = paths["mergedb"] chainsdir = mergedb + "/chains" logorderfile = mergedb + "/logorder" + sthfile = mergedb + "/sth" + create_ssl_context(cafile=paths["https_cacertfile"]) timing = timing_point() - logorder = get_logorder(logorderfile) - timing_point(timing, "get logorder") - - (tree_size, root_hash, timestamp) = sth_in - tree_head_signature = None - for signingnode in signingnodes: - try: - tree_head_signature = \ - create_sth_signature(tree_size, timestamp, - root_hash, - "https://%s/" % signingnode["address"], - key=own_key) - break - except urllib2.URLError, err: - print >>sys.stderr, err - sys.stderr.flush() - if tree_head_signature == None: - print >>sys.stderr, "Could not contact any signing nodes" - sys.exit(1) - - sth = {"tree_size": tree_size, "timestamp": timestamp, - "sha256_root_hash": base64.b64encode(root_hash), - "tree_head_signature": base64.b64encode(tree_head_signature)} - - check_sth_signature(ctbaseurl, sth, publickey=logpublickey) + try: + sth = json.loads(open(sthfile, 'r').read()) + except (IOError, ValueError): + print >>sys.stderr, "No valid STH file found in", sthfile + return timestamp + if sth['timestamp'] < timestamp: + print >>sys.stderr, "New STH file older than the previous one:", \ + sth['timestamp'], "<", timestamp + return timestamp + if sth['timestamp'] == timestamp: + return timestamp + timestamp = sth['timestamp'] - timing_point(timing, "build sth") - - if args.timing: - print >>sys.stderr, timing["deltatimes"] - sys.stderr.flush() - - print hexencode(root_hash) - sys.stdout.flush() + logorder = get_logorder(logorderfile, sth['tree_size']) + timing_point(timing, "get logorder") for frontendnode in frontendnodes: nodeaddress = "https://%s/" % frontendnode["address"] nodename = frontendnode["name"] timing = timing_point() + print >>sys.stderr, "distributing for node", nodename sys.stderr.flush() curpos = get_curpos(nodename, nodeaddress, own_key, paths) timing_point(timing, "get curpos") print >>sys.stderr, "current position", curpos sys.stderr.flush() - entries = [base64.b64encode(entry) for entry in logorder[curpos:]] + + entries = [b64encode(entry) for entry in logorder[curpos:]] print >>sys.stderr, "sending log:", sys.stderr.flush() for chunk in chunks(entries, 1000): @@ -83,7 +65,7 @@ def merge_dist(args, config, localconfig, sth_in): if sendlogresult == None: if trynumber == 1: sys.exit(1) - select.select([], [], [], 10.0) + sleep(10) print >>sys.stderr, "tries left:", trynumber sys.stderr.flush() continue @@ -98,20 +80,22 @@ def merge_dist(args, config, localconfig, sth_in): timing_point(timing, "sendlog") print >>sys.stderr, "log sent" sys.stderr.flush() + missingentries = get_missingentries(nodename, nodeaddress, own_key, paths) timing_point(timing, "get missing") + print >>sys.stderr, "missing entries:", len(missingentries) sys.stderr.flush() fetched_entries = 0 print >>sys.stderr, "fetching missing entries", sys.stderr.flush() for missingentry in missingentries: - ehash = base64.b64decode(missingentry) + ehash = b64decode(missingentry) sendentryresult = sendentry(nodename, nodeaddress, own_key, paths, read_chain(chainsdir, ehash), ehash) if sendentryresult["result"] != "ok": - print >>sys.stderr, "send sth:", sendentryresult + print >>sys.stderr, "sendentry:", sendentryresult sys.exit(1) fetched_entries += 1 if fetched_entries % 1000 == 0: @@ -120,11 +104,33 @@ def merge_dist(args, config, localconfig, sth_in): print >>sys.stderr sys.stderr.flush() timing_point(timing, "send missing") + + print >>sys.stderr, "sending sth to node", nodename + sys.stderr.flush() sendsthresult = sendsth(nodename, nodeaddress, own_key, paths, sth) if sendsthresult["result"] != "ok": - print >>sys.stderr, "send sth:", sendsthresult + print >>sys.stderr, "sendsth:", sendsthresult sys.exit(1) timing_point(timing, "send sth") + if args.timing: print >>sys.stderr, timing["deltatimes"] sys.stderr.flush() + + return timestamp + +def main(): + """ + Distribute missing entries and the STH to all frontend nodes. + """ + args, config, localconfig = parse_args() + timestamp = 0 + while True: + timestamp = merge_dist(args, config, localconfig, timestamp) + if args.interval is None: + break + print >>sys.stderr, "sleeping", args.interval, "seconds" + sleep(args.interval) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/merge_fetch.py b/tools/merge_fetch.py old mode 100644 new mode 100755 index a0a0396..1540c34 --- a/tools/merge_fetch.py +++ b/tools/merge_fetch.py @@ -6,13 +6,14 @@ import sys import struct -import time import subprocess +from time import sleep from mergetools import get_logorder, verify_entry, get_new_entries, \ - chunks, fsync_logorder, get_entries, write_chain, add_to_logorder -from certtools import timing_point, build_merkle_tree + chunks, fsync_logorder, get_entries, write_chain, add_to_logorder, \ + hexencode, parse_args +from certtools import timing_point, write_file, create_ssl_context -def merge_fetch(args, config, localconfig): +def merge_fetch(_args, config, localconfig): paths = localconfig["paths"] storagenodes = config["storagenodes"] mergedb = paths["mergedb"] @@ -21,7 +22,6 @@ def merge_fetch(args, config, localconfig): own_key = (localconfig["nodename"], "%s/%s-private.pem" % (paths["privatekeys"], localconfig["nodename"])) - timing = timing_point() logorder = get_logorder(logorderfile) @@ -48,9 +48,6 @@ def merge_fetch(args, config, localconfig): print >>sys.stderr, "adding", len(new_entries), "entries" sys.stderr.flush() - if args.nomerge: - sys.exit(0) - for ehash in new_entries: for storagenode in storagenodes: if ehash in new_entries_per_node[storagenode["name"]]: @@ -89,9 +86,36 @@ def merge_fetch(args, config, localconfig): verifycert.communicate(struct.pack("I", 0)) - tree = build_merkle_tree(logorder) tree_size = len(logorder) - root_hash = tree[-1][0] - timestamp = int(time.time() * 1000) + if tree_size == 0: + return (0, '') + else: + return (tree_size, logorder[tree_size-1]) + +def main(): + """ + Fetch new entries from all storage nodes. + + Indicate current position by writing the index in the logorder file + (0-based) to the 'fetched' file. + + Sleep some and start over. + """ + args, config, localconfig = parse_args() + paths = localconfig["paths"] + mergedb = paths["mergedb"] + currentsizefile = mergedb + "/fetched" + create_ssl_context(cafile=paths["https_cacertfile"]) + + while True: + logsize, last_hash = merge_fetch(args, config, localconfig) + currentsize = {"index": logsize - 1, "hash": hexencode(last_hash)} + print >>sys.stderr, "DEBUG: writing to", currentsizefile, ":", currentsize + write_file(currentsizefile, currentsize) + if args.interval is None: + break + print >>sys.stderr, "sleeping", args.interval, "seconds" + sleep(args.interval) - return (tree_size, root_hash, timestamp) +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/merge_sth.py b/tools/merge_sth.py new file mode 100755 index 0000000..68b52a0 --- /dev/null +++ b/tools/merge_sth.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014-2015, NORDUnet A/S. +# See LICENSE for licensing information. + +import sys +import json +import urllib2 +import time +from base64 import b64encode, b64decode +from mergetools import parse_args, get_nfetched, hexencode, hexdecode, \ + get_logorder, get_sth +from certtools import create_ssl_context, get_public_key_from_file, \ + timing_point, create_sth_signature, write_file, check_sth_signature, \ + build_merkle_tree + +def merge_sth(args, config, localconfig): + paths = localconfig["paths"] + own_key = (localconfig["nodename"], + "%s/%s-private.pem" % (paths["privatekeys"], + localconfig["nodename"])) + ctbaseurl = config["baseurl"] + signingnodes = config["signingnodes"] + mergenodes = config.get("mergenodes", []) + mergedb = paths["mergedb"] + sthfile = mergedb + "/sth" + logorderfile = mergedb + "/logorder" + logpublickey = get_public_key_from_file(paths["logpublickey"]) + backupquorum = localconfig.get("backupquorum", 0) + assert backupquorum <= len(mergenodes) - 1 + create_ssl_context(cafile=paths["https_cacertfile"]) + timing = timing_point() + + trees = [{'tree_size': 0, 'sha256_root_hash': ''}] + for mergenode in mergenodes: + if mergenode["name"] == config["primarymergenode"]: + continue + verifiedfile = mergedb + "/verified." + mergenode["name"] + try: + tree = json.loads(open(verifiedfile, "r").read()) + except (IOError, ValueError): + tree = {'tree_size': 0, "sha256_root_hash": ''} + trees.append(tree) + trees.sort(key=lambda e: e['tree_size'], reverse=True) + print >>sys.stderr, "DEBUG: trees:", trees + tree_size = trees[backupquorum]['tree_size'] + root_hash = hexdecode(trees[backupquorum]['sha256_root_hash']) + print >>sys.stderr, "DEBUG: tree size candidate at backupquorum", \ + backupquorum, ":", tree_size + + cur_sth = get_sth(sthfile) + if tree_size < cur_sth['tree_size']: + print >>sys.stderr, "candidate tree < current tree:", \ + tree_size, "<", cur_sth['tree_size'] + return + + assert tree_size >= 0 # Don't read logorder without limit. + logorder = get_logorder(logorderfile, tree_size) + timing_point(timing, "get logorder") + if tree_size == -1: + tree_size = len(logorder) + print >>sys.stderr, "new tree size will be", tree_size + + root_hash_calc = build_merkle_tree(logorder)[-1][0] + assert root_hash == '' or root_hash == root_hash_calc + root_hash = root_hash_calc + timestamp = int(time.time() * 1000) + + tree_head_signature = None + for signingnode in signingnodes: + try: + tree_head_signature = \ + create_sth_signature(tree_size, timestamp, + root_hash, + "https://%s/" % signingnode["address"], + key=own_key) + break + except urllib2.URLError, err: + print >>sys.stderr, err + sys.stderr.flush() + if tree_head_signature == None: + print >>sys.stderr, "Could not contact any signing nodes" + sys.exit(1) + + sth = {"tree_size": tree_size, "timestamp": timestamp, + "sha256_root_hash": b64encode(root_hash), + "tree_head_signature": b64encode(tree_head_signature)} + + check_sth_signature(ctbaseurl, sth, publickey=logpublickey) + timing_point(timing, "build sth") + + print hexencode(root_hash), timestamp, tree_size + sys.stdout.flush() + + write_file(sthfile, sth) + + if args.timing: + print >>sys.stderr, timing["deltatimes"] + sys.stderr.flush() + +def main(): + """ + Read file 'sth' to get current tree size, assuming zero if file not + found. + + Read tree sizes from the backup. files, put them in a + list and sort it. Let new tree size equal list[backup-quorum]. Barf + on a new tree size smaller than the currently published tree size. + + Decide on a timestamp, build an STH and write it to file 'sth'. + """ + args, config, localconfig = parse_args() + + while True: + merge_sth(args, config, localconfig) + if args.interval is None: + break + print >>sys.stderr, "sleeping", args.interval, "seconds" + time.sleep(args.interval) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/mergetools.py b/tools/mergetools.py index 7644dac..86f9255 100644 --- a/tools/mergetools.py +++ b/tools/mergetools.py @@ -9,14 +9,43 @@ import struct import urllib import urllib2 import json +import yaml +import argparse from certtools import get_leaf_hash, http_request, get_leaf_hash def parselogrow(row): return base64.b16decode(row, casefold=True) -def get_logorder(filename): - f = open(filename, "r") - return [parselogrow(row.rstrip()) for row in f] +def get_logorder(filename, items=-1): + logorder = [] + n = 0 + for row in open(filename, "r"): + if n == items: + break + logorder.append(parselogrow(row.rstrip())) + n += 1 + return logorder + +def get_nfetched(currentsizefile, logorderfile): + try: + limit = json.loads(open(currentsizefile).read()) + except (IOError, ValueError): + return -1 + if limit['index'] >= 0: + with open(logorderfile, 'r') as f: + f.seek(limit['index']*65) + assert f.read(64).lower() == limit['hash'] + return limit['index'] + 1 + +def get_sth(filename): + try: + sth = json.loads(open(filename, 'r').read()) + except (IOError, ValueError): + sth = {'tree_size': -1, + 'timestamp': 0, + 'sha256_root_hash': '', + 'tree_head_signature': ''} + return sth def read_chain_open(chainsdir, filename): path = chainsdir + "/" + \ @@ -104,6 +133,9 @@ def verify_entry(verifycert, entry, ehash): def hexencode(key): return base64.b16encode(key).lower() +def hexdecode(s): + return base64.b16decode(s.upper()) + def write_chain(key, value, chainsdir, hashed_dir=True): filename = hexencode(key) if hashed_dir: @@ -356,3 +388,20 @@ def get_missingentriesforbackup(node, baseurl, own_key, paths): def chunks(l, n): return [l[i:i+n] for i in range(0, len(l), n)] + +def parse_args(): + parser = argparse.ArgumentParser(description="") + parser.add_argument('--config', help="System configuration", + required=True) + parser.add_argument('--localconfig', help="Local configuration", + required=True) + parser.add_argument('--interval', type=int, metavar="n", + help="Repeate every N seconds") + parser.add_argument("--timing", action='store_true', + help="Print timing information") + args = parser.parse_args() + + config = yaml.load(open(args.config)) + localconfig = yaml.load(open(args.localconfig)) + + return (args, config, localconfig) diff --git a/tools/testcase1.py b/tools/testcase1.py index c66d976..697cc99 100755 --- a/tools/testcase1.py +++ b/tools/testcase1.py @@ -37,7 +37,7 @@ logpublickey = get_public_key_from_file(logpublickeyfile) def testgroup(name): global indentation - print name + ":" + print "testgroup " + name + ":" indentation = " " def print_error(message, *args): @@ -147,7 +147,7 @@ def get_and_check_entry(timestamp, chain, leaf_index, baseurl): len(submittedcertchain)) def merge(): - return subprocess.call(["../tools/merge.py", "--config", "../test/catlfish-test.cfg", + return subprocess.call(["../tools/merge", "--config", "../test/catlfish-test.cfg", "--localconfig", "../test/catlfish-test-local-merge.cfg"]) mergeresult = merge() -- cgit v1.1