BIND 10 #547: Update of statistics daemon for HTTP/XML reporting: implement

BIND 10 Development do-not-reply at isc.org
Fri Apr 8 10:08:55 UTC 2011


#547: Update of statistics daemon for HTTP/XML reporting: implement
-------------------------------------+-------------------------------------
                 Reporter:           |                Owner:  naokikambe
  naokikambe                         |               Status:  reviewing
                     Type:           |            Milestone:
  enhancement                        |  Sprint-20110419
                 Priority:  major    |           Resolution:
                Component:           |            Sensitive:  0
  statistics                         |  Add Hours to Ticket:  0
                 Keywords:           |          Total Hours:  0
Estimated Number of Hours:  40.0     |
                Billable?:  1        |
                Internal?:  0        |
-------------------------------------+-------------------------------------
Changes (by vorner):

 * owner:  vorner => naokikambe


Comment:

 Hello

 Replying to [comment:9 naokikambe]:
 > Thank you very much for so deeply reviewing and for giving so many
 comments!  And I'm very sorry for confusing reviewers a lot. So I would
 like to suggest you this. I'll close this ticket and split it into
 following 4 tickets.
 > And I'll delete the existing branches on the repository (trac547,
 trac547-summarized) and recreate new branch and complete history by each
 ticket. How about that? Can it make sense for you? I'll do that if it is
 okay for you. Please let me know.

 No need to. I already went trough the code, so splitting it up now is no
 longer needed, it would only waste your time.

 > >  * Every process/module has a separate directory in the bin/. Would
 the xml stats server deserve it's own directory as well?
 > Because I think the stats daemon and the HTTP server are grouped in the
 same category according to the picture in [[DesignDiagrams]], and they
 almost share the same libraries and the same stub codes, so I put them
 into the same directory. If it is incorrect, I will separate the
 directory.

 Well, with these things, there's no correct or incorrect, it's just how we
 feel about it. It surprised me, so I asked ‒ if it is on purpose, then
 it's OK.

 > >  * Do we expect users to want to know the internal how it works? Like
 how it is started by boss, etc. Maybe the man page could be less detailed
 in that sense, and just say that it presents the statistics from stats
 module trough XML/HTTP?
 > Yes, the users needs to know details but I don't exactly know what we
 should add in the man page. What about this? Please show me more
 suggestion if you have.

 Why do they need to know?

 I mean, if I was a user, I would care about if it runs or not and how to
 ask it for my web page with statistics. Where or how it gets the data,
 it's none of my problems. So, why would any other user want to care what
 is the internal format that goes from one place in the BIND10 system to
 another? I fear that the man page is too long and confusing users about
 too much detail.

 This information is, of course, valuable as developer documentation. But
 man page is for the end user.

 > >  * The man page talks about parameters when it talks on which
 addresses it listens. IMO that's little bit misleading, user might want to
 put it into the command line after reading it. Maybe call them options or
 configuration points so it is clear they are not command line arguments?
 > OK. What about adding the following description into OPTIONS section in
 the man page?
 > {{{
 > The verbose mode is only supported in the command-line option of
 > b10-stats-httpd. You can set the parameters like addresses and ports in
 HTTP
 > into the specification file (stats-httpd.spec). Please see
 "CONFIGURATION AND
 > COMMANDS" section below for details.
 > }}}

 But that's not true. No user edits the .spec file, it's configured trough
 bind control.

 > >  * The {{{BASE_LOCATION = BASE_LOCATION.replace("${datarootdir}",
 DATAROOTDIR).replace("${prefix}", PREFIX)}}} is little bit suspicious. Can
 the `BASE_LOCATION` really contain strings like '${prefix}'? Where do they
 come from?
 > Yes. In my environment, BASE_LOCATION is "${datarootdir}/bind10-devel",
 DATAROOTDIR is "${prefix}/share" and PREFIX is "/home/kambe/bind10", then
 ${datarootdir} in BASE_LOCATION is replaced with DATAROOTDIR and ${prefix}
 in DATAROOTDIR is replaced with "/home/kambe/bind10". That is,
 BASE_LOCATION contains ${datarootdir} and ${datarootdir} contains
 ${prefix}. Is that correct?

 Hmm, I see, it does so even here. OK, we have a strange build system.

 > >  * You seem to use {{{dict(key=value)}}} consistently trough the code.
 Is there any special reason about that? I think the use of
 {{{{'key':value}}}} is more common in the python world.
 > I don't have so special reason. The way of dict method is more intuitive
 for me because we don't need to bracket the key name with quotations. If
 it is the bad manner, I will correct through the all codes.

 I don't know, it probably isn't bad. Again, I was just surprised to see
 it, because I wouldn't write it that way myself, but it's OK if you like
 it this way more.

 > >  * Why is this limitation in place?:
 > >    {{{#!python
 > >    # The size of template file should be under 100k. TODO: should be
 > >    # considered later.
 > >    MAX_SIZE_OF_TEMPLATE = 102400
 > >    }}}
 > >    Allowing arbitrary size should be no problem, since the file is
 local one and the only one able to change it is the administrator. Why
 stop him? Reading the whole file by single call without the limitation
 should be no problem in python (the file object should have something like
 {{{readAll()}}} or similar).
 > I don't have so specific reason for it. But I cannot expect the
 situation which so huge file is read-in. For the unexpected situation, I
 set such limitation. In almost cases an administrator dosen't need to
 change this limitation. Do we need to remove it?

 Well, the limitation probably will not be hit, but there's no technical
 reason for this exact number. The code and hardware can surely handle much
 more. So it only makes the code little bit more complicated and there's no
 benefit for the user (it can, in theory, make him unhappy actually), so I
 don't see much reason to have the limitation there.

 > >  * If you want to raise the original exception:
 > >    {{{#!python
 > >    except select.error as err:
 > >        if err.args[0] == errno.EINTR:
 > >        (rfd, wfd, xfd) = ([], [], [])
 > >    else:
 > >        raise select.error(err)
 > >    }}}
 > >    You might want to use just raise without any parameters. That
 raises the exact instance of exception as it caught in the except,
 preserving all other information (like errno, which your way doesn't) and
 the backtrace is more helpful (it doesn't show the note about exception
 being raised while handling another exception).
 > OK. I will replace with another exception instead of the original
 exception(select.error).

 I'm not sure if we understand each other here. Was the original intention
 to catch the sellect.error only in the case it is EINTR, but let it fall
 when it's different errno? If so, then you don't need to replace any
 exception, the correct code would be:
 {{{#!python
     except select.error as err:
         if err.args[0] == errno.EINTR:
         (rfd, wfd, xfd) = ([], [], [])
     else:
         raise
 }}}

 Just `raise`, without any parameter. It will just re-raise the original,
 unmodified, exception.

 > >  * You use select around the httpd object and when a socket is
 readable, you call it. But, does it use non-blocking sockets? If there's a
 client that sends `GET url` and gets stuck before sending the rest of
 headers, will our program get stuck as well, trying to read until the end
 of the headers?
 > The HTTP server can handle only one request at a time. If the server is
 trying to read, it will be timed out and the client will be reset later. I
 think this interface is not so busy like a DNS server, because I think
 this feature is for administration use only. Is that correct?

 If you are aware of it and think it's not so big problem to complicate the
 code, then OK. But it would deserve a FIXME comment in the code at last,
 to note that the issue is known.

 > >  * You seem to use regexps in the tests when you really think
 substrings:
 > >  {{{#!python
 > >  self.assertRegexpMatches(handler.response.body,
 stats_httpd.XSD_NAMESPACE)
 > >  self.assertRegexpMatches(handler.response.body,
 stats_httpd.XSD_URL_PATH)
 > >  }}}
 > >  The paths aren't valid regexps, they are just string. Furthermore, if
 they contain regexp metacharacters, the test would break.
 > That's right. I'll use find method in string object for it. What about
 this?
 > {{{#!python
 > self.assertTrue(handler.response.body.find(stats_httpd.XSD_NAMESPACE)>0)
 > self.assertTrue(handler.response.body.find(stats_httpd.XSD_URL_PATH)>0)
 > }}}

 Yes, that seems better.

 > No, but I'll remove these assertions as I mentioned above.
 > >  * In `test_config`, you call it with various configs and check that
 it doesn't crash and it returns the correct answer. But shouldn't there be
 a check it did anything „internal“, like it sets any value inside?
 > OK. I will add tests to check internal values. What about this?
 > {{{#!python
 >   self.assertEqual(
 >       self.stats_httpd.config_handler(
 >                   dict(listen_on=[dict(address="::2",port=8000)])),
 >       isc.config.ccsession.create_answer(0))
 >   self.assertTrue(self.stats_httpd.config in "listen_on")
 >   self.assertTrue(self.stats_httpd.config["listen_on"] in "address")
 >   self.assertTrue(self.stats_httpd.config["listen_on"] in "port")
 >   self.assertTrue(self.stats_httpd.config["listen_on"]["address"] ==
 "::2")
 >   self.assertTrue(self.stats_httpd.config["listen_on"]["port"] == 8000)
 > }}}

 I don't really remember the exact internal layout, but yes, I mean
 something like this.

 > >  * What is tested in `test_no_buildpath`? How can the test fail, if
 there's no self.assert* call? The same with `test_osenv` (probably older
 code, but I saw it in the diff as well).
 > There aren't so specific reason. I intended to let it go through the
 following code in stats_http.py. It will fail if it has errors in syntax.
 Do we need to remove `test_no_buildpath`?

 No need to remove it, but a comment about it would help, it looks like
 part of the code might be missing or something.

 > >  * The get_value seems suspicious. It returns either some spec file
 default value or default value of a type. But is it able to return any
 actual configured value? Or why isn't it needed?
 > No, it is not able to return any actual value. The purpose of this
 get_value is only for getting the default value in the spec file, because
 this method is called only when stats_http is loading the spec file at
 first.  But the behavior of this method is unlike to the behavior of the
 original method in the original class. So what about switching the name of
 it to `get_default_value`?

 OK, seems reasonable.

 > >  * The mock select has some hidden state which can make it quite
 surprising, if someone tried to reuse it in some other tests or wrote
 another test here that used it. Shouldn't the variable be exported and
 explicitly set in the test using it?
 > I think these mock classes (select.py, socket.py, etc) are not reusable
 for other tests, the codes should be more coded if they need to be, and I
 think these tasks are out of scope of this ticket. Should they be
 reusable?

 They don't really need to be reusable, but again, a comment with warning
 about it might prevent someone from trying to reuse it and failing.


 OK to anything I left out from direct answer.

 Thanks

-- 
Ticket URL: <http://bind10.isc.org/ticket/547#comment:10>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list