Closed Bug 530975 Opened 15 years ago Closed 12 years ago

Some automated sanity checks: is subdomain, connection possible

Categories

(Webtools :: ISPDB Server, defect, P3)

defect

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: bwinton, Assigned: bwinton)

References

Details

Attachments

(1 file, 2 obsolete files)

The checks to run for this first cut are: a) domains are available. b) we can establish a cxn with the config settings. c) domains are sub-domains of the email domain. Note: The reviewer can ignore the warnings, if there are any, at their discretion. (i.e. we don't have to worry about GoogleApps domains not being sub-domains of googlemail.com.)
From DavidA over irc: 4) do a dns mx record lookup.
Apparently we need PyDNS to do DNS lookups in Python, so I added it as a requirement. I wasn't entirely sure what checks I should do with the MX record, David, so if you wanted to elaborate on those a little, that would be cool. Thanks, Blake.
Attachment #414877 - Flags: review?(david.ascher)
Whiteboard: [patch up, needs r davida]
So, I was running the tests for this patch, and they started giving me more errors than they used to, because something changed in one of the hosts I was using. So I changed the tests to use mock objects for the DNS and socket calls, so that we can test those things even when we're disconnnected. And then I added some client-side error handling, for the cases where the server doesn't respond for some reason. Thanks, Blake.
Attachment #414877 - Attachment is obsolete: true
Attachment #416443 - Flags: review?(david.ascher)
Attachment #414877 - Flags: review?(david.ascher)
Attachment #416443 - Flags: review?(david.ascher) → review?(jbalogh)
Whiteboard: [patch up, needs r davida] → [patch up, needs r jbalogh]
Comment on attachment 416443 [details] [diff] [review] A better patch, which checks for errors, and doesn't hit the network. I can't argue with 200 lines of tests. > - pip install django python-openid django-openid-auth django-nose lxml > + pip install django python-openid django-openid-auth django-nose lxml PyDNS mox pip install -r requirements.txt? > +def sanity(request, id): > + config = Config.objects.filter(id=int(id))[0] No get_object_or_404? Are you using filter()[0] instead of get() for a reason? > + errors = [] > + warnings = [] > + for domain in Domain.objects.filter(config=config): > + host = domain.name > + inHost = config.incoming_hostname What is this camelCase thing you're doing here? > + outHost = config.outgoing_hostname > + > + # Check the DNS MX and SRV records. > + mxs = DNS.mxlookup(host.encode("utf-8")) > + if len(mxs) < 1: > + errors.append(u"Couldn’t find MX record for %s." % (host,)) > + > + result = check_srv_record(host, config.incoming_type, > + inHost, config.incoming_port) > + errors.extend(result["errors"]) > + warnings.extend(result["warnings"]) This repeated extending makes me slightly uncomfortable, but I don't have a great suggestion for a better way. My first idea is something like def tally(result): errors.extend(result) warnings.extend(result) as an inner function. > +# Utility methods > + > +def check_connection(host, port): > + """Test to see that we can find and make a connection to the host and > + port passed in.""" > + > + errors = [] > + warnings = [] > + > + # Make sure we can get an address for the host. > + addrinfo = None > + try: > + addrinfo = socket.getaddrinfo(host, None) > + except socket.gaierror, e: > + errors.append(u"Couldn’t get address for %s." % (host,)) > + > + # See if we can connect to the requested port. > + if addrinfo and len(addrinfo) > 0: Isn't the second check redundant since "" evaluates to False? > +def check_srv_record(domain, service, host, port): > + """Check that, if there are SRV records for this service and this > + domain, the passed-in host and port are somewhere in those SRV > + records.""" > + > + errors = [] > + warnings = [] > + > + dnsReq = u"_%s._tcp.%s" % (service, domain) > + #dnsReq = u"_%s._tcp.%s" % (service, u"fudo.org") Do you still need this line? > + dnsReq = dnsReq.encode("utf-8") > + a = DNS.Request(dnsReq, qtype = "srv").req().answers > + srv = [x["data"] for x in a if x["typename"] == "SRV"] > + srv.sort() > + if len(srv) > 0: > + valid = False > + records = [] > + for record in srv: > + records.append("(%s:%d)" % (record[3], record[2])) Does this need to be a u"" string? > + if port == record[2] and host == record[3]: > + valid = True > + break > + if not valid: > + errors.append(u"Couldn’t find settings (%s:%d) in %s SRV " > + u"records [%s] for %s." % ( > + host, port, service, ", ".join(records), domain)) Can you use a for-else instead of managing the valid boolean? If you break out of the for loop, the else won't run, so you could append an error inside the else block. > diff --git a/templates/config/details.html b/templates/config/details.html > + $("#sanity_link").click(function() { If your function takes the event argument and runs ``event.preventDefault()``, the URL won't get the # appended. > + if ($(this).text() == "Running sanity checks.") > + return; > + $(this).html("Running sanity checks."); > + self = $(this); > + $.getJSON("{% url ispdb_sanity id=config.id %}", null, > + function(data) { > + self.html("Re-run sanity checks."); > + results = ""; > + $.each(data["errors"], > + function(index, error) { > + results += '<span class="error">' + error + "</span><br/>"; += has poor performance in js, similar to python. Of course, you have < 10 strings here, so no one's going to notice. > diff --git a/tests/test_sanity.py b/tests/test_sanity.py The mocking here is pretty cool. Verbose, but cool. I wish it wasn't copied from a jaVaLibRary. > + def test_no_srv_errors(self): Does this test differ significantly from test_no_errors?
Attachment #416443 - Flags: review?(jbalogh) → review+
Blocks: 543614
I'll narrow the subject to not overlap with other sanity checks and focus on the patch here. Bug 543614 is the tracker for sanity checks.
Summary: Allow reviewers to run automated sanity checks. → Some automated sanity checks: is subdomain, connection possible
Whiteboard: [patch up, needs r jbalogh] → [patch up, needs fixes]
(In reply to comment #4) > I can't argue with 200 lines of tests. I think you could. ;) > > - pip install django python-openid django-openid-auth django-nose lxml > > + pip install django python-openid django-openid-auth django-nose lxml PyDNS mox > pip install -r requirements.txt? Changed. > > + config = Config.objects.filter(id=int(id))[0] > No get_object_or_404? Are you using filter()[0] instead of get() for a reason? Fixed. > > + errors = [] > > + warnings = [] > > + for domain in Domain.objects.filter(config=config): > > + host = domain.name > > + inHost = config.incoming_hostname > What is this camelCase thing you're doing here? Sorry, java habits. Fixed. > > + result = check_srv_record(host, config.incoming_type, > > + inHost, config.incoming_port) > > + errors.extend(result["errors"]) > > + warnings.extend(result["warnings"]) > This repeated extending makes me slightly uncomfortable, but I don't have a > great suggestion for a better way. My first idea is something like > def tally(result): > errors.extend(result) > warnings.extend(result) > as an inner function. That's not bad… Fixed. > > + if addrinfo and len(addrinfo) > 0: > Isn't the second check redundant since "" evaluates to False? Fixed. > > + dnsReq = u"_%s._tcp.%s" % (service, domain) > > + #dnsReq = u"_%s._tcp.%s" % (service, u"fudo.org") > Do you still need this line? Nope. Fixed. > > + for record in srv: > > + records.append("(%s:%d)" % (record[3], record[2])) > Does this need to be a u"" string? Apparently not, but fixed anyways. :) > > + if port == record[2] and host == record[3]: > > + valid = True > > + break > > + if not valid: > > + errors.append(u"Couldn’t find settings (%s:%d) in %s SRV " > > + u"records [%s] for %s." % ( > > + host, port, service, ", ".join(records), domain)) > Can you use a for-else instead of managing the valid boolean? If you break out > of the for loop, the else won't run, so you could append an error inside the > else block. Yeah, I never remember about the for-else. It just seems slightly odd to me. Anyways, fixed. > > diff --git a/templates/config/details.html b/templates/config/details.html > > + $("#sanity_link").click(function() { > If your function takes the event argument and runs ``event.preventDefault()``, > the URL won't get the # appended. Fixed. > > + $.each(data["errors"], > > + function(index, error) { > > + results += '<span class="error">' + error + "</span><br/>"; > += has poor performance in js, similar to python. Of course, you have < 10 > strings here, so no one's going to notice. What do you think about: + if (data["errors"].length) { + results.push('<span class="error">' + + data["errors"].join('</span><br/><span class="error">') + + "</span><br/>"); + } :) > > diff --git a/tests/test_sanity.py b/tests/test_sanity.py > The mocking here is pretty cool. Verbose, but cool. I wish it wasn't copied > from a jaVaLibRary. Yeah. I don't mind so much, since mocking seems kinda Java-y to me, but yeah. > > + def test_no_srv_errors(self): > Does this test differ significantly from test_no_errors? Yeah, in this test, the domain has SRV records, which test_no_errors doesn't. Thanks, Blake.
Attachment #416443 - Attachment is obsolete: true
Whiteboard: [patch up, needs fixes]
Comment on attachment 429208 [details] [diff] [review] The previous patch, with jbalogh's changes. Discussed a couple things over IRC, looks good to me.
Attachment #429208 - Flags: review+
Comment on attachment 429208 [details] [diff] [review] The previous patch, with jbalogh's changes. And over to Gozer for the second review.
Attachment #429208 - Flags: review?(gozer)
(In reply to comment #1) > From DavidA over irc: > 4) do a dns mx record lookup. Not sure what good dns MX records will do you. An ISP can very well have completely different smtp servers for who wants to send e-mail *in* and those who are sending e-mail *out*.
However, if flintstones.com points to mx.dreamhost.com, then pop.dreamhost.com is probably OK as mail server for flintstones.com. However, pop.badguy.com is not. In other words, a passing MX test would accept some otherwise rejected configs, it would not reject otherwise accepted configs And as bwinton said: > The reviewer can ignore the warnings, if there are any, at their discretion.
(In reply to comment #10) > However, if flintstones.com points to mx.dreamhost.com, then pop.dreamhost.com > is probably OK as mail server for flintstones.com. However, pop.badguy.com is > not. > In other words, a passing MX test would accept some otherwise rejected configs, > it would not reject otherwise accepted configs Works for me.
Attachment #429208 - Flags: review?(gozer) → review+
Status: ASSIGNED → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Component: ispdb → ISPDB Server
Product: Mozilla Messaging → Webtools
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: