diff options
author | Rob Austein <sra@hactrn.net> | 2015-11-11 03:22:38 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2015-11-11 03:22:38 +0000 |
commit | 9f6d6462a9cef37735a9d4c61921d04934fd9864 (patch) | |
tree | e5d1b046f6f6bd44faf1b5028f6f1df9698e2a88 | |
parent | ac415cdd0f88f8479975627772dd0a84797b261a (diff) |
Configure pylint to use the pylint-django plugin, which (mostly)
understands Django's exotic metaclasses, which in turn allows us to
re-enable a number of pylint checks we had disabled. While we were at
this, stripped out a bunch of old pylint pragmas, then added back the
subset that were really needed. As usual with pylint, this turned up
a few real bugs along with an awful lot of noise.
svn path=/branches/tk705/; revision=6162
49 files changed, 484 insertions, 273 deletions
diff --git a/buildtools/make-relaxng.py b/buildtools/make-relaxng.py index 3d239e8a..a8b562fa 100644 --- a/buildtools/make-relaxng.py +++ b/buildtools/make-relaxng.py @@ -26,6 +26,8 @@ import sys header = """\ # Automatically generated, do not edit. +# pylint: skip-file + from rpki.relaxng_parser import RelaxNGParser """ diff --git a/buildtools/pylint.rc b/buildtools/pylint.rc index 1c57aa22..ac893ad6 100644 --- a/buildtools/pylint.rc +++ b/buildtools/pylint.rc @@ -24,11 +24,13 @@ profile=no # making ten zillion cosmetic changes in a co-worker's code on a # long-running development branch. -ignore=.svn,.git,migrations,south_migrations,irbe_cli,gui +ignore=.svn,.git,migrations,south_migrations,gui persistent=yes cache-size=500 -load-plugins= + +# We make heavy use of Django, which confuses pylint. Fortunately, there's a plug-in. +load-plugins=pylint_django # Extension (C, etc) modules that pylint should trust enough to import. @@ -54,7 +56,18 @@ disable-msg-cat= #enable-msg= # Disable the message(s) with the given id(s). -disable=R0801,R0903,R0913,C0321,R0904,W0201,E1101,W0614,C0301,R0901,C0302,R0902,R0201,W0613,R0912,R0915,W0703,W0212,R0914,W0603,W0142,I0011,C0111,C0103,R0401,C0326,R0911,C0325,C0330,W0311,E1124,W0702 +# +# I0011 is (sort of) special, in that it marks places where we've used +# inline overrides in the code to control pylint's behavior. +# Ordinarily we leave this turned off, but it's a good idea to run +# with it enabled every once in a while to see what we've overriden. +# +disable=I0011,I0013,R0801,C0111,C0301,C0326,W0702,R0902,R0913,W0703,R0912,R0903,R0915,R0914,C0302,W0613,R0201,R0901,R0904,C0325,R0911,C0103,R0401 +# +# Additional messages we used to have disabled but now appear to be +# able to leave alone. +# +#disable=C0321,W0201,E1101,W0614,W0212,W0603,W0142,C0330,W0311,E1124 [REPORTS] diff --git a/ca/irbe_cli b/ca/irbe_cli index 59039bf9..15a7a30d 100755 --- a/ca/irbe_cli +++ b/ca/irbe_cli @@ -50,6 +50,9 @@ import rpki.publication pem_out = None +# This program needs a complete rewrite. In the meantime, shut up about lint. +# pylint: skip-file + class UsageWrapper(textwrap.TextWrapper): """ Call interface around Python textwrap.Textwrapper class. @@ -207,7 +210,7 @@ class left_right_msg(cmd_msg_mixin, rpki.left_right.msg): for x in (self_elt, bsc_elt, parent_elt, child_elt, repository_elt, list_published_objects_elt, list_received_resources_elt, report_error_elt)) -class left_right_sax_handler(rpki.left_right.sax_handler): # pylint: disable=W0232 +class left_right_sax_handler(rpki.left_right.sax_handler): pdu = left_right_msg class left_right_cms_msg(rpki.left_right.cms_msg): @@ -251,7 +254,7 @@ class publication_msg(cmd_msg_mixin, rpki.publication.msg): manifest_elt, roa_elt, report_error_elt, ghostbuster_elt)) -class publication_sax_handler(rpki.publication.sax_handler): # pylint: disable=W0232 +class publication_sax_handler(rpki.publication.sax_handler): pdu = publication_msg class publication_cms_msg(rpki.publication.cms_msg): diff --git a/ca/rpki-sql-setup b/ca/rpki-sql-setup index c399fcfe..297571a2 100755 --- a/ca/rpki-sql-setup +++ b/ca/rpki-sql-setup @@ -51,6 +51,7 @@ class RootDB(object): self.mysql_defaults = mysql_defaults def __getattr__(self, name): + # pylint: disable=W0201 if self.initialized: raise AttributeError if self.mysql_defaults is None: @@ -70,7 +71,7 @@ class RootDB(object): def close(self): if self.initialized: - self.db.close() + self.db.close() # pylint: disable=E1101 class UserDB(object): @@ -112,15 +113,17 @@ class UserDB(object): self.cur.close() self.cur = None if self.db is not None: + # pylint: disable=E1101 self.db.commit() self.db.close() self.db = None @property def exists_and_accessible(self): + # pylint: disable=E1101 try: MySQLdb.connect(db = self.database, user = self.username, passwd = self.password).close() - except: # pylint: disable=W0702 + except: return False else: return True @@ -143,7 +146,7 @@ class UserDB(object): if v > self.version: self.cur.execute("DELETE FROM upgrade_version") self.cur.execute("INSERT upgrade_version (version, updated) VALUES (%s, %s)", (v, datetime.datetime.now())) - self.db.commit() + self.db.commit() # pylint: disable=E1101 log("Updated %s to %s" % (self.name, v)) @@ -192,7 +195,7 @@ class Upgrade(object): # db is an argument here primarily so the script we exec can get at it log("Applying %s to %s" % (self.fn, db.name)) with open(self.fn, "r") as f: - exec f # pylint: disable=W0122 + exec f # pylint: disable=W0122 def do_drop(name): @@ -200,7 +203,7 @@ def do_drop(name): if db.database in root.databases: log("DROP DATABASE %s" % db.database) root.cur.execute("DROP DATABASE %s" % db.database) - root.db.commit() + root.db.commit() # pylint: disable=E1101 def do_create(name): db = UserDB(name) @@ -209,7 +212,7 @@ def do_create(name): log("GRANT ALL ON %s.* TO %s@localhost IDENTIFIED BY ###" % (db.database, db.username)) root.cur.execute("GRANT ALL ON %s.* TO %s@localhost IDENTIFIED BY %%s" % (db.database, db.username), (db.password,)) - root.db.commit() + root.db.commit() # pylint: disable=E1101 db.open() db.version = current_version db.close() @@ -228,7 +231,7 @@ def do_fix_grants(name): log("GRANT ALL ON %s.* TO %s@localhost IDENTIFIED BY ###" % (db.database, db.username)) root.cur.execute("GRANT ALL ON %s.* TO %s@localhost IDENTIFIED BY %%s" % (db.database, db.username), (db.password,)) - root.db.commit() + root.db.commit() # pylint: disable=E1101 def do_create_if_missing(name): db = UserDB(name) diff --git a/ca/rpki-start-servers b/ca/rpki-start-servers index e01f4f9b..9bf47d0c 100755 --- a/ca/rpki-start-servers +++ b/ca/rpki-start-servers @@ -68,7 +68,6 @@ cfg = rpki.config.parser(set_filename = args.config, section = "myrpki") def run(name, old_flag = None): if cfg.getboolean("start_" + name, cfg.getboolean("run_" + name if old_flag is None else old_flag, False)): - # pylint: disable=E1103 log_file = os.path.join(args.log_directory, name + ".log") cmd = (os.path.join(rpki.autoconf.libexecdir, name), "--log-level", args.log_level) if args.log_file: diff --git a/ca/rpkigui-apache-conf-gen b/ca/rpkigui-apache-conf-gen index a6a58c2c..b617b4ac 100755 --- a/ca/rpkigui-apache-conf-gen +++ b/ca/rpkigui-apache-conf-gen @@ -207,6 +207,7 @@ def Guess(args): return Redhat(args) raise NotImplementedError("Can't guess what platform this is, sorry") + class Platform(object): """ Abstract base class representing an operating system platform. @@ -317,6 +318,13 @@ class Platform(object): # on the details of your particular Apache configuration. ''' % (self.apache_conf_sample, self.apache_conf)) + @property + def apache_conf_target(self): + raise NotImplementedError + + def restart(self): + raise NotImplementedError + def install(self): with open(self.apache_conf_sample, "w") as f: self.log("Writing %s" % f.name) @@ -353,7 +361,7 @@ class Platform(object): def remove(self): try: same = open(self.apache_conf, "r").read() == open(self.apache_conf_sample, "r").read() - except: # pylint: disable=W0702 + except: same = False self.unlink(self.apache_conf_sample) if same: @@ -393,6 +401,7 @@ class Platform(object): return True return False + class FreeBSD(Platform): """ FreeBSD. @@ -429,6 +438,7 @@ class FreeBSD(Platform): def restart(self): self.run("service", self.apache_name, "restart") + class Debian(Platform): """ Debian and related platforms like Ubuntu. @@ -474,6 +484,7 @@ class Debian(Platform): def restart(self): self.run("service", "apache2", "restart") + class Ubuntu(Debian): # On Ubuntu, the filename must end in .conf on Trusty and must not @@ -485,20 +496,18 @@ class Ubuntu(Debian): else: return "/etc/apache2/sites-available/rpki" -class NIY(Platform): + +class NIY(Platform): # pylint: disable=W0223 def __init__(self, args): super(NIY, self).__init__(args) raise NotImplementedError("Platform %s not implemented yet, sorry" % self.__class__.__name__) -class Redhat(NIY): - """ - Redhat family of Linux distributions (Fedora, CentOS). - """ +class Redhat(NIY): # pylint: disable=W0223 + "Redhat family of Linux distributions (Fedora, CentOS)." + +class Darwin(NIY): # pylint: disable=W0223 + "Mac OS X (aka Darwin)." -class Darwin(NIY): - """ - Mac OS X (aka Darwin). - """ def main(): """ diff --git a/ca/tests/yamltest.py b/ca/tests/yamltest.py index 3740cbf6..a7ee6540 100755 --- a/ca/tests/yamltest.py +++ b/ca/tests/yamltest.py @@ -36,8 +36,6 @@ and waits for one of them to exit. # running daemons. # -# pylint: disable=W0702,W0621 - import subprocess import re import os @@ -57,6 +55,8 @@ import rpki.csv_utils import rpki.x509 import rpki.relaxng +# pylint: disable=W0621 + # Nasty regular expressions for parsing config files. Sadly, while # the Python ConfigParser supports writing config files, it does so in # such a limited way that it's easier just to hack this ourselves. @@ -288,7 +288,7 @@ class allocation(object): resources = self.base for kid in self.kids: resources |= kid.closure() - self.resources = resources + self.resources = resources # pylint: disable=W0201 return resources def dump(self): @@ -299,6 +299,7 @@ class allocation(object): print str(self) def __str__(self): + # pylint: disable=C0321 s = self.name + ":\n" if self.resources.asn: s += " ASNs: %s\n" % self.resources.asn if self.resources.v4: s += " IPv4: %s\n" % self.resources.v4 @@ -1111,12 +1111,6 @@ whack_ec_key_to_namedCurve(EVP_PKEY *pkey) * Validation status codes. Still under construction. Modeled after * rcynic's validation status database, conceptually anyway. * - * Probably need to add an optional (default NULL) slot in - * x509_store_ctx_object to hold the status set. Might also add a - * method to that class so that Python handlers can fiddle with the - * status from the callback, but am primarily thinking of the extended - * validation C code here. - * * Assuming we go this way, should we PySet_Clear() the status set * upon entering the _verify function? Probably. * @@ -4943,6 +4937,13 @@ x509_store_ctx_object_set_policy (x509_store_ctx_object *self, PyObject *args) #endif /* IMPLEMENT_X509StoreCTX_POLICY */ /* + * Do we need an access method to let Python callbacks fiddle with the + * validation status set? Maybe. Skip for now, add later if needed. + * May need to pay closer attention to initialization and reference + * count management of the status field if we exposing it. + */ + +/* * See (omnibus) man page for X509_STORE_CTX_get_error() for other * query methods we might want to expose. Someday we might want to * support X509_V_FLAG_USE_CHECK_TIME too. diff --git a/rp/rcynic/rcynic-cron b/rp/rcynic/rcynic-cron index 3d38726c..d1f96422 100755 --- a/rp/rcynic/rcynic-cron +++ b/rp/rcynic/rcynic-cron @@ -52,7 +52,7 @@ def run(*cmd, **kwargs): os.setuid(pw.pw_uid) os.closerange(3, os.sysconf("SC_OPEN_MAX")) os.execvp(cmd[0], cmd) - os._exit(1) + os._exit(1) # pylint: disable=W0212 else: status = os.waitpid(pid, 0)[1] if status == 0: diff --git a/rp/rcynic/rcynic-html b/rp/rcynic/rcynic-html index 012bccad..154193b2 100755 --- a/rp/rcynic/rcynic-html +++ b/rp/rcynic/rcynic-html @@ -41,7 +41,7 @@ args = None def parse_options(): - global args + global args # pylint: disable=W0603 parser = argparse.ArgumentParser(description = __doc__) parser.add_argument("--refresh", type = int, default = 1800, @@ -157,6 +157,8 @@ class Validation_Status(object): class Problem_Mixin(object): + # pylint: disable=E1101 + @property def connection_problems(self): result = [v for v in self.validation_status if v.is_connection_problem] @@ -595,7 +597,7 @@ class HTML(object): def main(): - global session + global session # pylint: disable=W0603 os.putenv("TZ", "UTC") time.tzset() diff --git a/rp/rcynic/rcynic-svn b/rp/rcynic/rcynic-svn index a9417d8d..3c59116a 100755 --- a/rp/rcynic/rcynic-svn +++ b/rp/rcynic/rcynic-svn @@ -171,6 +171,7 @@ run(*cmd, cwd = args.working_directory) # files have been deleted, and tell Subversion that we deleted them # intentionally. +# pylint: disable=E1101 missing = sorted(entry.get("path") for entry in runxml("svn", "status", "--xml", args.working_directory).find("target").findall("entry") if entry.find("wc-status").get("item") == "missing") diff --git a/rp/utils/find_roa b/rp/utils/find_roa index 15a2f25f..8b962d9c 100755 --- a/rp/utils/find_roa +++ b/rp/utils/find_roa @@ -61,7 +61,7 @@ class Prefix(object): if self.prefix & ((1 << (self.prefix.bits - self.length)) - 1) != 0: raise ValueError - def matches(self, roa): # pylint: disable=W0621 + def matches(self, roa): # pylint: disable=W0621 return any(self.prefix == prefix and self.length == length and (not args.match_maxlength or @@ -77,9 +77,9 @@ class ROA(rpki.POW.ROA): # pylint: disable=W0232 """ @classmethod - def parse(cls, fn): # pylint: disable=W0621 + def parse(cls, fn): # pylint: disable=W0621 assert fn.startswith(args.rcynic_dir) - self = cls.derReadFile(fn) + self = cls.derReadFile(fn) # pylint: disable=E1101 self.fn = fn self.extractWithoutVerifying() v4, v6 = self.getPrefixes() @@ -88,17 +88,18 @@ class ROA(rpki.POW.ROA): # pylint: disable=W0232 @property def uri(self): - return filename_to_uri(self.fn) + return filename_to_uri(self.fn) # pylint: disable=E1101 @property def formatted_prefixes(self): - for prefix in self.prefixes: + for prefix in self.prefixes: # pylint: disable=E1101 if prefix[2] is None or prefix[1] == prefix[2]: yield "%s/%d" % (prefix[0], prefix[1]) else: yield "%s/%d-%d" % (prefix[0], prefix[1], prefix[2]) def __str__(self): + # pylint: disable=E1101 prefixes = " ".join(self.formatted_prefixes) plural = "es" if " " in prefixes else "" if args.show_inception: @@ -107,12 +108,13 @@ class ROA(rpki.POW.ROA): # pylint: disable=W0232 return "ASN %s prefix%s %s" % (self.getASID(), plural, prefixes) def show(self): + # pylint: disable=E1101 print "%s %s" % (self, self.fn if args.show_filenames else self.uri) def show_expiration(self): print self - x = self.certs()[0] - fn = self.fn # pylint: disable=W0621 + x = self.certs()[0] # pylint: disable=E1101 + fn = self.fn # pylint: disable=E1101,W0621 uri = self.uri while uri is not None: name = fn if args.show_filenames else uri diff --git a/rp/utils/print_roa b/rp/utils/print_roa index 78ae244f..dd13447d 100755 --- a/rp/utils/print_roa +++ b/rp/utils/print_roa @@ -26,6 +26,9 @@ import rpki.POW class ROA(rpki.POW.ROA): # pylint: disable=W0232 + v4_prefixes = None + v6_prefixes = None + @staticmethod def _format_prefix(p): if p[2] in (None, p[1]): @@ -34,8 +37,8 @@ class ROA(rpki.POW.ROA): # pylint: disable=W0232 return "%s/%d-%d" % (p[0], p[1], p[2]) def parse(self): - self.extractWithoutVerifying() - v4, v6 = self.getPrefixes() + self.extractWithoutVerifying() # pylint: disable=E1101 + v4, v6 = self.getPrefixes() # pylint: disable=E1101 self.v4_prefixes = [self._format_prefix(p) for p in (v4 or ())] self.v6_prefixes = [self._format_prefix(p) for p in (v6 or ())] @@ -43,7 +46,7 @@ parser = argparse.ArgumentParser(description = __doc__) parser.add_argument("-b", "--brief", action = "store_true", help = "show only ASN and prefix(es)") parser.add_argument("-c", "--cms", action = "store_true", help = "print text representation of entire CMS blob") parser.add_argument("-s", "--signing-time", action = "store_true", help = "show SigningTime in brief mode") -parser.add_argument("roas", nargs = "+", type = ROA.derReadFile, help = "ROA(s) to print") +parser.add_argument("roas", nargs = "+", type = ROA.derReadFile, help = "ROA(s) to print") # pylint: disable=E1101 args = parser.parse_args() for roa in args.roas: diff --git a/rp/utils/scan_roas b/rp/utils/scan_roas index f4489f32..689d1365 100755 --- a/rp/utils/scan_roas +++ b/rp/utils/scan_roas @@ -34,14 +34,14 @@ def check_dir(d): class ROA(rpki.POW.ROA): # pylint: disable=W0232 @classmethod - def parse(cls, fn): # pylint: disable=W0621 - self = cls.derReadFile(fn) + def parse(cls, fn): # pylint: disable=W0621 + self = cls.derReadFile(fn) # pylint: disable=E1101 self.extractWithoutVerifying() return self @property def prefixes(self): - v4, v6 = self.getPrefixes() + v4, v6 = self.getPrefixes() # pylint: disable=E1101 for prefix, length, maxlength in (v4 or ()) + (v6 or ()): if maxlength is None or length == maxlength: yield "%s/%d" % (prefix, length) @@ -49,6 +49,7 @@ class ROA(rpki.POW.ROA): # pylint: disable=W0232 yield "%s/%d-%d" % (prefix, length, maxlength) def __str__(self): + # pylint: disable=E1101 return "%s %s %s" % (self.signingTime(), self.getASID(), " ".join(self.prefixes)) parser = argparse.ArgumentParser(description = __doc__) diff --git a/rp/utils/uri b/rp/utils/uri index 4fecf73a..65ca117b 100755 --- a/rp/utils/uri +++ b/rp/utils/uri @@ -46,7 +46,7 @@ class Certificate(object): def __init__(self, fn): try: x = rpki.POW.X509.derReadFile(fn) - except: # pylint: disable=W0702 + except: try: cms = rpki.POW.CMS.derReadFile(fn) cms.extractWithoutVerifying() diff --git a/rpki/POW/__init__.py b/rpki/POW/__init__.py index 7fb445e0..7f18b548 100644 --- a/rpki/POW/__init__.py +++ b/rpki/POW/__init__.py @@ -17,7 +17,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# pylint: disable=W0622,W0401 +# pylint: disable=W0401,W0622 from rpki.POW._POW import * from rpki.POW._POW import __doc__ diff --git a/rpki/adns.py b/rpki/adns.py index b0f235e7..365e9803 100644 --- a/rpki/adns.py +++ b/rpki/adns.py @@ -22,6 +22,8 @@ Basic asynchronous DNS code, using asyncore and Bob Halley's excellent dnspython package. """ +# pylint: skip-file + import sys import time import socket diff --git a/rpki/cli.py b/rpki/cli.py index 9440ecb2..0fdccf8b 100644 --- a/rpki/cli.py +++ b/rpki/cli.py @@ -82,12 +82,12 @@ class Cmd(cmd.Cmd): self.last_command_failed = True return False - def do_EOF(self, arg): # pylint: disable=W0613 + def do_EOF(self, arg): if self.EOF_exits_command_loop and self.prompt: print return self.EOF_exits_command_loop - def do_exit(self, arg): # pylint: disable=W0613,R0201 + def do_exit(self, arg): """ Exit program. """ @@ -106,7 +106,7 @@ class Cmd(cmd.Cmd): if self.emptyline_repeats_last_command: cmd.Cmd.emptyline(self) - def filename_complete(self, text, line, begidx, endidx): # pylint: disable=W0613,R0201 + def filename_complete(self, text, line, begidx, endidx): """ Filename completion handler, with hack to restore what I consider the normal (bash-like) behavior when one hits the completion key diff --git a/rpki/django_settings/common.py b/rpki/django_settings/common.py index 13dcdcef..4aa3e119 100644 --- a/rpki/django_settings/common.py +++ b/rpki/django_settings/common.py @@ -57,6 +57,8 @@ if os.getenv("RPKI_DJANGO_DEBUG") == "yes": class DatabaseConfigurator(object): default_sql_engine = "mysql" + cfg = None + section = None def configure(self, cfg, section): # pylint: disable=W0621 self.cfg = cfg diff --git a/rpki/django_settings/gui.py b/rpki/django_settings/gui.py index 4e9ac0f3..2c664f91 100644 --- a/rpki/django_settings/gui.py +++ b/rpki/django_settings/gui.py @@ -20,7 +20,7 @@ This module contains GUI-specific configuration settings for Django libraries. # Pull in the irdb configuration, which in turn pulls in the common configuration. -from .irdb import * # pylint: disable=W0401 +from .irdb import * # pylint: disable=W0401,W0614 __version__ = "$Id$" diff --git a/rpki/django_settings/irdb.py b/rpki/django_settings/irdb.py index 2a49739b..da42a111 100644 --- a/rpki/django_settings/irdb.py +++ b/rpki/django_settings/irdb.py @@ -21,7 +21,7 @@ the GUI code also uses this but adds a bunch of other stuff, thus has its own settings file. """ -from .common import * # pylint: disable=W0401 +from .common import * # pylint: disable=W0401,W0614 __version__ = "$Id$" diff --git a/rpki/django_settings/pubd.py b/rpki/django_settings/pubd.py index 0df0ddb9..6bd9fdc0 100644 --- a/rpki/django_settings/pubd.py +++ b/rpki/django_settings/pubd.py @@ -19,7 +19,7 @@ This module contains configuration settings for Django libraries for the pubd program. """ -from .common import * # pylint: disable=W0401 +from .common import * # pylint: disable=W0401,W0614 __version__ = "$Id$" diff --git a/rpki/django_settings/rpkid.py b/rpki/django_settings/rpkid.py index 70987315..e34518bb 100644 --- a/rpki/django_settings/rpkid.py +++ b/rpki/django_settings/rpkid.py @@ -19,7 +19,7 @@ This module contains configuration settings for Django libraries for the rpkid program. """ -from .common import * # pylint: disable=W0401 +from .common import * # pylint: disable=W0401,W0614 __version__ = "$Id$" diff --git a/rpki/exceptions.py b/rpki/exceptions.py index cbdb9f83..d66ad00c 100644 --- a/rpki/exceptions.py +++ b/rpki/exceptions.py @@ -241,3 +241,9 @@ class UnexpectedUpDownResponse(RPKI_Exception): class BadContentType(RPKI_Exception): "Bad HTTP Content-Type." + +class ResourceClassMismatch(RPKI_Exception): + "Up-down resource class does not match." + +class IRDBExpired(RPKI_Exception): + "Back-end database record has expired." diff --git a/rpki/fields.py b/rpki/fields.py index f8ee8789..06f71259 100644 --- a/rpki/fields.py +++ b/rpki/fields.py @@ -143,7 +143,7 @@ class DERField(models.BinaryField): del kwargs["default"] return name, path, args, kwargs - def from_db_value(self, value, expression, connection, context): # pylint: disable=W0613 + def from_db_value(self, value, expression, connection, context): if value is not None: value = self.rpki_type(DER = str(value)) return value diff --git a/rpki/irdb/__init__.py b/rpki/irdb/__init__.py index 25dedfe3..64b0ea28 100644 --- a/rpki/irdb/__init__.py +++ b/rpki/irdb/__init__.py @@ -19,7 +19,5 @@ Django really wants its models packaged up in a "models" module within a Python package, so humor it. """ -# pylint: disable=W0401 - from rpki.irdb.zookeeper import Zookeeper from rpki.irdb.router import DBContextRouter, database diff --git a/rpki/irdb/models.py b/rpki/irdb/models.py index 4ff5734a..a663c36f 100644 --- a/rpki/irdb/models.py +++ b/rpki/irdb/models.py @@ -24,7 +24,7 @@ to be usable by command line programs and other scripts, not just Django GUI code, so be careful. """ -# pylint: disable=W0232,C1001 +# pylint: disable=W5101,W5103 import django.db.models import rpki.x509 @@ -98,6 +98,8 @@ class CertificateManager(django.db.models.Manager): anything has changed. """ + # pylint: disable=E1101 + changed = False try: @@ -120,6 +122,7 @@ class CertificateManager(django.db.models.Manager): return obj, changed def _get_or_certify_keys(self, kwargs): + # pylint: disable=E1101,W0212 assert len(self.model._meta.unique_together) == 1 return dict((k, kwargs[k]) for k in self.model._meta.unique_together[0]) @@ -154,6 +157,10 @@ class CA(django.db.models.Model): class Meta: abstract = True + @property + def subject_name(self): + raise NotImplementedError + def avow(self): if self.private_key is None: self.private_key = rpki.x509.RSA.generate(quiet = True) @@ -245,16 +252,17 @@ class Certificate(django.db.models.Model): unique_together = ("issuer", "handle") def revoke(self): - self.issuer.revoke(self) + self.issuer.revoke(self) # pylint: disable=E1101 class CrossCertification(Certificate): handle = HandleField() - ta = CertificateField() + ta = CertificateField() # pylint: disable=C0103 class Meta: abstract = True def avow(self): + # pylint: disable=E1101 self.certificate = self.issuer.certify( subject_name = self.ta.getSubject(), subject_key = self.ta.getPublicKey(), @@ -305,6 +313,7 @@ class EECertificate(Certificate): abstract = True def avow(self): + # pylint: disable=E1101 if self.private_key is None: self.private_key = rpki.x509.RSA.generate(quiet = True) self.certificate = self.issuer.certify( @@ -350,6 +359,7 @@ class BSC(Certificate): pkcs10 = PKCS10Field() def avow(self): + # pylint: disable=E1101 self.certificate = self.issuer.certify( subject_name = self.pkcs10.getSubject(), subject_key = self.pkcs10.getPublicKey(), @@ -365,6 +375,9 @@ class ResourceSet(django.db.models.Model): class Meta: abstract = True + def _select_resource_bag(self): + return (), () + @property def resource_bag(self): raw_asn, raw_net = self._select_resource_bag() @@ -491,8 +504,8 @@ class EECertificateRequest(ResourceSet): issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "ee_certificate_requests") pkcs10 = PKCS10Field() gski = django.db.models.CharField(max_length = 27) - cn = django.db.models.CharField(max_length = 64) - sn = django.db.models.CharField(max_length = 64) + cn = django.db.models.CharField(max_length = 64) # pylint: disable=C0103 + sn = django.db.models.CharField(max_length = 64) # pylint: disable=C0103 eku = django.db.models.TextField(null = True) def _select_resource_bag(self): diff --git a/rpki/irdb/router.py b/rpki/irdb/router.py index 3cbd52f9..a2ba81c7 100644 --- a/rpki/irdb/router.py +++ b/rpki/irdb/router.py @@ -26,6 +26,8 @@ passing database names everywhere. Using a database router accomplishes this. """ +# pylint: disable=W0212 + class DBContextRouter(object): """ A Django database router for use with multiple IRDBs. @@ -81,6 +83,7 @@ class database(object): self.name = name self.on_entry = on_entry self.on_exit = on_exit + self.former = None def __enter__(self): if self.on_entry is not None: diff --git a/rpki/irdb/zookeeper.py b/rpki/irdb/zookeeper.py index 514ff683..5508d64a 100644 --- a/rpki/irdb/zookeeper.py +++ b/rpki/irdb/zookeeper.py @@ -20,8 +20,6 @@ Management code for the IRDB. """ -# pylint: disable=W0612,C0325 - import os import copy @@ -135,7 +133,7 @@ class PEM_writer(object): try: if compare and pem == open(filename, "r").read(): return - except: # pylint: disable=W0702 + except: pass tempname += ".%s.tmp" % os.getpid() mode = 0400 if filename.endswith(".key") else 0444 @@ -295,7 +293,7 @@ class Zookeeper(object): """ if self.run_rpkid or self.run_pubd: - server_ca, created = rpki.irdb.models.ServerCA.objects.get_or_certify() + server_ca = rpki.irdb.models.ServerCA.objects.get_or_certify()[0] rpki.irdb.models.ServerEE.objects.get_or_certify(issuer = server_ca, purpose = "irbe") if self.run_rpkid: @@ -320,7 +318,7 @@ class Zookeeper(object): resource-holding BPKI idenity if needed. """ - resource_ca, created = rpki.irdb.models.ResourceHolderCA.objects.get_or_certify(handle = self.handle) + rpki.irdb.models.ResourceHolderCA.objects.get_or_certify(handle = self.handle) return self.generate_identity() @@ -476,7 +474,7 @@ class Zookeeper(object): @staticmethod - def _compose_left_right_query(): + def compose_left_right_query(): """ Compose top level element of a left-right query. """ @@ -506,7 +504,7 @@ class Zookeeper(object): """ if self.run_rpkid: - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() for ca in rpki.irdb.models.ResourceHolderCA.objects.all(): q_pdu = SubElement(q_msg, rpki.left_right.tag_tenant, @@ -598,11 +596,11 @@ class Zookeeper(object): self.log("Child calls itself %r, we call it %r" % (x.get("child_handle"), child_handle)) - child, created = rpki.irdb.models.Child.objects.get_or_certify( + child = rpki.irdb.models.Child.objects.get_or_certify( issuer = self.resource_ca, handle = child_handle, ta = rpki.x509.X509(Base64 = x.findtext(tag_oob_child_bpki_ta)), - valid_until = valid_until) + valid_until = valid_until)[0] return self.generate_parental_response(child), child_handle @@ -641,7 +639,7 @@ class Zookeeper(object): else: proposed_sia_base = repo.sia_base + child.handle + "/" - referral_cert, created = rpki.irdb.models.Referral.objects.get_or_certify(issuer = self.resource_ca) + referral_cert = rpki.irdb.models.Referral.objects.get_or_certify(issuer = self.resource_ca)[0] auth = rpki.x509.SignedReferral() auth.set_content(B64Element(None, tag_oob_authorization, child.ta, nsmap = oob_nsmap, version = oob_version, @@ -704,7 +702,7 @@ class Zookeeper(object): self.log("Parent calls itself %r, we call it %r" % (x.get("parent_handle"), parent_handle)) self.log("Parent calls us %r" % x.get("child_handle")) - parent, created = rpki.irdb.models.Parent.objects.get_or_certify( + parent = rpki.irdb.models.Parent.objects.get_or_certify( issuer = self.resource_ca, handle = parent_handle, child_handle = x.get("child_handle"), @@ -713,7 +711,7 @@ class Zookeeper(object): ta = rpki.x509.X509(Base64 = x.findtext(tag_oob_parent_bpki_ta)), repository_type = repository_type, referrer = referrer, - referral_authorization = referral_authorization) + referral_authorization = referral_authorization)[0] return self.generate_repository_request(parent), parent_handle @@ -761,6 +759,8 @@ class Zookeeper(object): and service URI. """ + # pylint: disable=E1124 + x = etree_read(filename) if x.tag != tag_oob_publisher_request: @@ -825,11 +825,11 @@ class Zookeeper(object): self.log("Client calls itself %r, we call it %r" % ( x.get("publisher_handle"), client_handle)) - client, created = rpki.irdb.models.Client.objects.get_or_certify( + client = rpki.irdb.models.Client.objects.get_or_certify( issuer = self.server_ca, handle = client_handle, ta = client_ta, - sia_base = sia_base) + sia_base = sia_base)[0] return self.generate_repository_response(client), client_handle @@ -900,11 +900,11 @@ class Zookeeper(object): turtles = [] for parent in self.resource_ca.parents.all(): try: - _ = parent.repository + _ = parent.repository # pylint: disable=W0612 except rpki.irdb.models.Repository.DoesNotExist: turtles.append(parent) try: - _ = self.resource_ca.rootd.repository + _ = self.resource_ca.rootd.repository # pylint: disable=W0612 except rpki.irdb.models.Repository.DoesNotExist: turtles.append(self.resource_ca.rootd) except rpki.irdb.models.Rootd.DoesNotExist: @@ -992,11 +992,11 @@ class Zookeeper(object): raise else: for prefix in rset(",".join(prefixes)): - obj, created = rpki.irdb.models.ChildNet.objects.get_or_create( + obj = rpki.irdb.models.ChildNet.objects.get_or_create( child = child, start_ip = str(prefix.min), end_ip = str(prefix.max), - version = version) + version = version)[0] primary_keys.append(obj.pk) q = rpki.irdb.models.ChildNet.objects @@ -1028,10 +1028,10 @@ class Zookeeper(object): raise else: for asn in rpki.resource_set.resource_set_as(",".join(asns)): - obj, created = rpki.irdb.models.ChildASN.objects.get_or_create( + obj = rpki.irdb.models.ChildASN.objects.get_or_create( child = child, start_as = str(asn.min), - end_as = str(asn.max)) + end_as = str(asn.max))[0] primary_keys.append(obj.pk) q = rpki.irdb.models.ChildASN.objects @@ -1131,7 +1131,7 @@ class Zookeeper(object): def _rpkid_tenant_control(self, *bools): assert all(isinstance(b, str) for b in bools) - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() q_pdu = SubElement(q_msg, rpki.left_right.tag_tenant, action = "set", tenant_handle = self.handle) for b in bools: q_pdu.set(b, "yes") @@ -1200,7 +1200,7 @@ class Zookeeper(object): """ if self.run_rpkid: - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() for ca in rpki.irdb.models.ResourceHolderCA.objects.all(): SubElement(q_msg, rpki.left_right.tag_tenant, action = "set", tenant_handle = ca.handle, clear_replay_protection = "yes") @@ -1324,6 +1324,8 @@ class Zookeeper(object): CA to the end of whatever other commands this method generates. """ + # pylint: disable=C0330 + # We can use a single BSC for everything -- except BSC key # rollovers. Drive off that bridge when we get to it. @@ -1349,7 +1351,7 @@ class Zookeeper(object): # See what rpkid already has on file for this entity. - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() SubElement(q_msg, rpki.left_right.tag_tenant, action = "get", tenant_handle = ca.handle) SubElement(q_msg, rpki.left_right.tag_bsc, action = "list", tenant_handle = ca.handle) SubElement(q_msg, rpki.left_right.tag_repository, action = "list", tenant_handle = ca.handle) @@ -1371,11 +1373,11 @@ class Zookeeper(object): child_pdus = dict((r_pdu.get("child_handle"), r_pdu) for r_pdu in r_msg.getiterator(rpki.left_right.tag_child)) - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() - tenant_cert, created = rpki.irdb.models.HostedCA.objects.get_or_certify( + tenant_cert = rpki.irdb.models.HostedCA.objects.get_or_certify( issuer = self.server_ca, - hosted = ca) + hosted = ca)[0] # There should be exactly one <tenant/> object per hosted entity, by definition @@ -1421,15 +1423,15 @@ class Zookeeper(object): if r_pdu.get("action") == "list") bsc_pdu = bsc_pdus.pop(bsc_handle, None) - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() bsc_pkcs10 = bsc_pdu.find(rpki.left_right.tag_pkcs10_request) assert bsc_pkcs10 is not None - bsc, created = rpki.irdb.models.BSC.objects.get_or_certify( + bsc = rpki.irdb.models.BSC.objects.get_or_certify( issuer = ca, handle = bsc_handle, - pkcs10 = rpki.x509.PKCS10(Base64 = bsc_pkcs10.text)) + pkcs10 = rpki.x509.PKCS10(Base64 = bsc_pkcs10.text))[0] if (bsc_pdu.findtext(rpki.left_right.tag_signing_cert, "").decode("base64") != bsc.certificate.get_DER() or bsc_pdu.findtext(rpki.left_right.tag_signing_cert_crl, "").decode("base64") != ca.latest_crl.get_DER()): @@ -1586,6 +1588,8 @@ class Zookeeper(object): related to pubd should call this when they're done. """ + # pylint: disable=C0330 + # If we're not running pubd, the rest of this is a waste of time if not self.run_pubd: @@ -1652,7 +1656,7 @@ class Zookeeper(object): inside a Django commit wrapper. """ - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() SubElement(q_msg, rpki.left_right.tag_tenant, action = "list") r_msg = self.call_rpkid(q_msg) @@ -1660,7 +1664,7 @@ class Zookeeper(object): ca_handles = set(ca.handle for ca in rpki.irdb.models.ResourceHolderCA.objects.all()) assert ca_handles <= tenant_handles - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() for handle in (tenant_handles - ca_handles): SubElement(q_msg, rpki.left_right.tag_tenant, action = "destroy", tenant_handle = handle) diff --git a/rpki/irdbd.py b/rpki/irdbd.py index 91859f5d..44628886 100644 --- a/rpki/irdbd.py +++ b/rpki/irdbd.py @@ -156,6 +156,8 @@ class main(object): self.cfg = rpki.config.parser(set_filename = args.config, section = "irdbd") self.cfg.set_global_flags() + self.cms_timestamp = None + if not args.foreground: rpki.daemonize.daemon(pidfile = args.pidfile) @@ -188,8 +190,6 @@ class main(object): self.http_server_host = self.cfg.get("server-host", "") self.http_server_port = self.cfg.getint("server-port") - self.cms_timestamp = None - rpki.http_simple.server( host = self.http_server_host, port = self.http_server_port, diff --git a/rpki/log.py b/rpki/log.py index 8afee4ba..dd3923a7 100644 --- a/rpki/log.py +++ b/rpki/log.py @@ -96,12 +96,12 @@ class Formatter(object): try: if not self.is_syslog: yield time.strftime("%Y-%m-%d %H:%M:%S ", time.gmtime(record.created)) - except: # pylint: disable=W0702 + except: yield "[$!$Time format failed]" try: yield "%s[%d]: " % (self.ident, record.process) - except: # pylint: disable=W0702 + except: yield "[$!$ident format failed]" try: @@ -111,12 +111,12 @@ class Formatter(object): yield repr(record.context) + " " except AttributeError: pass - except: # pylint: disable=W0702 + except: yield "[$!$context format failed]" try: yield record.getMessage() - except: # pylint: disable=W0702 + except: yield "[$!$record.getMessage() failed]" try: @@ -129,7 +129,7 @@ class Formatter(object): lines.insert(0, "\n") for line in lines: yield line - except: # pylint: disable=W0702 + except: yield "[$!$exception formatting failed]" @@ -218,8 +218,6 @@ def init(ident = None, args = None): Default logging destination is stderr if "args" is not specified. """ - # pylint: disable=E1103 - if ident is None: ident = os.path.basename(sys.argv[0]) @@ -227,12 +225,12 @@ def init(ident = None, args = None): args = argparse.Namespace(log_level = logging.WARNING, log_handler = logging.StreamHandler) - handler = args.log_handler() + handler = args.log_handler() # pylint: disable=E1101 handler.setFormatter(Formatter(ident, handler)) root_logger = logging.getLogger() root_logger.addHandler(handler) - root_logger.setLevel(args.log_level) + root_logger.setLevel(args.log_level) # pylint: disable=E1101 if ident and have_setproctitle and use_setproctitle: if proctitle_extra: @@ -262,8 +260,6 @@ def log_repr(obj, *tokens): IDs as needed, includes tenant_handle when available. """ - # pylint: disable=W0702 - words = ["%s.%s" % (obj.__class__.__module__, obj.__class__.__name__)] try: words.append("{%s}" % obj.tenant.tenant_handle) diff --git a/rpki/oids.py b/rpki/oids.py index abc928bc..b27be6f3 100644 --- a/rpki/oids.py +++ b/rpki/oids.py @@ -88,8 +88,7 @@ for _sym in dir(): raise ValueError("Bad OID definition: %s = %r" % (_sym, _val)) _oid2name[_val] = _sym.replace("_", "-") -# pylint: disable=W0631 -del _sym +del _sym # pylint: disable=W0631 del _val def oid2name(oid): diff --git a/rpki/old_irdbd.py b/rpki/old_irdbd.py index 4ebb33b0..b2dd42bd 100644 --- a/rpki/old_irdbd.py +++ b/rpki/old_irdbd.py @@ -25,6 +25,8 @@ and perhaps still useful as a minimal example. This does NOT work with the GUI, rpkic, or any of the other more recent tools. """ +# pylint: skip-file + import os import time import logging diff --git a/rpki/pubdb/models.py b/rpki/pubdb/models.py index 46dcf493..43600a5e 100644 --- a/rpki/pubdb/models.py +++ b/rpki/pubdb/models.py @@ -31,6 +31,8 @@ import rpki.relaxng logger = logging.getLogger(__name__) +# pylint: disable=W5101 + # Some of this probably ought to move into a rpki.rrdp module. rrdp_xmlns = rpki.relaxng.rrdp.xmlns @@ -93,6 +95,8 @@ class Session(models.Model): Construct a new delta associated with this session. """ + # pylint: disable=W0201 + delta = Delta(session = self, serial = self.serial + 1, expires = expires) @@ -261,7 +265,10 @@ class Delta(models.Model): def withdraw(self, client, uri, obj_hash): - obj = client.publishedobject_set.get(session = self.session, uri = uri) + try: + obj = client.publishedobject_set.get(session = self.session, uri = uri) + except rpki.pubdb.models.PublishedObject.DoesNotExist: + raise rpki.exceptions.NoObjectAtURI("No published object found at %s" % uri) if obj.hash != obj_hash: raise rpki.exceptions.DifferentObjectAtURI("Found different object at %s (old %s, new %s)" % (uri, obj.hash, obj_hash)) logger.debug("Withdrawing %s", uri) @@ -308,6 +315,6 @@ class PublishedObject(models.Model): client = models.ForeignKey(Client) session = models.ForeignKey(Session) - class Meta: # pylint: disable=C1001,W0232 + class Meta: unique_together = (("session", "hash"), ("session", "uri")) diff --git a/rpki/rcynic.py b/rpki/rcynic.py index 76d5d183..c6ad60d5 100644 --- a/rpki/rcynic.py +++ b/rpki/rcynic.py @@ -43,9 +43,10 @@ class rcynic_object(object): self.filename = filename for k, v in kwargs.iteritems(): setattr(self, k, v) - self.obj = self.obj_class(DER_file = filename) + self.obj = self.obj_class(DER_file = filename) # pylint: disable=E1101 def __repr__(self): + # pylint: disable=E1101 return "<%s %s %s at 0x%x>" % (self.__class__.__name__, self.uri, self.resources, id(self)) def show_attrs(self, *attrs): @@ -178,7 +179,8 @@ class rcynic_file_iterator(object): self.rcynic_dir = os.path.join(rcynic_root, authenticated_subdir) def __iter__(self): - for root, dirs, files in os.walk(self.rcynic_dir): # pylint: disable=W0612 + # pylint: disable=W0612 + for root, dirs, files in os.walk(self.rcynic_dir): for filename in files: filename = os.path.join(root, filename) ext = os.path.splitext(filename)[1] @@ -196,6 +198,7 @@ class validation_status_element(object): self._obj = None def get_obj(self): + # pylint: disable=E1101 if not self._obj: self._obj = self.file_class(filename=self.filename, uri=self.uri) return self._obj diff --git a/rpki/relaxng.py b/rpki/relaxng.py index 49ea88d8..aa1f58d4 100644 --- a/rpki/relaxng.py +++ b/rpki/relaxng.py @@ -1,5 +1,8 @@ # Automatically generated, do not edit. +# pylint: disable=I0013 +# pylint: skip-file + from rpki.relaxng_parser import RelaxNGParser ## @var left_right @@ -7,17 +10,17 @@ from rpki.relaxng_parser import RelaxNGParser left_right = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> <!-- $Id: left-right.rnc 6137 2015-10-20 19:21:37Z sra $ - + RelaxNG schema for RPKI left-right protocol. - + Copyright (C) 2012- -2014 Dragon Research Labs ("DRL") Portions copyright (C) 2009- -2011 Internet Systems Consortium ("ISC") Portions copyright (C) 2007- -2008 American Registry for Internet Numbers ("ARIN") - + Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notices and this permission notice appear in all copies. - + THE SOFTWARE IS PROVIDED "AS IS" AND DRL, ISC, AND ARIN DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL, @@ -1106,23 +1109,23 @@ left_right = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> myrpki = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> <!-- $Id: myrpki.rnc 5876 2014-06-26 19:00:12Z sra $ - + RelaxNG schema for MyRPKI XML messages. - + This message protocol is on its way out, as we're in the process of moving on from the user interface model that produced it, but even after we finish replacing it we'll still need the schema for a while to validate old messages when upgrading. - + libxml2 (including xmllint) only groks the XML syntax of RelaxNG, so run the compact syntax through trang to get XML syntax. - + Copyright (C) 2009-2011 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, @@ -1661,17 +1664,17 @@ oob_setup = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> publication_control = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> <!-- $Id: publication-control.rnc 5903 2014-07-18 17:08:13Z sra $ - + RelaxNG schema for RPKI publication protocol. - + Copyright (C) 2012- -2014 Dragon Research Labs ("DRL") Portions copyright (C) 2009- -2011 Internet Systems Consortium ("ISC") Portions copyright (C) 2007- -2008 American Registry for Internet Numbers ("ARIN") - + Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notices and this permission notice appear in all copies. - + THE SOFTWARE IS PROVIDED "AS IS" AND DRL, ISC, AND ARIN DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL, @@ -1735,7 +1738,7 @@ publication_control = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> <!-- Base64 encoded DER stuff base64 = xsd:base64Binary { maxLength="512000" } - + Sadly, it turns out that CRLs can in fact get longer than this for an active CA. Remove length limit for now, think about whether to put it back later. --> @@ -1945,29 +1948,29 @@ publication_control = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> publication = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> <!-- $Id: publication.rnc 5896 2014-07-15 19:34:32Z sra $ - + RelaxNG schema for RPKI publication protocol, from current I-D. - + Copyright (c) 2014 IETF Trust and the persons identified as authors of the code. All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + * Neither the name of Internet Society, IETF or IETF Trust, nor the names of specific contributors, may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS @@ -2150,22 +2153,22 @@ publication = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> router_certificate = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> <!-- $Id: router-certificate.rnc 5881 2014-07-03 16:55:02Z sra $ - + RelaxNG schema for BGPSEC router certificate interchange format. - + At least for now, this is a trivial encapsulation of a PKCS #10 request, a set (usually containing exactly one member) of autonomous system numbers, and a router-id. Be warned that this could change radically by the time we have any real operational understanding of how these things will be used, this is just our current best guess to let us move forward on initial coding. - + Copyright (C) 2014 Dragon Research Labs ("DRL") - + 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 DRL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL BE LIABLE FOR ANY SPECIAL, DIRECT, @@ -2252,15 +2255,15 @@ router_certificate = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> rrdp = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> <!-- $Id: rrdp.rnc 6010 2014-11-08 18:01:58Z sra $ - + RelaxNG schema for RPKI Repository Delta Protocol (RRDP). - + Copyright (C) 2014 Dragon Research Labs ("DRL") - + 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 DRL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL BE LIABLE FOR ANY SPECIAL, DIRECT, @@ -2406,29 +2409,29 @@ rrdp = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> up_down = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?> <!-- $Id: up-down.rnc 5881 2014-07-03 16:55:02Z sra $ - + RelaxNG schema for the up-down protocol, extracted from RFC 6492. - + Copyright (c) 2012 IETF Trust and the persons identified as authors of the code. All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + * Neither the name of Internet Society, IETF or IETF Trust, nor the names of specific contributors, may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS diff --git a/rpki/resource_set.py b/rpki/resource_set.py index b8d1f658..319e2677 100644 --- a/rpki/resource_set.py +++ b/rpki/resource_set.py @@ -52,6 +52,11 @@ class resource_range(object): directly. """ + # Give pylint a little help here + + datum_type = int + parse_str = int + def __init__(self, range_min, range_max): assert range_min.__class__ is range_max.__class__, \ "Type mismatch, %r doesn't match %r" % (range_min.__class__, range_max.__class__) @@ -130,6 +135,9 @@ class resource_range_ip(resource_range): datum_type = rpki.POW.IPAddress + # Give pylint a little help here + version = None + def prefixlen(self): """ Determine whether a resource_range_ip can be expressed as a @@ -306,6 +314,9 @@ class resource_set(list): canonical = False + # Give pylint a little help here + range_type = resource_range + def __init__(self, ini = None, allow_overlap = False): """ Initialize a resource_set. @@ -316,7 +327,7 @@ class resource_set(list): ini = str(ini) if ini is inherit_token: self.inherit = True - elif isinstance(ini, str) and len(ini): + elif isinstance(ini, (str, unicode)) and len(ini): self.extend(self.parse_str(s) for s in ini.split(",")) elif isinstance(ini, list): self.extend(ini) @@ -542,22 +553,6 @@ class resource_set(list): return self.inherit or len(self) @classmethod - def from_sql(cls, sql, query, args = None): - """ - Create resource set from an SQL query. - - sql is an object that supports execute() and fetchall() methods - like a DB API 2.0 cursor object. - - query is an SQL query that returns a sequence of (min, max) pairs. - """ - - sql.execute(query, args) - return cls(ini = [cls.range_type(cls.range_type.datum_type(b), - cls.range_type.datum_type(e)) - for (b, e) in sql.fetchall()]) - - @classmethod def from_django(cls, iterable): """ Create resource set from a Django query. @@ -602,6 +597,7 @@ class resource_set_ip(resource_set): Convert from a resource set to a ROA prefix set. """ + # pylint: disable=E1101 prefix_ranges = [] for r in self: r.chop_into_prefixes(prefix_ranges) @@ -846,6 +842,9 @@ class roa_prefix(object): ## @var max_prefixlen # Maxmimum prefix length. + # Give pylint a little help + range_type = resource_range_ip + def __init__(self, prefix, prefixlen, max_prefixlen = None): """ Initialize a ROA prefix. max_prefixlen is optional and defaults @@ -949,13 +948,18 @@ class roa_prefix_set(list): Set of ROA prefixes, analogous to the resource_set_ip class. """ + # Give pylint a little help + + prefix_type = roa_prefix + resource_set_type = resource_set_ip + def __init__(self, ini = None): """ Initialize a ROA prefix set. """ list.__init__(self) - if isinstance(ini, str) and len(ini): + if isinstance(ini, (str, unicode)) and len(ini): self.extend(self.parse_str(s) for s in ini.split(",")) elif isinstance(ini, (list, tuple)): self.extend(ini) @@ -1103,21 +1107,21 @@ if __name__ == "__main__": return " (%s)" % v.to_roa_prefix_set() if isinstance(v, resource_set_ip) else "" def test1(t, s1, s2): - if isinstance(s1, str) and isinstance(s2, str): + if isinstance(s1, (str, unicode)) and isinstance(s2, (str, unicode)): print "x: ", s1 print "y: ", s2 r1 = t(s1) r2 = t(s2) print "x: ", r1, testprefix(r1) print "y: ", r2, testprefix(r2) - v1 = r1._comm(r2) - v2 = r2._comm(r1) + v1 = r1._comm(r2) # pylint: disable=W0212 + v2 = r2._comm(r1) # pylint: disable=W0212 assert v1[0] == v2[1] and v1[1] == v2[0] and v1[2] == v2[2] - for i in r1: assert i in r1 and i.min in r1 and i.max in r1 - for i in r2: assert i in r2 and i.min in r2 and i.max in r2 - for i in v1[0]: assert i in r1 and i not in r2 - for i in v1[1]: assert i not in r1 and i in r2 - for i in v1[2]: assert i in r1 and i in r2 + assert all(i in r1 and i.min in r1 and i.max in r1 for i in r1) + assert all(i in r2 and i.min in r2 and i.max in r2 for i in r2) + assert all(i in r1 and i not in r2 for i in v1[0]) + assert all(i not in r1 and i in r2 for i in v1[1]) + assert all(i in r1 and i in r2 for i in v1[2]) v1 = r1 | r2 v2 = r2 | r1 assert v1 == v2 diff --git a/rpki/rootd.py b/rpki/rootd.py index e3a460f4..08259a9a 100644 --- a/rpki/rootd.py +++ b/rpki/rootd.py @@ -369,7 +369,7 @@ class main(object): try: crl = rpki.x509.CRL(DER_file = self.rpki_root_crl_file) self.crl_number = crl.getCRLNumber() - except: # pylint: disable=W0702 + except: self.crl_number = 0 self.crl_number += 1 return self.crl_number diff --git a/rpki/rpkic.py b/rpki/rpkic.py index 9cde75fb..7d63bbe7 100644 --- a/rpki/rpkic.py +++ b/rpki/rpkic.py @@ -115,7 +115,10 @@ class main(Cmd): args.func(self, args) def read_config(self): - global rpki # pylint: disable=W0602 + + # pylint: disable=W0201,W0602,W0621 + + global rpki try: cfg = rpki.config.parser(set_filename = self.cfg_file, section = "myrpki") @@ -131,7 +134,7 @@ class main(Cmd): import django django.setup() - import rpki.irdb # pylint: disable=W0621 + import rpki.irdb try: rpki.irdb.models.ca_certificate_lifetime = rpki.sundial.timedelta.parse( @@ -582,7 +585,7 @@ class main(Cmd): Show resources received by this entity from its parent(s). """ - q_msg = self.zoo._compose_left_right_query() + q_msg = self.zoo.compose_left_right_query() SubElement(q_msg, rpki.left_right.tag_list_received_resources, tenant_handle = self.zoo.handle) for r_pdu in self.zoo.call_rpkid(q_msg): @@ -604,7 +607,7 @@ class main(Cmd): Show published objects. """ - q_msg = self.zoo._compose_left_right_query() + q_msg = self.zoo.compose_left_right_query() SubElement(q_msg, rpki.left_right.tag_list_published_objects, tenant_handle = self.zoo.handle) for r_pdu in self.zoo.call_rpkid(q_msg): diff --git a/rpki/rpkid.py b/rpki/rpkid.py index 001c36e2..96f3426f 100644 --- a/rpki/rpkid.py +++ b/rpki/rpkid.py @@ -252,7 +252,7 @@ class main(object): @tornado.gen.coroutine def cron_loop(self): """ - Asynchronous infinite loop to drive cron cycle. + Asynchronous infinite loop to drive internal cron cycle. """ logger.debug("cron_loop(): Starting") @@ -268,7 +268,7 @@ class main(object): @tornado.gen.coroutine def cron_run(self): """ - Schedule periodic tasks. + Schedule periodic tasks and wait for them to finish. """ now = rpki.sundial.now() @@ -296,7 +296,7 @@ class main(object): handler.set_status(500, "Running cron internally") else: logger.debug("Starting externally triggered cron") - yield self.cron() + yield self.cron_run() handler.set_status(200) handler.finish() @@ -340,7 +340,7 @@ class main(object): raise tornado.gen.Return(response) @staticmethod - def _compose_left_right_query(): + def compose_left_right_query(): """ Compose top level element of a left-right query to irdbd. """ @@ -393,7 +393,7 @@ class main(object): Ask IRDB about a child's resources. """ - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() SubElement(q_msg, rpki.left_right.tag_list_resources, tenant_handle = tenant_handle, child_handle = child_handle) r_msg = yield self.irdb_query(q_msg) @@ -415,7 +415,7 @@ class main(object): Ask IRDB about self's ROA requests. """ - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() SubElement(q_msg, rpki.left_right.tag_list_roa_requests, tenant_handle = tenant_handle) r_msg = yield self.irdb_query(q_msg) raise tornado.gen.Return(r_msg) @@ -426,7 +426,7 @@ class main(object): Ask IRDB about self's ghostbuster record requests. """ - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() for parent_handle in parent_handles: SubElement(q_msg, rpki.left_right.tag_list_ghostbuster_requests, tenant_handle = tenant_handle, parent_handle = parent_handle) @@ -439,7 +439,7 @@ class main(object): Ask IRDB about self's EE certificate requests. """ - q_msg = self._compose_left_right_query() + q_msg = self.compose_left_right_query() SubElement(q_msg, rpki.left_right.tag_list_ee_certificate_requests, tenant_handle = tenant_handle) r_msg = yield self.irdb_query(q_msg) raise tornado.gen.Return(r_msg) @@ -450,10 +450,12 @@ class main(object): Map element tag to rpkidb model. """ + # pylint: disable=W0621,W0201 + try: return self._left_right_models except AttributeError: - import rpki.rpkidb.models # pylint: disable=W0621 + import rpki.rpkidb.models self._left_right_models = { rpki.left_right.tag_tenant : rpki.rpkidb.models.Tenant, rpki.left_right.tag_bsc : rpki.rpkidb.models.BSC, @@ -468,6 +470,8 @@ class main(object): Map element tag to bound handler methods for trivial PDU types. """ + # pylint: disable=W0201 + try: return self._left_right_trivial_handlers except AttributeError: @@ -690,17 +694,20 @@ class publication_queue(object): old_pdu = self.uris.pop(uri) self.msgs[rid].remove(old_pdu) pdu_hash = old_pdu.get("hash") + if pdu_hash is None and new_obj is None: + logger.debug("Withdrawing object %r which was never published simplifies to no-op", old_pdu) + return elif old_hash is not None: - logger.debug("Old hash supplied") # XXX + logger.debug("Old hash supplied") # XXX Debug log pdu_hash = old_hash elif old_obj is None: - logger.debug("No old object present") # XXX + logger.debug("No old object present") # XXX Debug log pdu_hash = None else: - logger.debug("Calculating hash of old object") # XXX + logger.debug("Calculating hash of old object") # XXX Debug log pdu_hash = rpki.x509.sha256(old_obj.get_DER()).encode("hex") - logger.debug("uri %s old hash %s new hash %s", uri, pdu_hash, # XXX + logger.debug("uri %s old hash %s new hash %s", uri, pdu_hash, # XXX Debug log None if new_obj is None else rpki.x509.sha256(new_obj.get_DER()).encode("hex")) if new_obj is None: diff --git a/rpki/rpkid_tasks.py b/rpki/rpkid_tasks.py index 989042b9..3fd3a411 100644 --- a/rpki/rpkid_tasks.py +++ b/rpki/rpkid_tasks.py @@ -279,8 +279,8 @@ class UpdateROAsTask(AbstractTask): seen = set() orphans = [] updates = [] - self.publisher = rpki.rpkid.publication_queue(self.rpkid) - self.ca_details = set() + self.publisher = rpki.rpkid.publication_queue(self.rpkid) # pylint: disable=W0201 + self.ca_details = set() # pylint: disable=W0201 for roa in self.tenant.roas.all(): k = (roa.asn, str(roa.ipv4), str(roa.ipv6)) @@ -458,6 +458,8 @@ class UpdateEECertificatesTask(AbstractTask): ee.reissue(resources = resources, publisher = publisher) covering.remove(ee.ca_detail) else: + # This probably never happens, as the most likely cause would be a CA certificate + # being revoked, which should trigger automatic clean up of issued certificates. logger.debug("%r: Existing EE certificate for %s %s is no longer covered", self, gski, resources) ee.revoke(publisher = publisher) diff --git a/rpki/rpkidb/models.py b/rpki/rpkidb/models.py index ab89ba7b..527b81d4 100644 --- a/rpki/rpkidb/models.py +++ b/rpki/rpkidb/models.py @@ -26,6 +26,9 @@ from lxml.etree import Element, SubElement, tostring as ElementToString logger = logging.getLogger(__name__) +# pylint: disable=W5101 + + # XXX Temporary hack to help trace call chains so we can clear some of # the historical clutter out of this module. @@ -161,7 +164,7 @@ class XMLTemplate(object): setattr(obj, k, self.element_type[k](Base64 = v)) -class XMLManager(models.Manager): # pylint: disable=W0232 +class XMLManager(models.Manager): """ Add a few methods which locate or create an object or objects corresponding to the handles in an XML element, as appropriate. @@ -174,6 +177,8 @@ class XMLManager(models.Manager): # pylint: disable=W0232 debug = False + # pylint: disable=E1101 + def xml_get_or_create(self, xml): name = self.model.xml_template.name action = xml.get("action") @@ -382,6 +387,7 @@ class Tenant(models.Model): def cron_tasks(self, rpkid): trace_call_chain() + # pylint: disable=W0201 try: return self._cron_tasks except AttributeError: @@ -418,7 +424,7 @@ class BSC(models.Model): tenant = models.ForeignKey(Tenant, related_name = "bscs") objects = XMLManager() - class Meta: # pylint: disable=C1001,W0232 + class Meta: unique_together = ("tenant", "bsc_handle") xml_template = XMLTemplate( @@ -447,7 +453,7 @@ class Repository(models.Model): tenant = models.ForeignKey(Tenant, related_name = "repositories") objects = XMLManager() - class Meta: # pylint: disable=C1001,W0232 + class Meta: unique_together = ("tenant", "repository_handle") xml_template = XMLTemplate( @@ -542,7 +548,7 @@ class Parent(models.Model): repository = models.ForeignKey(Repository, related_name = "parents") objects = XMLManager() - class Meta: # pylint: disable=C1001,W0232 + class Meta: unique_together = ("tenant", "parent_handle") xml_template = XMLTemplate( @@ -668,7 +674,7 @@ class Parent(models.Model): """ trace_call_chain() - yield [ca.destroy(self) for ca in self.cas()] + yield [ca.destroy(self) for ca in self.cas()] # pylint: disable=E1101 yield self.serve_revoke_forgotten(rpkid = rpkid) if delete_parent: self.delete() @@ -806,6 +812,8 @@ class CA(models.Model): with the same key, etc. """ + # pylint: disable=C0330 + trace_call_chain() logger.debug("check_for_updates()") sia_uri = parent.construct_sia_uri(rc) @@ -1056,7 +1064,7 @@ class CADetail(models.Model): manifest_published = SundialField(null = True) state = EnumField(choices = ("pending", "active", "deprecated", "revoked")) ca_cert_uri = models.TextField(null = True) - ca = models.ForeignKey(CA, related_name = "ca_details") + ca = models.ForeignKey(CA, related_name = "ca_details") # pylint: disable=C0103 # Like the old ca_obj class, the old ca_detail_obj class had ten @@ -1079,6 +1087,7 @@ class CADetail(models.Model): Return tail (filename portion) of publication URI for this ca_detail's CRL. """ + # pylint: disable=E1101 return self.public_key.gSKI() + ".crl" @@ -1088,6 +1097,7 @@ class CADetail(models.Model): Return publication URI for this ca_detail's manifest. """ + # pylint: disable=E1101 return self.ca.sia_uri + self.public_key.gSKI() + ".mft" @@ -1179,7 +1189,7 @@ class CADetail(models.Model): - Request revocation of old keypair by parent. - - Revoke all child certs issued by the old keypair. + - Revoke all certificates issued by the old keypair. - Generate a final CRL, signed with the old keypair, listing all the revoked certs, with a next CRL time after the last cert or @@ -1234,6 +1244,10 @@ class CADetail(models.Model): nextUpdate = nextUpdate.later(ghostbuster.cert.getNotAfter()) ghostbuster.revoke(publisher = publisher) + for eecert in self.ee_certificates.all(): + nextUpdate = nextUpdate.later(eecert.cert.getNotAfter()) + eecert.revoke(publisher = publisher) + nextUpdate += crl_interval self.generate_crl(publisher = publisher, nextUpdate = nextUpdate) @@ -1463,8 +1477,8 @@ class CADetail(models.Model): if nextUpdate is None: nextUpdate = now + crl_interval if (self.latest_manifest_cert is None or - (self.latest_manifest_cert.getNotAfter() < nextUpdate and - self.latest_manifest_cert.getNotAfter() < self.latest_ca_cert.getNotAfter())): + (self.latest_manifest_cert.getNotAfter() < nextUpdate and + self.latest_manifest_cert.getNotAfter() < self.latest_ca_cert.getNotAfter())): logger.debug("Generating EE certificate for %s", uri) self.generate_manifest_cert() logger.debug("Latest CA cert notAfter %s, new %s EE notAfter %s", @@ -1616,7 +1630,7 @@ class Child(models.Model): bsc = models.ForeignKey(BSC, related_name = "children") objects = XMLManager() - class Meta: # pylint: disable=C1001,W0232 + class Meta: unique_together = ("tenant", "child_handle") xml_template = XMLTemplate( @@ -1861,6 +1875,7 @@ class ChildCert(models.Model): """ trace_call_chain() + # pylint: disable=E1101 ca = ca_detail.ca child = self.child old_resources = self.cert.get_3779resources() diff --git a/rpki/rtr/bgpdump.py b/rpki/rtr/bgpdump.py index 3336fb9f..1ca04803 100755 --- a/rpki/rtr/bgpdump.py +++ b/rpki/rtr/bgpdump.py @@ -91,6 +91,8 @@ class PrefixPDU(rpki.rtr.generator.PrefixPDU): class AXFRSet(rpki.rtr.generator.AXFRSet): + serial = None + @staticmethod def read_bgpdump(filename): assert filename.endswith(".bz2") @@ -101,6 +103,7 @@ class AXFRSet(rpki.rtr.generator.AXFRSet): @classmethod def parse_bgpdump_rib_dump(cls, filename): + # pylint: disable=W0201 assert os.path.basename(filename).startswith("ribs.") self = cls() self.serial = None @@ -212,7 +215,7 @@ def bgpdump_select_main(args): nonce = rpki.rtr.server.read_current(version)[1] if nonce is None: - nonce = rpki.rtr.generator.new_nonce() + nonce = rpki.rtr.generator.AXFRSet.new_nonce(force_zero_nonce = False) rpki.rtr.server.write_current(serial, nonce, version) rpki.rtr.generator.kick_all(serial) @@ -238,7 +241,7 @@ class BGPDumpReplayClock(object): self.timestamps = [Timestamp(int(f.split(".")[0])) for f in glob.iglob("*.ax.v*")] self.timestamps.sort() self.offset = self.timestamps[0] - int(time.time()) - self.nonce = rpki.rtr.generator.new_nonce() + self.nonce = rpki.rtr.generator.AXFRSet.new_nonce(force_zero_nonce = False) def __nonzero__(self): return len(self.timestamps) > 0 @@ -278,7 +281,7 @@ def bgpdump_server_main(args): You have been warned. """ - logger = logging.LoggerAdapter(logging.root, dict(connection = rpki.rtr.server._hostport_tag())) + logger = logging.LoggerAdapter(logging.root, dict(connection = rpki.rtr.server.hostport_tag())) logger.debug("[Starting]") diff --git a/rpki/rtr/channels.py b/rpki/rtr/channels.py index df96fa58..a4dccbc1 100644 --- a/rpki/rtr/channels.py +++ b/rpki/rtr/channels.py @@ -59,6 +59,8 @@ class ReadBuffer(object): def __init__(self): self.buffer = "" self.version = None + self.need = None + self.callback = None def update(self, need, callback): """ diff --git a/rpki/rtr/generator.py b/rpki/rtr/generator.py index e00e44b7..a879cc39 100644 --- a/rpki/rtr/generator.py +++ b/rpki/rtr/generator.py @@ -105,6 +105,11 @@ class RouterKeyPDU(rpki.rtr.pdus.RouterKeyPDU): Router Key PDU. """ + announce = None + ski = None + asn = None + key = None + @classmethod def from_text(cls, version, asn, gski, key): """ @@ -140,14 +145,15 @@ class ROA(rpki.POW.ROA): # pylint: disable=W0232 """ @classmethod - def derReadFile(cls, fn): # pylint: disable=E1002 + def derReadFile(cls, fn): + # pylint: disable=E1002 self = super(ROA, cls).derReadFile(fn) self.extractWithoutVerifying() return self @property def prefixes(self): - v4, v6 = self.getPrefixes() + v4, v6 = self.getPrefixes() # pylint: disable=E1101 if v4 is not None: for p in v4: yield p @@ -162,7 +168,7 @@ class X509(rpki.POW.X509): # pylint: disable=W0232 @property def asns(self): - resources = self.getRFC3779() + resources = self.getRFC3779() # pylint: disable=E1101 if resources is not None and resources[0] is not None: for min_asn, max_asn in resources[0]: for asn in xrange(min_asn, max_asn + 1): @@ -215,6 +221,8 @@ class AXFRSet(PDUSet): field set. """ + serial = None + @classmethod def parse_rcynic(cls, rcynic_dir, version, scan_roas = None, scan_routercerts = None): """ @@ -245,7 +253,7 @@ class AXFRSet(PDUSet): self.extend(PrefixPDU.from_roa(version = version, asn = asn, prefix_tuple = prefix_tuple) for prefix_tuple in roa.prefixes) if include_routercerts and scan_routercerts is None and fn.endswith(".cer"): - x = X509.derReadFile(os.path.join(root, fn)) + x = X509.derReadFile(os.path.join(root, fn)) # pylint: disable=E1101 eku = x.getEKU() if eku is not None and rpki.oids.id_kp_bgpsec_router in eku: ski = x.getSKI() @@ -415,6 +423,9 @@ class IXFRSet(PDUSet): indicate the changes. """ + from_serial = None + to_serial = None + @classmethod def load(cls, filename): """ diff --git a/rpki/rtr/pdus.py b/rpki/rtr/pdus.py index d355026c..3fb7457d 100644 --- a/rpki/rtr/pdus.py +++ b/rpki/rtr/pdus.py @@ -116,6 +116,8 @@ class PDU(object): header_struct = struct.Struct("!BB2xL") + pdu_type = None + def __init__(self, version): assert version in self.version_map self.version = version @@ -123,6 +125,9 @@ class PDU(object): def __cmp__(self, other): return cmp(self.to_pdu(), other.to_pdu()) + def to_pdu(self, announce = None): + return NotImplementedError + @property def default_version(self): return max(self.version_map.iterkeys()) @@ -170,11 +175,12 @@ class PDUWithSerial(PDU): def __str__(self): return "[%s, serial #%d nonce %d]" % (self.__class__.__name__, self.serial, self.nonce) - def to_pdu(self): + def to_pdu(self, announce = None): """ Generate the wire format PDU. """ + assert announce is None if self._pdu is None: self._pdu = self.header_struct.pack(self.version, self.pdu_type, self.nonce, self.header_struct.size, self.serial) @@ -208,11 +214,12 @@ class PDUWithNonce(PDU): def __str__(self): return "[%s, nonce %d]" % (self.__class__.__name__, self.nonce) - def to_pdu(self): + def to_pdu(self, announce = None): """ Generate the wire format PDU. """ + assert announce is None if self._pdu is None: self._pdu = self.header_struct.pack(self.version, self.pdu_type, self.nonce, self.header_struct.size) return self._pdu @@ -239,11 +246,12 @@ class PDUEmpty(PDU): def __str__(self): return "[%s]" % self.__class__.__name__ - def to_pdu(self): + def to_pdu(self, announce = None): """ Generate the wire format PDU for this prefix. """ + assert announce is None if self._pdu is None: self._pdu = self.header_struct.pack(self.version, self.pdu_type, 0, self.header_struct.size) return self._pdu @@ -370,11 +378,12 @@ class EndOfDataPDUv1(EndOfDataPDUv0): return "[%s, serial #%d nonce %d refresh %d retry %d expire %d]" % ( self.__class__.__name__, self.serial, self.nonce, self.refresh, self.retry, self.expire) - def to_pdu(self): + def to_pdu(self, announce = None): """ Generate the wire format PDU. """ + assert announce is None if self._pdu is None: self._pdu = self.header_struct.pack(self.version, self.pdu_type, self.nonce, self.header_struct.size, self.serial, @@ -416,6 +425,15 @@ class PrefixPDU(PDU): header_struct = struct.Struct("!BB2xLBBBx") asnum_struct = struct.Struct("!L") + address_byte_count = 0 + + def __init__(self, version): + super(PrefixPDU, self).__init__(version) + self.asn = None + self.prefix = None + self.prefixlen = None + self.max_prefixlen = None + self.announce = None def __str__(self): plm = "%s/%s-%s" % (self.prefix, self.prefixlen, self.max_prefixlen) @@ -511,6 +529,13 @@ class RouterKeyPDU(PDU): header_struct = struct.Struct("!BBBxL20sL") + def __init__(self, version): + super(RouterKeyPDU, self).__init__(version) + self.announce = None + self.ski = None + self.asn = None + self.key = None + def __str__(self): return "%s %8s %-32s %s" % ("+" if self.announce else "-", self.asn, base64.urlsafe_b64encode(self.ski).rstrip("="), @@ -596,6 +621,8 @@ class ErrorReportPDU(PDU): self.errno = errno self.errpdu = errpdu self.errmsg = errmsg if errmsg is not None or errno is None else self.errors[errno] + self.pdulen = None + self.errlen = None def __str__(self): return "[%s, error #%s: %r]" % (self.__class__.__name__, self.errno, self.errmsg) @@ -609,11 +636,12 @@ class ErrorReportPDU(PDU): assert remaining >= self.string_struct.size + n return n, reader.get(n), (remaining - self.string_struct.size - n) - def to_pdu(self): + def to_pdu(self, announce = None): """ Generate the wire format PDU for this error report. """ + assert announce is None if self._pdu is None: assert isinstance(self.errno, int) assert not isinstance(self.errpdu, ErrorReportPDU) diff --git a/rpki/rtr/server.py b/rpki/rtr/server.py index f57c3037..052aef2c 100644 --- a/rpki/rtr/server.py +++ b/rpki/rtr/server.py @@ -393,7 +393,7 @@ class KickmeChannel(asyncore.dispatcher, object): self.close() try: os.unlink(self.sockname) - except: # pylint: disable=W0702 + except: pass def log(self, msg): @@ -420,7 +420,7 @@ class KickmeChannel(asyncore.dispatcher, object): sys.exit(1) -def _hostport_tag(): +def hostport_tag(): """ Construct hostname/address + port when we're running under a protocol we understand well enough to do that. This is all @@ -433,28 +433,28 @@ def _hostport_tag(): try: host, port = socket.fromfd(0, socket.AF_INET, socket.SOCK_STREAM).getpeername() proto = "tcp" - except: # pylint: disable=W0702 + except: pass if proto is None: try: host, port = socket.fromfd(0, socket.AF_INET6, socket.SOCK_STREAM).getpeername()[0:2] proto = "tcp" - except: # pylint: disable=W0702 + except: pass if proto is None: try: host, port = os.environ["SSH_CONNECTION"].split()[0:2] proto = "ssh" - except: # pylint: disable=W0702 + except: pass if proto is None: try: host, port = os.environ["REMOTE_HOST"], os.getenv("REMOTE_PORT") proto = "ssl" - except: # pylint: disable=W0702 + except: pass if proto is None: @@ -476,7 +476,7 @@ def server_main(args): pass the results along to a client. """ - logger = logging.LoggerAdapter(logging.root, dict(connection = _hostport_tag())) + logger = logging.LoggerAdapter(logging.root, dict(connection = hostport_tag())) logger.debug("[Starting]") @@ -516,7 +516,7 @@ def listener_main(args): try: listener = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) listener.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) - except: # pylint: disable=W0702 + except: if listener is not None: listener.close() listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -536,8 +536,8 @@ def listener_main(args): logging.debug("[Received connection from %r]", ai) pid = os.fork() if pid == 0: - os.dup2(s.fileno(), 0) # pylint: disable=E1103 - os.dup2(s.fileno(), 1) # pylint: disable=E1103 + os.dup2(s.fileno(), 0) # pylint: disable=E1101 + os.dup2(s.fileno(), 1) # pylint: disable=E1101 s.close() #os.closerange(3, os.sysconf("SC_OPEN_MAX")) server_main(args) @@ -546,11 +546,11 @@ def listener_main(args): logging.debug("[Spawned server %d]", pid) while True: try: - pid, status = os.waitpid(0, os.WNOHANG) # pylint: disable=W0612 + pid, status = os.waitpid(0, os.WNOHANG) if pid: - logging.debug("[Server %s exited]", pid) + logging.debug("[Server %s exited with status 0x%x]", pid, status) continue - except: # pylint: disable=W0702 + except: pass break diff --git a/rpki/sundial.py b/rpki/sundial.py index 0381599f..1556d0bd 100644 --- a/rpki/sundial.py +++ b/rpki/sundial.py @@ -155,10 +155,17 @@ class datetime(pydatetime.datetime): return other if other < self else self - def __add__(self, y): return _cast(pydatetime.datetime.__add__(self, y)) - def __radd__(self, y): return _cast(pydatetime.datetime.__radd__(self, y)) - def __rsub__(self, y): return _cast(pydatetime.datetime.__rsub__(self, y)) - def __sub__(self, y): return _cast(pydatetime.datetime.__sub__(self, y)) + def __add__(self, y): + return _cast(pydatetime.datetime.__add__(self, y)) + + def __radd__(self, y): + return _cast(pydatetime.datetime.__radd__(self, y)) + + def __rsub__(self, y): + return _cast(pydatetime.datetime.__rsub__(self, y)) + + def __sub__(self, y): + return _cast(pydatetime.datetime.__sub__(self, y)) @classmethod def DateTime_or_None(cls, s): @@ -172,7 +179,7 @@ class datetime(pydatetime.datetime): if t: try: return cls(*[int(x) for x in d.split("-") + t.split(":")]) - except: # pylint: disable=W0702 + except: break from rpki.mysql_import import MySQLdb @@ -260,19 +267,44 @@ class timedelta(pydatetime.timedelta): return cls(days = x.days, seconds = x.seconds, microseconds = x.microseconds) - def __abs__(self): return _cast(pydatetime.timedelta.__abs__(self)) - def __add__(self, x): return _cast(pydatetime.timedelta.__add__(self, x)) - def __div__(self, x): return _cast(pydatetime.timedelta.__div__(self, x)) - def __floordiv__(self, x): return _cast(pydatetime.timedelta.__floordiv__(self, x)) - def __mul__(self, x): return _cast(pydatetime.timedelta.__mul__(self, x)) - def __neg__(self): return _cast(pydatetime.timedelta.__neg__(self)) - def __pos__(self): return _cast(pydatetime.timedelta.__pos__(self)) - def __radd__(self, x): return _cast(pydatetime.timedelta.__radd__(self, x)) - def __rdiv__(self, x): return _cast(pydatetime.timedelta.__rdiv__(self, x)) - def __rfloordiv__(self, x): return _cast(pydatetime.timedelta.__rfloordiv__(self, x)) - def __rmul__(self, x): return _cast(pydatetime.timedelta.__rmul__(self, x)) - def __rsub__(self, x): return _cast(pydatetime.timedelta.__rsub__(self, x)) - def __sub__(self, x): return _cast(pydatetime.timedelta.__sub__(self, x)) + def __abs__(self): + return _cast(pydatetime.timedelta.__abs__(self)) + + def __add__(self, x): + return _cast(pydatetime.timedelta.__add__(self, x)) + + def __div__(self, x): + return _cast(pydatetime.timedelta.__div__(self, x)) + + def __floordiv__(self, x): + return _cast(pydatetime.timedelta.__floordiv__(self, x)) + + def __mul__(self, x): + return _cast(pydatetime.timedelta.__mul__(self, x)) + + def __neg__(self): + return _cast(pydatetime.timedelta.__neg__(self)) + + def __pos__(self): + return _cast(pydatetime.timedelta.__pos__(self)) + + def __radd__(self, x): + return _cast(pydatetime.timedelta.__radd__(self, x)) + + def __rdiv__(self, x): + return _cast(pydatetime.timedelta.__rdiv__(self, x)) + + def __rfloordiv__(self, x): + return _cast(pydatetime.timedelta.__rfloordiv__(self, x)) + + def __rmul__(self, x): + return _cast(pydatetime.timedelta.__rmul__(self, x)) + + def __rsub__(self, x): + return _cast(pydatetime.timedelta.__rsub__(self, x)) + + def __sub__(self, x): + return _cast(pydatetime.timedelta.__sub__(self, x)) def _cast(x): """ diff --git a/rpki/x509.py b/rpki/x509.py index 32bedc6a..5286fabd 100644 --- a/rpki/x509.py +++ b/rpki/x509.py @@ -159,6 +159,10 @@ class X501DN(object): simple. """ + def __init__(self, dn): + assert isinstance(dn, tuple) + self.dn = dn + def __str__(self): return "".join("/" + "+".join("%s=%s" % (rpki.oids.oid2name(a[0]), a[1]) for a in rdn) @@ -181,19 +185,15 @@ class X501DN(object): elif isinstance(sn, (str, unicode)): assert all(c in "0123456789abcdefABCDEF" for c in sn) sn = str(sn) - self = cls() if sn is not None: - self.dn = (((rpki.oids.commonName, cn),), ((rpki.oids.serialNumber, sn),)) + dn = (((rpki.oids.commonName, cn),), ((rpki.oids.serialNumber, sn),)) else: - self.dn = (((rpki.oids.commonName, cn),),) - return self + dn = (((rpki.oids.commonName, cn),),) + return cls(dn) @classmethod - def from_POW(cls, t): - assert isinstance(t, tuple) - self = cls() - self.dn = t - return self + def from_POW(cls, dn): + return cls(dn) def get_POW(self): return self.dn @@ -320,6 +320,8 @@ class DER_object(object): Check for updates to a DER object that auto-updates from a file. """ + # pylint: disable=W0201 + if self.filename is None: return try: @@ -368,6 +370,7 @@ class DER_object(object): Subclasses may need to override this. """ + # pylint: disable=W0201 assert self.empty() self.POW = self.POW_class.pemRead(pem) @@ -391,8 +394,9 @@ class DER_object(object): Subclasses may need to override this method. """ + # pylint: disable=E0203,W0201 self.check() - if not self.POW: # pylint: disable=E0203 + if not self.POW: self.POW = self.POW_class.derRead(self.get_DER()) return self.POW @@ -566,7 +570,7 @@ class DER_object(object): resources = rpki.resource_set.resource_bag.from_POW_rfc3779(self.get_POW().getRFC3779()) try: - resources.valid_until = self.getNotAfter() + resources.valid_until = self.getNotAfter() # pylint: disable=E1101 except AttributeError: pass return resources @@ -615,11 +619,11 @@ class DER_object(object): this information at the start of the tracking line. """ + # pylint: disable=E1101 + try: - return "%s %s %s" % (uri, - self.creation_timestamp, - "".join(("%02X" % ord(b) for b in sha1(self.get_DER())))) - except: # pylint: disable=W0702 + return "%s %s %s" % (uri, self.creation_timestamp, "".join(("%02X" % ord(b) for b in sha1(self.get_DER())))) + except: return uri def __getstate__(self): @@ -995,8 +999,9 @@ class PKCS10(DER_object): Get the rpki.POW value of this certification request. """ + # pylint: disable=E0203,W0201 self.check() - if not self.POW: # pylint: disable=E0203 + if not self.POW: self.POW = rpki.POW.PKCS10.derRead(self.get_DER()) return self.POW @@ -1279,8 +1284,9 @@ class PrivateKey(DER_object): Get the rpki.POW value of this keypair. """ + # pylint: disable=E0203,W0201 self.check() - if not self.POW: # pylint: disable=E0203 + if not self.POW: self.POW = rpki.POW.Asymmetric.derReadPrivate(self.get_DER()) return self.POW @@ -1296,6 +1302,7 @@ class PrivateKey(DER_object): Set the POW value of this keypair from a PEM string. """ + # pylint: disable=W0201 assert self.empty() self.POW = self.POW_class.pemReadPrivate(pem) @@ -1345,8 +1352,9 @@ class PublicKey(DER_object): Get the rpki.POW value of this public key. """ + # pylint: disable=E0203,W0201 self.check() - if not self.POW: # pylint: disable=E0203 + if not self.POW: self.POW = rpki.POW.Asymmetric.derReadPublic(self.get_DER()) return self.POW @@ -1362,6 +1370,7 @@ class PublicKey(DER_object): Set the POW value of this public key from a PEM string. """ + # pylint: disable=W0201 assert self.empty() self.POW = self.POW_class.pemReadPublic(pem) @@ -1490,8 +1499,9 @@ class CMS_object(DER_object): Get the rpki.POW value of this CMS_object. """ + # pylint: disable=E0203,W0201 self.check() - if not self.POW: # pylint: disable=E0203 + if not self.POW: self.POW = self.POW_class.derRead(self.get_DER()) return self.POW @@ -1660,6 +1670,9 @@ class CMS_object(DER_object): [c.get_POW() for c in crls], rpki.POW.CMS_NOCERTS if no_certs else 0) + def _sign(self, cert, keypair, certs, crls, flags): + raise NotImplementedError + @property def creation_timestamp(self): """ @@ -1697,6 +1710,7 @@ class Wrapped_CMS_object(CMS_object): Set the (inner) content of this Wrapped_CMS_object, clearing the wrapper. """ + # pylint: disable=W0201 self.clear() self.content = content @@ -1740,10 +1754,17 @@ class Wrapped_CMS_object(CMS_object): different CMS-based POW classes handle the inner content. """ + # pylint: disable=W0201 cms = self.POW_class() cms.sign(cert, keypair, self.encode(), certs, crls, self.econtent_oid, flags) self.POW = cms + def decode(self, whatever): + raise NotImplementedError + + def encode(self): + raise NotImplementedError + class DER_CMS_object(CMS_object): """ @@ -1856,7 +1877,7 @@ class ROA(DER_CMS_object): text.append("%s/%s-%s" % (prefix, prefixlen, maxprefixlen)) text.sort() msg = "%s %s %s" % (msg, asn, ",".join(text)) - except: # pylint: disable=W0702 + except: pass return msg @@ -1897,6 +1918,8 @@ class XML_CMS_object(Wrapped_CMS_object): """ econtent_oid = rpki.oids.id_ct_xml + encoding = None + schema = None ## @var dump_outbound_cms # If set, we write all outbound XML-CMS PDUs to disk, for debugging. @@ -1935,6 +1958,7 @@ class XML_CMS_object(Wrapped_CMS_object): Decode XML and set inner content. """ + # pylint: disable=W0201 self.content = lxml.etree.fromstring(xml) def pretty_print_content(self): @@ -2047,6 +2071,7 @@ class Ghostbuster(Wrapped_CMS_object): the VCard as an opaque byte string, so no encoding needed here. """ + # pylint: disable=W0201 self.content = vcard @classmethod @@ -2086,8 +2111,9 @@ class CRL(DER_object): Get the rpki.POW value of this CRL. """ + # pylint: disable=W0201,E0203 self.check() - if not self.POW: # pylint: disable=E0203 + if not self.POW: self.POW = rpki.POW.CRL.derRead(self.get_DER()) return self.POW |