diff options
Diffstat (limited to 'scripts/convert-from-csv-to-entitydb.py')
-rw-r--r-- | scripts/convert-from-csv-to-entitydb.py | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/scripts/convert-from-csv-to-entitydb.py b/scripts/convert-from-csv-to-entitydb.py new file mode 100644 index 00000000..282d2e75 --- /dev/null +++ b/scripts/convert-from-csv-to-entitydb.py @@ -0,0 +1,233 @@ +""" +Convert {parents,children,pubclients}.csv into new XML formats. + +$Id$ + +Copyright (C) 2010 Internet Systems Consortium ("ISC") + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +""" + +import subprocess, csv, re, os, getopt, sys, base64, urlparse +import rpki.sundial, myrpki, rpki.config + +from lxml.etree import Element, SubElement, ElementTree + +section_regexp = re.compile("\s*\[\s*(.+?)\s*\]\s*$") +variable_regexp = re.compile("\s*([-a-zA-Z0-9_]+)(\s*=\s*)(.+?)\s*$") + +cfg_file = "myrpki.conf" +template_file = os.path.join(os.path.dirname(sys.argv[0]), "examples", "myrpki.conf") +new_cfg_file = None +preserve_valid_until = False + +opts, argv = getopt.getopt(sys.argv[1:], "c:hn:pt:?", ["config=", "new_config=", "preserve_valid_until", "template_config=", "help"]) +for o, a in opts: + if o in ("-h", "--help", "-?"): + print __doc__ + sys.exit(0) + elif o in ("-c", "--config"): + cfg_file = a + elif o in ("-n", "--new_config"): + new_cfg_file = a + elif o in ("-p", "--preserve_valid_until"): + preserve_valid_until = True + elif o in ("-t", "--template_config"): + template_file = a +if argv: + raise RuntimeError, "Unexpected arguments %r" % (argv,) +if os.path.samefile(cfg_file, template_file): + raise RuntimeError, "Old config and template for new config can't be the same file" +if new_cfg_file is None: + new_cfg_file = cfg_file + ".new" +if os.path.exists(new_cfg_file): + raise RuntimeError, "%s already exists, NOT overwriting" % new_cfg_file + +cfg = rpki.config.parser(cfg_file) + +# These have no counterparts in new config file, just read them from old + +repository_bpki_certificate = cfg.get(option = "repository_bpki_certificate", section = "myrpki") +repository_handle = cfg.get(option = "repository_handle", section = "myrpki") +parents_csv = cfg.get(option = "parents_csv", section = "myrpki", default = "parents.csv") +children_csv = cfg.get(option = "children_csv", section = "myrpki", default = "children.csv") +pubclients_csv = cfg.get(option = "pubclients_csv", section = "myrpki", default = "pubclients.csv") +pubd_base = cfg.get(option = "pubd_base", section = "myirbe") + +# Here we need to construct values for the new config file from the +# old one. Basic model here is to look at whatever variables need to +# be set in the template (mostly just the [myrpki], I hope), pull +# necessary data from old config file any way we can. Stuff that +# didn't make the jump from old config file to new we can just ignore, +# stuff that is automated via macro expansions in the new config file +# should be ok without modification. + +r = {} + +if cfg.has_section("myrpki"): + for i in ("handle", "roa_csv", "prefix_csv", "asn_csv", "xml_filename"): + r["myrpki", i] = cfg.get(section = "myrpki", option = i) + r["myrpki", "bpki_resources_directory"] = cfg.get(option = "bpki_directory", section = "myrpki") + +if cfg.has_section("myirbe"): + r["myrpki", "bpki_servers_directory"] = cfg.get(option = "bpki_directory", section = "myirbe") + r["myrpki", "run_rpkid"] = True + r["myrpki", "run_pubd"] = cfg.getboolean(option = "want_pubd", section = "myirbe", default = False) + r["myrpki", "run_rootd"] = cfg.getboolean(option = "want_rootd", section = "myirbe", default = False) +else: + for i in ("run_rpkid", "run_pubd", "run_rootd"): + r["myrpki", i] = False + +if cfg.has_section("rpkid"): + r["myrpki", "rpkid_server_host"] = cfg.get(option = "server-host", section = "rpkid") + r["myrpki", "rpkid_server_port"] = cfg.get(option = "server-port", section = "rpkid") + +if cfg.has_section("irdbd"): + u = urlparse.urlparse(cfg.get(option = "https-url", section = "irdbd")) + r["myrpki", "irdbd_server_host"] = u.hostname or "localhost" + r["myrpki", "irdbd_server_port"] = u.port or 443 + +if cfg.has_section("pubd"): + r["myrpki", "pubd_server_host"] = cfg.get(option = "server-host", section = "pubd") + r["myrpki", "pubd_server_port"] = cfg.get(option = "server-port", section = "pubd") + r["myrpki", "publication_base_directory"] = cfg.get(option = "publication-base", section = "pubd") + +if cfg.has_section("rootd"): + r["myrpki", "rootd_server_port"] = cfg.get(option = "server-port", section = "rootd") + u = urlparse.urlparse(cfg.get(option = "rpki-base-uri", section = "rootd")) + r["myrpki", "publication_rsync_server"] = u.netloc + +for i in ("rpkid", "irdbd", "pubd"): + if cfg.has_section(i): + for j in ("sql-database", "sql-username", "sql-password"): + r[i, j] = cfg.get(section = i, option = j) + +f = open(new_cfg_file, "w") +f.write("# Automatically converted from %s using %s as a template.\n\n" % (cfg_file, template_file)) +section = None +for line in open(template_file): + m = section_regexp.match(line) + if m: + section = m.group(1) + m = variable_regexp.match(line) + if m: + option, whitespace = m.group(1, 2) + else: + option = None + if (section, option) in r: + line = "%s%s%s\n" % (option, whitespace, r[section, option]) + f.write(line) +f.close() +print "Wrote", new_cfg_file + +# Get all of these from the new config file; in theory we just set all +# of them, but we want to use values matching new config in any case. + +newcfg = rpki.config.parser(new_cfg_file, "myrpki") + +handle = newcfg.get("handle") +bpki_resources_directory = newcfg.get("bpki_resources_directory") +bpki_servers_directory = newcfg.get("bpki_servers_directory") +pubd_server_host = newcfg.get("pubd_server_host") +pubd_server_port = newcfg.get("pubd_server_port") +rpkid_server_host = newcfg.get("rpkid_server_host") +rpkid_server_port = newcfg.get("rpkid_server_port") +entitydb_dir = newcfg.get("entitydb_dir", "entitydb") + +bpki_resources_pemfile = bpki_resources_directory + "/ca.cer" +bpki_servers_pemfile = bpki_servers_directory + "/ca.cer" + +def entitydb(*args): + return os.path.join(entitydb_dir, *args) + +# Now convert the .csv files. It'd be nice to have XML validation +# enabled for this, so try to turn it on ourselves if the magic +# environment variable hasn't already been set. + +rng_file = os.path.join(os.path.dirname(sys.argv[0]), "myrpki.rng") +if not os.getenv("MYRPKI_RNG") and os.path.exists(rng_file): + os.putenv("MYRPKI_RNG", rng_file) + +for d in map(entitydb, ("children", "parents", "repositories", "pubclients")): + if not os.path.exists(d): + os.makedirs(d) + +one_year_from_now = str(rpki.sundial.now() + rpki.sundial.timedelta(days = 365)) + +if os.path.exists(children_csv): + for child_handle, valid_until, child_resource_pemfile in myrpki.csv_reader(children_csv, columns = 3): + try: + + e = Element("parent", + valid_until = valid_until if preserve_valid_until else one_year_from_now, + service_uri = "https://%s:%s/up-down/%s/%s" % (rpkid_server_host, rpkid_server_port, handle, child_handle), + child_handle = child_handle, + parent_handle = handle) + myrpki.PEMElement(e, "bpki_resource_ta", bpki_resources_pemfile) + myrpki.PEMElement(e, "bpki_server_ta", bpki_servers_pemfile) + myrpki.PEMElement(e, "bpki_child_ta", child_resource_pemfile) + myrpki.etree_write(e, entitydb("children", "%s.xml" % child_handle)) + + except IOError: + pass + +if os.path.exists(parents_csv): + for parent_handle, parent_service_uri, parent_cms_pemfile, parent_https_pemfile, parent_myhandle, parent_sia_base in myrpki.csv_reader(parents_csv, columns = 6): + try: + + e = Element("parent", + valid_until = one_year_from_now, + service_uri = parent_service_uri, + child_handle = parent_myhandle, + parent_handle = parent_handle) + myrpki.PEMElement(e, "bpki_resource_ta", parent_cms_pemfile) + myrpki.PEMElement(e, "bpki_server_ta", parent_https_pemfile) + myrpki.PEMElement(e, "bpki_child_ta", bpki_resources_pemfile) + myrpki.etree_write(e, entitydb("parents", "%s.xml" % parent_handle)) + + client_handle = "/".join(parent_sia_base.rstrip("/").split("/")[3:]) + assert client_handle.startswith(repository_handle) + + e = Element("repository", + parent_handle = parent_handle, + client_handle = client_handle, + service_uri = "%s/client/%s" % (pubd_base.rstrip("/"), client_handle), + sia_base = parent_sia_base, + type = "confirmed") + myrpki.PEMElement(e, "bpki_server_ta", repository_bpki_certificate) + myrpki.PEMElement(e, "bpki_client_ta", bpki_resources_pemfile) + SubElement(e, "contact_info").text = "Automatically generated by convert-csv.py" + myrpki.etree_write(e, entitydb("repositories", "%s.xml" % parent_handle)) + + except IOError: + pass + +if os.path.exists(pubclients_csv): + for client_handle, client_resource_pemfile, client_sia_base in myrpki.csv_reader(pubclients_csv, columns = 3): + try: + + parent_handle = client_handle.split("/")[-2] if "/" in client_handle else handle + + e = Element("repository", + parent_handle = parent_handle, + client_handle = client_handle, + service_uri = "https://%s:%s/client/%s" % (pubd_server_host, pubd_server_port, client_handle), + sia_base = client_sia_base, + type = "confirmed") + myrpki.PEMElement(e, "bpki_server_ta", bpki_servers_pemfile) + myrpki.PEMElement(e, "bpki_client_ta", client_resource_pemfile) + SubElement(e, "contact_info").text = "Automatically generated by convert-csv.py" + myrpki.etree_write(e, entitydb("pubclients", "%s.xml" % client_handle.replace("/", "."))) + + except IOError: + pass |