diff --git a/.gitignore b/.gitignore index 925b66eed..e44bf00fe 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ /static /testresult /unix.tag +/tmp-nomcom-public-keys-dir diff --git a/bin/daily b/bin/daily index f868e933d..3764e4a94 100755 --- a/bin/daily +++ b/bin/daily @@ -18,9 +18,16 @@ logger -p user.info -t cron "Running $DTDIR/bin/daily" # Set up the virtual environment source $DTDIR/env/bin/activate + +# Update our information about the current version of some commands we use +$DTDIR/ietf/manage.py update_external_command_info + # Populate the yang repositories $DTDIR/ietf/manage.py populate_yang_model_dirs +# Re-run yang checks on active documents +$DTDIR/ietf/manage.py run_yang_model_checks + # Expire internet drafts # Enable when removed from /a/www/ietf-datatracker/scripts/Cron-runner: $DTDIR/ietf/bin/expire-ids @@ -36,5 +43,3 @@ $DTDIR/ietf/bin/rfc-editor-index-updates -d 1969-01-01 # Fetch meeting attendance data from ietf.org/registration/attendees $DTDIR/ietf/manage.py fetch_meeting_attendance --latest - - diff --git a/bin/mkdevbranch b/bin/mkdevbranch index 16d038b9f..2ab89e9f8 100755 --- a/bin/mkdevbranch +++ b/bin/mkdevbranch @@ -142,7 +142,7 @@ cd $progdir if [ "$who" ]; then mksvndir $who svn cp https://svn.tools.ietf.org/svn/tools/ietfdb/$source https://svn.tools.ietf.org/svn/tools/ietfdb/personal/$who/$target/ -m "New branch for $target" - say "New branch: ^/personal/$who/$target" + print "New branch: ^/personal/$who/$target" else [ "$num" ] || num=$( < /www/tools.ietf.org/meta/current-ietf-number.txt) for n in $(seq $((num-3)) $num); do diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py index b71be5aa5..96162b164 100644 --- a/ietf/doc/templatetags/ietf_filters.py +++ b/ietf/doc/templatetags/ietf_filters.py @@ -533,3 +533,6 @@ def comma_separated_list(seq, end_word="and"): def role_names(roles): return list(set([ "%s %s" % (r.group.name, r.name.name) for r in roles ])) +@register.filter() +def zaptmp(s): + return re.sub(r'/tmp/tmp[^/]+/', '', s) diff --git a/ietf/name/fixtures/names.json b/ietf/name/fixtures/names.json index 6a6cd71e2..87ffc206b 100644 --- a/ietf/name/fixtures/names.json +++ b/ietf/name/fixtures/names.json @@ -9708,5 +9708,38 @@ }, "model": "name.topicaudiencename", "pk": "nominees" + }, + { + "fields": { + "command": "xym", + "switch": "--version", + "time": "2017-06-15T06:24:58.869", + "used": true, + "version": "xym 0.3.2" + }, + "model": "utils.versioninfo", + "pk": 1 + }, + { + "fields": { + "command": "pyang", + "switch": "--version", + "time": "2017-06-15T06:24:59.516", + "used": true, + "version": "pyang 1.7.2" + }, + "model": "utils.versioninfo", + "pk": 2 + }, + { + "fields": { + "command": "yanglint", + "switch": "--version", + "time": "2017-06-15T06:24:59.531", + "used": true, + "version": "yanglint 0.12.183" + }, + "model": "utils.versioninfo", + "pk": 3 } ] diff --git a/ietf/name/generate_fixtures.py b/ietf/name/generate_fixtures.py index 753f6b8ad..f90abcbda 100644 --- a/ietf/name/generate_fixtures.py +++ b/ietf/name/generate_fixtures.py @@ -47,5 +47,8 @@ import ietf.mailtrigger.models objects += ietf.mailtrigger.models.Recipient.objects.all() objects += ietf.mailtrigger.models.MailTrigger.objects.all() +import ietf.utils.models +objects += ietf.utils.models.VersionInfo.objects.all() + output("names", objects) diff --git a/ietf/settings.py b/ietf/settings.py index 5493189fc..c50b6753c 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -660,11 +660,19 @@ IDSUBMIT_DEFAULT_CUTOFF_DAY_OFFSET_01 = 13 IDSUBMIT_DEFAULT_CUTOFF_TIME_UTC = datetime.timedelta(hours=23, minutes=59, seconds=59) IDSUBMIT_DEFAULT_CUTOFF_WARNING_DAYS = datetime.timedelta(days=21) +# 14 Jun 2017: New convention: prefix settings with the app name to which +# they (mainly) belong. So here, SUBMIT_, rather than IDSUBMIT_ +SUBMIT_YANG_RFC_MODEL_DIR = '/a/www/ietf-ftp/yang/rfcmod/' +SUBMIT_YANG_DRAFT_MODEL_DIR = '/a/www/ietf-ftp/yang/draftmod/' +SUBMIT_YANG_INVAL_MODEL_DIR = '/a/www/ietf-ftp/yang/invalmod/' + IDSUBMIT_REPOSITORY_PATH = INTERNET_DRAFT_PATH IDSUBMIT_STAGING_PATH = '/a/www/www6s/staging/' IDSUBMIT_STAGING_URL = '//www.ietf.org/staging/' IDSUBMIT_IDNITS_BINARY = '/a/www/ietf-datatracker/scripts/idnits' -IDSUBMIT_PYANG_COMMAND = 'pyang -p %(modpath)s --verbose --ietf %(model)s' +SUBMIT_PYANG_COMMAND = 'pyang --verbose --ietf -p {libs} {model}' +SUBMIT_YANGLINT_COMMAND = 'yanglint --verbose -p {rfclib} -p {draftlib} {model}' +SUBMIT_YANGLINT_COMMAND = None # use the value above if you have yanglint installed IDSUBMIT_CHECKER_CLASSES = ( "ietf.submit.checkers.DraftIdnitsChecker", @@ -696,10 +704,6 @@ IDSUBMIT_MAX_DAILY_SAME_GROUP_SIZE = 450 # in MB IDSUBMIT_MAX_DAILY_SUBMISSIONS = 1000 IDSUBMIT_MAX_DAILY_SUBMISSIONS_SIZE = 2000 # in MB -YANG_RFC_MODEL_DIR = '/a/www/ietf-ftp/yang/rfcmod/' -YANG_DRAFT_MODEL_DIR = '/a/www/ietf-ftp/yang/draftmod/' -YANG_INVAL_MODEL_DIR = '/a/www/ietf-ftp/yang/invalmod/' - XML_LIBRARY = "/www/tools.ietf.org/tools/xml2rfc/web/public/rfc/" # === Meeting Related Settings ================================================= diff --git a/ietf/static/ietf/css/ietf.css b/ietf/static/ietf/css/ietf.css index 96fb06b6d..a0e48e2d3 100644 --- a/ietf/static/ietf/css/ietf.css +++ b/ietf/static/ietf/css/ietf.css @@ -865,3 +865,9 @@ blockquote { #debug-query-table .code .current { background-color: #ddd; } + +.checker-warning, +.checker-success { + line-height: 1.0; + cursor: pointer; +} diff --git a/ietf/submit/admin.py b/ietf/submit/admin.py index 194c0d1e0..5c5b6ff95 100644 --- a/ietf/submit/admin.py +++ b/ietf/submit/admin.py @@ -33,7 +33,7 @@ class SubmissionEventAdmin(admin.ModelAdmin): admin.site.register(SubmissionEvent, SubmissionEventAdmin) class SubmissionCheckAdmin(admin.ModelAdmin): - list_display = ['submission', 'time', 'checker', 'passed', 'errors', 'warnings', 'items'] + list_display = ['submission', 'time', 'checker', 'passed', 'errors', 'warnings', 'message'] raw_id_fields = ['submission'] search_fields = ['submission__name'] admin.site.register(SubmissionCheck, SubmissionCheckAdmin) diff --git a/ietf/submit/checkers.py b/ietf/submit/checkers.py index d1a1ae495..f600f0441 100644 --- a/ietf/submit/checkers.py +++ b/ietf/submit/checkers.py @@ -2,16 +2,19 @@ import os import re +import sys from xym import xym import shutil import tempfile +import StringIO from django.conf import settings import debug # pyflakes:ignore -from ietf.utils.pipe import pipe from ietf.utils.log import log +from ietf.utils.models import VersionInfo +from ietf.utils.pipe import pipe class DraftSubmissionChecker(): name = "" @@ -47,6 +50,9 @@ class DraftIdnitsChecker(object): # start using this when we provide more in the way of warnings during # submission checking: # symbol = '' + # symbol = u'\ua17d' # Yi syllable 'nit' + # symbol = u'\ub2e1' # Hangul syllable 'nit' + symbol = "" def __init__(self, options=["--submitcheck", "--nitcount", ]): @@ -123,39 +129,66 @@ class DraftYangChecker(object): def check_file_txt(self, path): name = os.path.basename(path) workdir = tempfile.mkdtemp() - errors = [] - warnings = [] - results = {} + errors = 0 + warnings = 0 + message = "" + results = [] + passed = True # Used by the submission tool. Yang checks always pass. - extractor = xym.YangModuleExtractor(path, workdir, strict=True, debug_level = 0) + extractor = xym.YangModuleExtractor(path, workdir, strict=True, strict_examples=False, debug_level=0) if not os.path.exists(path): return None, "%s: No such file or directory: '%s'"%(name.capitalize(), path), errors, warnings, results with open(path) as file: + out = "" + err = "" + code = 0 try: # This places the yang models as files in workdir + saved_stdout = sys.stdout + saved_stderr = sys.stderr + sys.stdout = StringIO.StringIO() + sys.stderr = StringIO.StringIO() extractor.extract_yang_model(file.readlines()) + out = sys.stdout.getvalue() + err = sys.stderr.getvalue() + sys.stdout = saved_stdout + sys.stderr = saved_stderr model_list = extractor.get_extracted_models() except Exception as exc: - passed = False - message = exc - errors = [ (name, None, None, exc) ] - warnings = [] - return passed, message, errors, warnings + code = 1 + err = '\n'.join( [ m for m in [out, err, exc] if m ] ) + if err: + code += 1 + command = "xym" + cmd_version = VersionInfo.objects.get(command=command).version + message = "%s:\n%s\n\n" % (cmd_version, out.replace('\n\n','\n').strip() if code == 0 else err) + + results.append({ + "name": name, + "passed": passed, + "message": message, + "warnings": 0, + "errors": code, + "items": [], + }) for model in model_list: path = os.path.join(workdir, model) + message = "" modpath = ':'.join([ workdir, - settings.YANG_RFC_MODEL_DIR, - settings.YANG_DRAFT_MODEL_DIR, - settings.YANG_INVAL_MODEL_DIR, + settings.SUBMIT_YANG_RFC_MODEL_DIR, + settings.SUBMIT_YANG_DRAFT_MODEL_DIR, + settings.SUBMIT_YANG_INVAL_MODEL_DIR, ]) with open(path) as file: text = file.readlines() - cmd = settings.IDSUBMIT_PYANG_COMMAND % {"modpath": modpath, "model": path, } + # pyang + cmd_template = settings.SUBMIT_PYANG_COMMAND + command = cmd_template.split()[0] + cmd_version = VersionInfo.objects.get(command=command).version + cmd = cmd_template.format(libs=modpath, model=path) code, out, err = pipe(cmd) - errors = 0 - warnings = 0 items = [] if code > 0: error_lines = err.splitlines() @@ -175,26 +208,54 @@ class DraftYangChecker(object): warnings += 1 except ValueError: pass - results[model] = { - "passed": code == 0, - "message": out+"No validation errors\n" if code == 0 else err, + #passed = passed and code == 0 # For the submission tool. Yang checks always pass + message += "%s: %s:\n%s\n" % (cmd_version, cmd_template, out+"No validation errors\n" if code == 0 else err) + + # yanglint + cmd_template = settings.SUBMIT_YANGLINT_COMMAND + command = cmd_template.split()[0] + cmd_version = VersionInfo.objects.get(command=command).version + cmd = cmd_template.format(model=path, rfclib=settings.SUBMIT_YANG_RFC_MODEL_DIR, draftlib=settings.SUBMIT_YANG_DRAFT_MODEL_DIR) + code, out, err = pipe(cmd) + if code > 0: + error_lines = err.splitlines() + for line in error_lines: + if line.strip(): + try: + if 'err : ' in line: + errors += 1 + if 'warn: ' in line: + warnings += 1 + except ValueError: + pass + #passed = passed and code == 0 # For the submission tool. Yang checks always pass + message += "%s: %s:\n%s\n" % (cmd_version, cmd_template, out+"No validation errors\n" if code == 0 else err) + + if errors==0 and warnings==0: + dest = os.path.join(settings.SUBMIT_YANG_DRAFT_MODEL_DIR, model) + shutil.move(path, dest) + else: + dest = os.path.join(settings.SUBMIT_YANG_INVAL_MODEL_DIR, model) + shutil.move(path, dest) + + # summary result + results.append({ + "name": model, + "passed": passed, + "message": message, "warnings": warnings, "errors": errors, "items": items, - } + }) + shutil.rmtree(workdir) - ## For now, never fail because of failed yang validation. - if len(model_list): - passed = True - else: - passed = None - #passed = all( res["passed"] for res in results.values() ) - message = "\n\n".join([ "\n".join([model+':', res["message"]]) for model, res in results.items() ]) - errors = sum(res["errors"] for res in results.values() ) - warnings = sum(res["warnings"] for res in results.values() ) - items = [ e for res in results.values() for e in res["items"] ] + passed = all( res["passed"] for res in results ) + message = "\n".join([ "\n".join([res['name']+':', res["message"]]) for res in results ]) + errors = sum(res["errors"] for res in results ) + warnings = sum(res["warnings"] for res in results ) + items = [ e for res in results for e in res["items"] ] return passed, message, errors, warnings, items diff --git a/ietf/submit/migrations/0010_data_set_submission_check_symbol.py b/ietf/submit/migrations/0010_data_set_submission_check_symbol.py index 43ca7fc82..8bce3a132 100644 --- a/ietf/submit/migrations/0010_data_set_submission_check_symbol.py +++ b/ietf/submit/migrations/0010_data_set_submission_check_symbol.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- from __future__ import unicode_literals from tqdm import tqdm diff --git a/ietf/submit/models.py b/ietf/submit/models.py index 90a6a1378..82ca0e067 100644 --- a/ietf/submit/models.py +++ b/ietf/submit/models.py @@ -65,6 +65,10 @@ class Submission(models.Model): def existing_document(self): return Document.objects.filter(name=self.name).first() + def latest_checks(self): + checks = [ self.checks.filter(checker=c, passed__in=[True,False]).latest('time') for c in self.checks.values_list('checker', flat=True).distinct() ] + return checks + class SubmissionCheck(models.Model): time = models.DateTimeField(auto_now=True) submission = models.ForeignKey(Submission, related_name='checks') diff --git a/ietf/submit/test_submission.nonascii b/ietf/submit/test_submission.nonascii index 02c044aa3..b6c6b4fe9 100644 --- a/ietf/submit/test_submission.nonascii +++ b/ietf/submit/test_submission.nonascii @@ -71,99 +71,90 @@ Table of Contents 2. Yang - file "ietf-mpls@2015-10-16.yang" + file "ietf-yang-metadata@2016-08-05.yang" - module ietf-mpls { + module ietf-yang-metadata { - namespace "urn:ietf:params:xml:ns:yang:ietf-mpls"; + namespace "urn:ietf:params:xml:ns:yang:ietf-yang-metadata"; - prefix "mpls"; + prefix "md"; - import ietf-routing { - prefix "rt"; - } + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; - import ietf-interfaces { - prefix "if"; - } + contact + "WG Web: - organization "TBD"; + WG List: - contact "TBD"; + WG Chair: Lou Berger + + + WG Chair: Kent Watsen + + + Editor: Ladislav Lhotka + "; description - "This YANG module defines the essential components for the - management of the MPLS subsystem."; + "This YANG module defines an 'extension' statement that allows + for defining metadata annotations. - revision "2015-10-16" { + Copyright (c) 2016 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, is permitted pursuant to, and subject to + the license terms contained in, the Simplified BSD License set + forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 7952 + (http://www.rfc-editor.org/info/rfc7952); see the RFC itself + for full legal notices."; + + revision 2016-08-05 { description - "Initial revision"; - reference "RFC 3031: A YANG Data Model for base MPLS"; + "Initial revision."; + reference + "RFC 7952: Defining and Using Metadata with YANG"; } - typedef mpls-label { - type uint32 { - range "0..1048575"; - } + extension annotation { + argument name; description - "The MPLS label range"; - } + "This extension allows for defining metadata annotations in + YANG modules. The 'md:annotation' statement can appear only + at the top level of a YANG module or submodule, i.e., it + becomes a new alternative in the ABNF production rule for + 'body-stmts' (Section 14 in RFC 7950). - typedef percent { - type uint16 { - range "0 .. 100"; - } - description "Percentage"; - } + The argument of the 'md:annotation' statement defines the name + of the annotation. Syntactically, it is a YANG identifier as + defined in Section 6.2 of RFC 7950. - grouping interface-mpls { - description "MPLS interface properties grouping"; - leaf enabled { - type boolean; - description - "'true' if mpls encapsulation is enabled on the - interface. 'false' if mpls encapsulation is enabled - on the interface."; - } - } + An annotation defined with this 'extension' statement inherits + the namespace and other context from the YANG module in which + it is defined. - augment "/rt:routing/rt:routing-instance" { - description "MPLS augmentation."; - container mpls { - description - "MPLS container, to be used as an augmentation target node - other MPLS sub-features config, e.g. MPLS static LSP, MPLS - LDP LSPs, and Trafic Engineering MPLS LSP Tunnels, etc."; + The data type of the annotation value is specified in the same + way as for a leaf data node using the 'type' statement. - list interface { - key "name"; - description "List of MPLS interfaces"; - leaf name { - type if:interface-ref; - description - "The name of a configured MPLS interface"; - } - container config { - description "Holds intended configuration"; - uses interface-mpls; - } - container state { - config false; - description "Holds inuse configuration"; - uses interface-mpls; - } - } - } - } + The semantics of the annotation and other documentation can be + specified using the following standard YANG substatements (all + are optional): 'description', 'if-feature', 'reference', + 'status', and 'units'. - augment "/rt:routing-state/rt:routing-instance" { - description "MPLS augmentation."; - container mpls { - config false; - description - "MPLS container, to be used as an augmentation target node - other MPLS sub-features state"; - } + A server announces support for a particular annotation by + including the module in which the annotation is defined among + the advertised YANG modules, e.g., in a NETCONF + message or in the YANG library (RFC 7950). The annotation can + then be attached to any instance of a data node defined in any + YANG module that is advertised by the server. + + XML encoding and JSON encoding of annotations are defined in + RFC 7952."; } } diff --git a/ietf/submit/test_submission.txt b/ietf/submit/test_submission.txt index b6551bf2d..30e063c47 100644 --- a/ietf/submit/test_submission.txt +++ b/ietf/submit/test_submission.txt @@ -73,99 +73,90 @@ Table of Contents 2. Yang - file "ietf-mpls@2015-10-16.yang" + file "ietf-yang-metadata@2016-08-05.yang" - module ietf-mpls { + module ietf-yang-metadata { - namespace "urn:ietf:params:xml:ns:yang:ietf-mpls"; + namespace "urn:ietf:params:xml:ns:yang:ietf-yang-metadata"; - prefix "mpls"; + prefix "md"; - import ietf-routing { - prefix "rt"; - } + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; - import ietf-interfaces { - prefix "if"; - } + contact + "WG Web: - organization "TBD"; + WG List: - contact "TBD"; + WG Chair: Lou Berger + + + WG Chair: Kent Watsen + + + Editor: Ladislav Lhotka + "; description - "This YANG module defines the essential components for the - management of the MPLS subsystem."; + "This YANG module defines an 'extension' statement that allows + for defining metadata annotations. - revision "2015-10-16" { + Copyright (c) 2016 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, is permitted pursuant to, and subject to + the license terms contained in, the Simplified BSD License set + forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 7952 + (http://www.rfc-editor.org/info/rfc7952); see the RFC itself + for full legal notices."; + + revision 2016-08-05 { description - "Initial revision"; - reference "RFC 3031: A YANG Data Model for base MPLS"; + "Initial revision."; + reference + "RFC 7952: Defining and Using Metadata with YANG"; } - typedef mpls-label { - type uint32 { - range "0..1048575"; - } + extension annotation { + argument name; description - "The MPLS label range"; - } + "This extension allows for defining metadata annotations in + YANG modules. The 'md:annotation' statement can appear only + at the top level of a YANG module or submodule, i.e., it + becomes a new alternative in the ABNF production rule for + 'body-stmts' (Section 14 in RFC 7950). - typedef percent { - type uint16 { - range "0 .. 100"; - } - description "Percentage"; - } + The argument of the 'md:annotation' statement defines the name + of the annotation. Syntactically, it is a YANG identifier as + defined in Section 6.2 of RFC 7950. - grouping interface-mpls { - description "MPLS interface properties grouping"; - leaf enabled { - type boolean; - description - "'true' if mpls encapsulation is enabled on the - interface. 'false' if mpls encapsulation is enabled - on the interface."; - } - } + An annotation defined with this 'extension' statement inherits + the namespace and other context from the YANG module in which + it is defined. - augment "/rt:routing/rt:routing-instance" { - description "MPLS augmentation."; - container mpls { - description - "MPLS container, to be used as an augmentation target node - other MPLS sub-features config, e.g. MPLS static LSP, MPLS - LDP LSPs, and Trafic Engineering MPLS LSP Tunnels, etc."; + The data type of the annotation value is specified in the same + way as for a leaf data node using the 'type' statement. - list interface { - key "name"; - description "List of MPLS interfaces"; - leaf name { - type if:interface-ref; - description - "The name of a configured MPLS interface"; - } - container config { - description "Holds intended configuration"; - uses interface-mpls; - } - container state { - config false; - description "Holds inuse configuration"; - uses interface-mpls; - } - } - } - } + The semantics of the annotation and other documentation can be + specified using the following standard YANG substatements (all + are optional): 'description', 'if-feature', 'reference', + 'status', and 'units'. - augment "/rt:routing-state/rt:routing-instance" { - description "MPLS augmentation."; - container mpls { - config false; - description - "MPLS container, to be used as an augmentation target node - other MPLS sub-features state"; - } + A server announces support for a particular annotation by + including the module in which the annotation is defined among + the advertised YANG modules, e.g., in a NETCONF + message or in the YANG library (RFC 7950). The annotation can + then be attached to any instance of a data node defined in any + YANG module that is advertised by the server. + + XML encoding and JSON encoding of annotations are defined in + RFC 7952."; } } diff --git a/ietf/submit/test_submission.xml b/ietf/submit/test_submission.xml index a8b6d9cde..4dbe41382 100644 --- a/ietf/submit/test_submission.xml +++ b/ietf/submit/test_submission.xml @@ -35,100 +35,91 @@
file "ietf-mpls@2015-10-16.yang" + file "ietf-yang-metadata@2016-08-05.yang" -module ietf-mpls { +module ietf-yang-metadata { - namespace "urn:ietf:params:xml:ns:yang:ietf-mpls"; + namespace "urn:ietf:params:xml:ns:yang:ietf-yang-metadata"; - prefix "mpls"; + prefix "md"; - import ietf-routing { - prefix "rt"; - } + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; - import ietf-interfaces { - prefix "if"; - } + contact + "WG Web: - organization "TBD"; + WG List: - contact "TBD"; + WG Chair: Lou Berger + - description - "This YANG module defines the essential components for the - management of the MPLS subsystem."; + WG Chair: Kent Watsen + - revision "2015-10-16" { - description - "Initial revision"; - reference "RFC 3031: A YANG Data Model for base MPLS"; - } + Editor: Ladislav Lhotka + "; - typedef mpls-label { - type uint32 { - range "0..1048575"; - } - description - "The MPLS label range"; - } + description + "This YANG module defines an 'extension' statement that allows + for defining metadata annotations. - typedef percent { - type uint16 { - range "0 .. 100"; - } - description "Percentage"; - } + Copyright (c) 2016 IETF Trust and the persons identified as + authors of the code. All rights reserved. - grouping interface-mpls { - description "MPLS interface properties grouping"; - leaf enabled { - type boolean; - description - "'true' if mpls encapsulation is enabled on the - interface. 'false' if mpls encapsulation is enabled - on the interface."; - } - } + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject to + the license terms contained in, the Simplified BSD License set + forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). - augment "/rt:routing/rt:routing-instance" { - description "MPLS augmentation."; - container mpls { - description - "MPLS container, to be used as an augmentation target node - other MPLS sub-features config, e.g. MPLS static LSP, MPLS - LDP LSPs, and Trafic Engineering MPLS LSP Tunnels, etc."; + This version of this YANG module is part of RFC 7952 + (http://www.rfc-editor.org/info/rfc7952); see the RFC itself + for full legal notices."; - list interface { - key "name"; - description "List of MPLS interfaces"; - leaf name { - type if:interface-ref; - description - "The name of a configured MPLS interface"; - } - container config { - description "Holds intended configuration"; - uses interface-mpls; - } - container state { - config false; - description "Holds inuse configuration"; - uses interface-mpls; - } - } - } - } + revision 2016-08-05 { + description + "Initial revision."; + reference + "RFC 7952: Defining and Using Metadata with YANG"; + } - augment "/rt:routing-state/rt:routing-instance" { - description "MPLS augmentation."; - container mpls { - config false; - description - "MPLS container, to be used as an augmentation target node - other MPLS sub-features state"; - } - } + extension annotation { + argument name; + description + "This extension allows for defining metadata annotations in + YANG modules. The 'md:annotation' statement can appear only + at the top level of a YANG module or submodule, i.e., it + becomes a new alternative in the ABNF production rule for + 'body-stmts' (Section 14 in RFC 7950). + + The argument of the 'md:annotation' statement defines the name + of the annotation. Syntactically, it is a YANG identifier as + defined in Section 6.2 of RFC 7950. + + An annotation defined with this 'extension' statement inherits + the namespace and other context from the YANG module in which + it is defined. + + The data type of the annotation value is specified in the same + way as for a leaf data node using the 'type' statement. + + The semantics of the annotation and other documentation can be + specified using the following standard YANG substatements (all + are optional): 'description', 'if-feature', 'reference', + 'status', and 'units'. + + A server announces support for a particular annotation by + including the module in which the annotation is defined among + the advertised YANG modules, e.g., in a NETCONF + message or in the YANG library (RFC 7950). The annotation can + then be attached to any instance of a data node defined in any + YANG module that is advertised by the server. + + XML encoding and JSON encoding of annotations are defined in + RFC 7952."; + } } diff --git a/ietf/submit/test_submission_invalid_yang.txt b/ietf/submit/test_submission_invalid_yang.txt new file mode 100644 index 000000000..d3b9a9d3d --- /dev/null +++ b/ietf/submit/test_submission_invalid_yang.txt @@ -0,0 +1,213 @@ + + + + +Network Working Group A. Name +Internet-Draft Test Centre Inc. +Intended status: Informational %(month)s %(year)s +Expires: %(expiration)s + + + Testing Tests + %(name)s + +Abstract + + This document describes how to test tests. + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at http://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on %(expiration)s. + +Copyright Notice + + Copyright (c) %(year)s IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + + + +Name Expires %(expiration)s [Page 1] + +Internet-Draft Testing Tests %(month)s %(year)s + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Yang . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 + 3. JSON example . . . . . . . . . . . . . . . . . . . . . . . . 2 + 4. Security Considerations . . . . . . . . . . . . . . . . . . . 2 + 5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 2 + Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 2 + +1. Introduction + + This document describes a protocol for testing tests. + +2. Yang + + file "ietf-yang-metadata@2016-08-05.yang" + + module ietf-yang-metadata { + + namespace "urn:ietf:params:xml:ns:yang:ietf-yang-metadata"; + + prefix "md"; + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + + WG List: + + WG Chair: Lou Berger + + + WG Chair: Kent Watsen + + + Editor: Ladislav Lhotka + "; + + description + "This YANG module defines an 'extension' statement that allows + for defining metadata annotations. + + Copyright (c) 2016 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, is permitted pursuant to, and subject to + the license terms contained in, the Simplified BSD License set + forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 7952 + (http://www.rfc-editor.org/info/rfc7952); see the RFC itself + for full legal notices."; + + revision 2016-08-05 { + description + "Initial revision."; + reference + "RFC 7952: Defining and Using Metadata with YANG"; + } + + extension annotation { + argument name;; + description + "This extension allows for defining metadata annotations in + YANG modules. The 'md:annotation' statement can appear only + at the top level of a YANG module or submodule, i.e., it + becomes a new alternative in the ABNF production rule for + 'body-stmts' (Section 14 in RFC 7950). + + The argument of the 'md:annotation' statement defines the name + of the annotation. Syntactically, it is a YANG identifier as + defined in Section 6.2 of RFC 7950. + + An annotation defined with this 'extension' statement inherits + the namespace and other context from the YANG module in which + it is defined. + + The data type of the annotation value is specified in the same + way as for a leaf data node using the 'type' statement. + + The semantics of the annotation and other documentation can be + specified using the following standard YANG substatements (all + are optional): 'description', 'if-feature', 'reference', + 'status', and 'units'. + + A server announces support for a particular annotation by + including the module in which the annotation is defined among + the advertised YANG modules, e.g., in a NETCONF + message or in the YANG library (RFC 7950). The annotation can + then be attached to any instance of a data node defined in any + YANG module that is advertised by the server. + + XML encoding and JSON encoding of annotations are defined in + RFC 7952."; + } + } + + + +3. JSON example + + The JSON object should look like this: + + { + "test": 1234 + } + +4. Security Considerations + + There are none. + +5. IANA Considerations + + No new registrations for IANA. + +Author's Address + + Author Name + Test Centre Inc. + 42 Some Road + Some Where 12345 + UK + + Email: author@example.com + + + + + + + + + + + + + + + + + + + + + + + +Name Expires %(expiration)s [Page 2] diff --git a/ietf/submit/tests.py b/ietf/submit/tests.py index ce93184bb..4419d95e2 100644 --- a/ietf/submit/tests.py +++ b/ietf/submit/tests.py @@ -24,6 +24,7 @@ from ietf.person.factories import UserFactory, PersonFactory from ietf.submit.models import Submission, Preapproval from ietf.submit.mail import add_submission_email, process_response_email from ietf.utils.mail import outbox, empty_outbox +from ietf.utils.models import VersionInfo from ietf.utils.test_data import make_test_data from ietf.utils.test_utils import login_testing_unauthorized, unicontent, TestCase @@ -68,17 +69,17 @@ class SubmitTests(TestCase): self.archive_dir = self.tempdir('submit-archive') settings.INTERNET_DRAFT_ARCHIVE_DIR = self.archive_dir - self.saved_yang_rfc_model_dir = settings.YANG_RFC_MODEL_DIR + self.saved_yang_rfc_model_dir = settings.SUBMIT_YANG_RFC_MODEL_DIR self.yang_rfc_model_dir = self.tempdir('yang-rfc-model') - settings.YANG_RFC_MODEL_DIR = self.yang_rfc_model_dir + settings.SUBMIT_YANG_RFC_MODEL_DIR = self.yang_rfc_model_dir - self.saved_yang_draft_model_dir = settings.YANG_DRAFT_MODEL_DIR + self.saved_yang_draft_model_dir = settings.SUBMIT_YANG_DRAFT_MODEL_DIR self.yang_draft_model_dir = self.tempdir('yang-draft-model') - settings.YANG_DRAFT_MODEL_DIR = self.yang_draft_model_dir + settings.SUBMIT_YANG_DRAFT_MODEL_DIR = self.yang_draft_model_dir - self.saved_yang_inval_model_dir = settings.YANG_INVAL_MODEL_DIR + self.saved_yang_inval_model_dir = settings.SUBMIT_YANG_INVAL_MODEL_DIR self.yang_inval_model_dir = self.tempdir('yang-inval-model') - settings.YANG_INVAL_MODEL_DIR = self.yang_inval_model_dir + settings.SUBMIT_YANG_INVAL_MODEL_DIR = self.yang_inval_model_dir def tearDown(self): shutil.rmtree(self.staging_dir) @@ -91,9 +92,9 @@ class SubmitTests(TestCase): settings.INTERNET_DRAFT_PATH = self.saved_internet_draft_path settings.IDSUBMIT_REPOSITORY_PATH = self.saved_idsubmit_repository_path settings.INTERNET_DRAFT_ARCHIVE_DIR = self.saved_archive_dir - settings.YANG_RFC_MODEL_DIR = self.saved_yang_rfc_model_dir - settings.YANG_DRAFT_MODEL_DIR = self.saved_yang_draft_model_dir - settings.YANG_INVAL_MODEL_DIR = self.saved_yang_inval_model_dir + settings.SUBMIT_YANG_RFC_MODEL_DIR = self.saved_yang_rfc_model_dir + settings.SUBMIT_YANG_DRAFT_MODEL_DIR = self.saved_yang_draft_model_dir + settings.SUBMIT_YANG_INVAL_MODEL_DIR = self.saved_yang_inval_model_dir def do_submission(self, name, rev, group=None, formats=["txt",]): @@ -220,6 +221,11 @@ class SubmitTests(TestCase): r = self.client.get(status_url) self.assertEqual(r.status_code, 200) + + self.assertContains(r, 'xym') + self.assertContains(r, 'pyang') + self.assertContains(r, 'yanglint') + q = PyQuery(r.content) approve_button = q('[type=submit]:contains("Approve")') self.assertEqual(len(approve_button), 1) @@ -266,6 +272,15 @@ class SubmitTests(TestCase): self.assertTrue("ames-chairs@" in outbox[-1]["To"].lower()) self.assertTrue("mars-chairs@" in outbox[-1]["To"].lower()) + # fetch the document page + url = urlreverse('ietf.doc.views_doc.document_main', kwargs={'name':name}) + r = self.client.get(url) + self.assertContains(r, name) + self.assertContains(r, 'Active Internet-Draft') + self.assertContains(r, 'mars WG') + self.assertContains(r, 'Yang Validation') + self.assertContains(r, 'WG Document') + def test_submit_new_wg_txt(self): self.submit_new_wg(["txt"]) @@ -943,6 +958,38 @@ class SubmitTests(TestCase): self.assertIn('The idnits check returned 1 error', m) + def test_submit_invalid_yang(self): + make_test_data() + + name = "draft-yang-testing-invalid" + rev = "00" + group = None + + # get + url = urlreverse('ietf.submit.views.upload_submission') + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + q = PyQuery(r.content) + + # submit + files = {"txt": submission_file(name, rev, group, "txt", "test_submission_invalid_yang.txt") } + + r = self.client.post(url, files) + self.assertEqual(r.status_code, 302) + status_url = r["Location"] + r = self.client.get(status_url) + q = PyQuery(r.content) + # + self.assertContains(r, u'The yang validation returned 1 error') + # + m = q('#yang-validation-message').text() + for command in ['xym', 'pyang', 'yanglint']: + version = VersionInfo.objects.get(command=command).version + self.assertIn(version, m) + self.assertIn("draft-yang-testing-invalid-00.txt", m) + self.assertIn("error: syntax error: illegal keyword: ;", m) + self.assertIn("No validation errors", m) + class ApprovalsTestCase(TestCase): def test_approvals(self): diff --git a/ietf/submit/views.py b/ietf/submit/views.py index 743760116..23f122589 100644 --- a/ietf/submit/views.py +++ b/ietf/submit/views.py @@ -165,7 +165,9 @@ def upload_submission(request): def apply_check(submission, checker, method, fn): func = getattr(checker, method) passed, message, errors, warnings, items = func(fn) - check = SubmissionCheck(submission=submission, checker=checker.name, passed=passed, message=message, errors=errors, warnings=warnings, items=items, symbol=checker.symbol) + check = SubmissionCheck(submission=submission, checker=checker.name, passed=passed, + message=message, errors=errors, warnings=warnings, items=items, + symbol=checker.symbol) check.save() for checker_path in settings.IDSUBMIT_CHECKER_CLASSES: diff --git a/ietf/templates/doc/document_draft.html b/ietf/templates/doc/document_draft.html index 870e188a5..4925d992d 100644 --- a/ietf/templates/doc/document_draft.html +++ b/ietf/templates/doc/document_draft.html @@ -76,15 +76,6 @@ {% if latest_revision and latest_revision.time.date != doc.time.date %} (latest revision {{ latest_revision.time|date:"Y-m-d" }}) {% endif %} - {% for check in doc.submission.checks.all %} - {% if check.passed != None and check.symbol.strip %} - {% if check.errors or check.warnings %} - {{ check.symbol|safe }} - {% else %} - {{ check.symbol|safe }} - {% endif %} - {% endif %} - {% endfor %} @@ -192,6 +183,27 @@ + {% for check in doc.submission.latest_checks %} + {% if check.passed != None and check.symbol.strip %} + + + {{ check.checker|title }} + + + {% if check.errors or check.warnings %} + {{ check.symbol|safe }} + {% else %} + {{ check.symbol|safe }} + {% endif %} + + {{ check.errors }} errors, {{ check.warnings }} warnings. + + {% include "doc/yang-check-modal-overlay.html" %} + + + {% endif %} + {% endfor %} + {% if review_requests or can_request_review %} diff --git a/ietf/templates/doc/search/search_result_row.html b/ietf/templates/doc/search/search_result_row.html index 1ada48b26..f2adcb93f 100644 --- a/ietf/templates/doc/search/search_result_row.html +++ b/ietf/templates/doc/search/search_result_row.html @@ -56,13 +56,14 @@ {% if doc.latest_revision_date|timesince_days|new_enough:request and doc.get_state_slug != "rfc" %}{% endif %} - {% for check in doc.submission.checks.all %} + {% for check in doc.submission.latest_checks %} {% if check.passed != None and check.symbol.strip %} {% if check.errors or check.warnings %} - {{ check.symbol|safe }} + {{ check.symbol|safe }} {% else %} - {{ check.symbol|safe }} + {{ check.symbol|safe }} {% endif %} + {% include "doc/yang-check-modal-overlay.html" %} {% endif %} {% endfor %} diff --git a/ietf/templates/doc/yang-check-modal-overlay.html b/ietf/templates/doc/yang-check-modal-overlay.html new file mode 100644 index 000000000..10b3bfb36 --- /dev/null +++ b/ietf/templates/doc/yang-check-modal-overlay.html @@ -0,0 +1,17 @@ + {% load ietf_filters %}{% load origin %}{% origin %} + diff --git a/ietf/templates/submit/submission_status.html b/ietf/templates/submit/submission_status.html index 473829130..a4b9d5a8b 100644 --- a/ietf/templates/submit/submission_status.html +++ b/ietf/templates/submit/submission_status.html @@ -44,7 +44,7 @@ Your draft has NOT been verified to pass the submission checks. {% endif %}

- {% for check in submission.checks.all %} + {% for check in submission.latest_checks %} {% if check.errors %}

The {{check.checker}} returned {{ check.errors }} error{{ check.errors|pluralize }} @@ -58,7 +58,7 @@ {% endif %} {% endfor %} - {% for check in submission.checks.all %} + {% for check in submission.latest_checks %} {% if check.passed != None %} @@ -67,9 +67,9 @@