Clay,

This looks good. I think it is ready to push.

Please file the bugs/RFEs suggested.

Also have you addressed the comments from the code walk through we did 
of file: publish_manifest.py ?

Joe

Clay Baenziger wrote:
 > Hi Joe,
 >     Thank you for this code review. My comments are inline. Please
 > confirm early today if I've met your requirements, so I may soon push.
 > My latest webrev is at:
 > http://cr.opensolaris.org/~clayb/AI_server/webrev_final_rc0/.
 >
 >                                 Thank you,
 >                                 Clay
 >
 > On Fri, 10 Oct 2008, Joseph J VLcek wrote:
 >
 >> Clay
 >>
 >> I still have to review bin/publish_manifest.py which I will do over the
 >> next day or so.
 >>
 >> "Please" understand that I am not a Python expert. A lot of my input may
 >> not seem pertinent simply due to my lack of Python experience. If some
 >> of my comments seem inapplicable it may simply be due to my lack of
 >> Python experience. Please forgive that.
 >>
 >> Joseph
 >>
 >> +-=+-=+-=+-=+-=+-=+-=+-=
 >>
 >> General comment:
 >> ---------------
 >>
 >> I think more extensive error checking/trapping with try would help
 >> us diagnose potential issues.
 >>
 >> General comment:
 >> ----------------
 >>
 >> More comments would be valuable. High level description of what
 >> is doing what and how things interrelate.
 >>
 >> Clay, you and I had done a quick TOI over the phone and you had
 >> sent me an email describing what is what. That kind of stuff should
 >> be placed in the code as comments.
 >>
 >> Thing of the person who will have to diagnose this in 2 or 3 years.
 >> What would be valuable for them to know and add that as comments.
 >>
 >> General question:
 >> -----------------
 >>
 >> How are you testing this code?
 >
 > Right now the testing is by manual hand testing of the various code 
paths.
 >

OK.


 >> How are you testing the cherrypy in webserver.py?
 >> Is there a good way to validate this?
 >
 > I trust CherryPy to be stable, but it would be evident if it were
 > failing to serve pages, or generate reasonable errors/redirections, etc.
 >

OK

 >> bin/AI_database.py - 425 lines
 >> 
+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-= 

 >>
 >>
 >> Issue/question:
 >> ----------------
 >> 31 from threading import Thread
 >>
 >> Please confirm is it necessary to "from threading import Thread"
 >> since you imported threading on the line above.
 >
 > I believe doing this on two lines is as compact as I can. It allows me
 > to doing things without having to do threadding.thread.setDaemon... for
 > example. Otherwise, the initial import threading would be sufficient.
 >


Thanks for the explanation.

 >> Issue/question:
 >> ----------------
 >> 33 from pysqlite2 import dbapi2 as sqlite
 >>
 >> Would it makes sense to consider sqlite3?
 >>
 >> http://oss.itsystementwicklung.de/trac/pysqlite/wiki/PysqliteVersions
 >
 > We are using SQLite3, as that's what PySQLite2 interfaces with. PySQLite
 > 0.x/1.x were for SQLite2.
 >

Ah, OK.

 >> Issue:/Question:
 >> ----------------
 >>
 >> 46         self._requests = Queue.Queue()
 >> Is an infinite queue OK? Or should it have bounds?
 >
 > This is an excellent RFE to limit queue sizes then for the client
 > applications to check for queue full exceptions and shutdown assuming
 > the DB got wedged.
 >

Please file a bug/RFE.

 >> Issue:
 >> ------
 >>
 >>  48         self._runner.setDaemon(True)
 >>
 >> According to  docs.python.org setDaemon is: Old API for daemon.
 >
 > I can't find this same information. I see it looks current on
 > http://www.python.org/doc/2.5.2/lib/thread-objects.html (and we're only
 > shipping Python 2.4.4 anyways versus this doc for 2.5.2).
 >

I saw this in the 2.6 docs.
http://docs.python.org/library/threading.html?highlight=daemon#threading.Thread.setDaemon

So as you point out not applicable.

 >> (JJV: I don't know... I'm learning this on the fly ;)
 >>
 >> Issue:
 >> ------
 >>
 >> 56         Ensures resonable DB schema and columns or else raises a
 >> SystemExit
 >>
 >> Misspelling: resonable -> reasonable
 >
 > Darn missing a's
 >
 >> Issue:
 >> ------
 >>
 >> 92         self._commitable = commit
 >> 156         self._commitable = commit
 >> 169         if self._commitable == True:
 >>
 >> Misspelling: commitable -> committable
 >
 > Yea for private variables
 >
 >> Issue:
 >> ------
 >>
 >> 95         """ Use commit() to determine if the query need to be
 >> commited. """
 >> Misspelling: commited -> committed
 >
 > Thank you for the help spelling again...
 >
 >> Issue/Qustion:
 >> --------------
 >>
 >> 102     def response(self, resp = None):
 >> and
 >> 125     def finished(self, error = None):
 >>
 >> I don't understand the value of having response do both set or retrieve.
 >>
 >> Would it be clearer to a future maintainer to separate this
 >> into: setDBResponse and getDBResponse?
 >>
 >> Same comment applies to finished.
 >>
 >> Would it be clearer to a future maintainer to separate this
 >> into: setFinished and isFinished?
 >
 > To me it seems a good use of Python's exception handling to do this as
 > one. I'm not sure that it buys much one way or the other
 >

OK. Thanks for thinking about it.

 >> Issue:
 >> ------
 >>
 >> 108         # Note: _ans not defined set to None so that its
 >> non-existance is
 >
 > I'm going to claim I've once known how to spell...
 >

I used spell(1) ;)


 >> Misspelling: non-existance -> nonexistence
 >>
 >> Issue:/Question:
 >> ----------------
 >>
 >> 131             self._e.set()
 >>
 >> The tread is set here  on line 131. Where/how is it cleared? Does
 >> class DBrequest(object): need to provide a mechanism to clear it?
 >
 > No, once set that DBrequest is fulfilled and will someday be garbage
 > collected but not used again
 >

OK.


 >> Issue/Question:
 >> ---------------
 >>
 >> 139         self._e.wait()
 >>
 >> Shouldn't wait specifiy a timeout so it doesn't hang on stuck
 >> access and report if the timeout expired?
 >
 > I've set this to 15 seconds
 >

Great.


 >> Issue/Question:
 >> ---------------
 >>
 >> 241         yield(query.response()[0][0])
 >> 318             yield str(column)
 >> 323             else: yield str(column.replace('min',''))
 >> 341                 yield str(colName)
 >>
 >> Is your usage of yield correct? It doesn't seem to match my 
understanding
 >> from what I read at: www.python.org/doc
 >
 > I think we cleared up my usage of yield on the phone.
 >


Yes. Thank you!

 >> Issue:
 >> ------
 >>
 >> 246     Returns the manifest names and instane tuple as specified by a
 >> list of
 >>
 >> Misspelling: instane -> insane ;) (or maybe instance ;)
 >
 > That was me trying to reflect on the code's author and slipping a t in...

So we have that in common!  ;)


 >
 >> Issue/Question:
 >> ---------------
 >>
 >>  254         queryStr = queryStr[:-5]
 >>
 >> What if criteria is empty?
 >
 > Then one shouldn't be using "findManifestByCriteria". As the criteria
 > argument is required I'm not sure what I should test for. (That it's a
 >> 0 length, list?)
 >

That the kind of thing I have been thinking of.

 >> queryStr would end being: "SELECT name, instance FROM manifests W"
 >>
 >> Perhaps it would be good to validate the arguments passed to all
 >> of the functions defined in AI_database.py
 >
 > Due to how quickly this code was written I think an RFE for sanity
 > checks would be a good idea.
 >

Please file a bug/RFE.


 >> bin/listManifests.py - 174 lines
 >> 
+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-= 

 >>
 >>
 >> General comment:
 >> ---------------
 >>
 >> more comments. ;)
 >>
 >> Each function definition should have a comment block describing
 >> functionality, input and output, and errors...
 >
 > I've added the comment blocks with a bit more information, and I've
 > commented the code more thoroughly.
 >

Thanks.

 >> General comment:
 >> ---------------
 >>
 >> Issue/Question:
 >> ---------------
 >>
 >> 87     print headerL1
 >> 91     print headerL2
 >> 102             print response + ":"
 >> 105             print response
 >>
 >> i18n ? This code doesn't seem I18N-ed to me.
 >>
 >> shouldn't print _() be used?
 >
 > For strings which can be localized gettext is used i.e.
 > "len(_("Instance"))" etc, but for the criteria we should use what the
 > database uses and in particular header/response will contain
 > unpredictable output depending on the criteria being printed out (from
 > the database) so not the right place to gettext() to me.
 >


Ah, yes. Thanks.

 >> Also:
 >>
 >> Wouldn't it be easy for the alignment of the output
 >> to easily become skewed.
 >>
 >> To ensure output lines up would it be better to explore using
 >> something like this?:
 >>
 >> print '--->%5s<--- --->%5s<--- --->%5s<---'  % ("hi", "why", "when")
 >
 > That might be a good RFE to limit the lengths, right now I hand compute
 > lengths which works, but may result in very wide outputs; though yours
 > would give a more deterministic length it would potentially truncate
 > criteria.
 >

Hum. I think deterministic would be good. Perhaps an RFE for
evaluation/improvement?

 >> Issue/Question:
 >> ---------------
 >>
 >>  100         response = name
 >>
 >> Why is "response" needed?
 >
 > Thank you, it's not
 >


OK.

 >> Could this:
 >>  101         if maxLengths:
 >>  102             print response + ":"
 >>  103             printCriteria(DB, maxLengths, name)
 >>  104         else:
 >>  105             print response
 >>
 >> be changed to:
 >>  101         if maxLengths:
 >>  102             print name + ":"
 >>  103             printCriteria(DB, maxLengths, name)
 >>  104         else:
 >>  105             print name
 >>
 >> Issue:
 >> ------
 >>
 >> Looks like there is an old, commented out, block of code that should
 >> be removed.
 >>
 >>  107 #    AIdb.numManifests(self.AISQL.getQueue())
 >>  108 #max(len(list(AIdb.getCriteria(self.AISQL.getQueue(),
 >>  109 #  strip = False))), 1)
 >>  110 #(AIdb.numInstances(manifest, self.AISQL.getQueue()),
 >>  111 #(AIdb.getCriteria(self.AISQL.getQueue(), strip=False))), 1)
 >>
 >
 > Yes, those were turds. My apologies for not grabbing those.
 >

Great.

 >> bin/publish_manifest.py - 601 lines
 >> 
+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-= 

 >>
 >> Not yet fully reviewed
 >>
 >>  214             # painful check to determin if this is a range 
collision
 >> change determin to: DETErmine
 >
 > Fixed
 >
 >>  539             # manifestPath will be unset if we're not using a
 >> seperate file for
 >> Change seperate to: separate
 >
 > Fixed
 >
 >>  561 print >> sys.stderr, "Error:\tFile %s failed validataion:" % \
 >> change validataion: to  validation
 >
 > Fixed
 >
 >> bin/verifyXML.py - 53 lines
 >> 
+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-= 

 >>
 >>
 >> Issue:
 >> -----
 >>
 >> Missing CDDL header.
 >
 > Fixed
 >
 >> Question:
 >> ---------
 >>
 >> The 2 functions defined in verifyXML.py seem so similar it makes
 >> me wonder if they couldn't easily be combined.
 >>
 >> Could
 >>   10 def verifyDTDManifest(data, xml_dtd):
 >> and5A
 >>   35 def verifyRelaxNGManifest(schema_f, data):
 >> be "easily" combined into:
 >>   def verifyManifest(data, type):
 >
 > Potentially, except their exceptions and the like are subtly different.
 > A combined function could be made and receive a flag as to if the XML is
 > RelaxNG or DTD based I suppose. I'm not sure how much it buys though.
 >


OK. Fair enough. I just wanted to spur the thought.

 >> bin/webserver.py - 273 lines
 >> 
+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-= 

 >>
 >>
 >> Issue:
 >> ------
 >>
 >> 36 import cherrypy
 >>
 >> I think there may be something wrong with cherrypy. In playing with it
 >> I get a traceback. I am sure this is not your code but I just wanted
 >> you to beware of it during your testing.
 >>
 >> Or maybe I'm just doing something wrong. ?
 >
 > Without the stack trace I'm not sure.
 >

OK. I am sure I was doing something wrong.


 >> Issue/Personal Opinion/Nit:
 >> ---------------------------
 >>
 >> 78 <p>This server has available the following manifests,
 >>
 >> I think this may read better as:
 >>
 >>    This server has the following manifests available,
 >
 > It now reads as such
 >

Thanks

 >> Issue/Question:
 >> ---------------
 >>
 >> What would happen if any of the AIdb. methods failed? Is it possible
 >> to try/except any possible exception?
 >
 > They'll handle their own errors, or else fail only for that request of
 > the webserver. I've tried to keep the webserver from fatally failing
 > since it's not being run out of SMF at this time.
 >


OK.

 >> var/AI_service_1/ai_schema.rng - 281 lines
 >> 
+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-= 

 >>
 >>
 >> I did not do an extensive review of this xml.
 >>
 >> var/AI_service_1/criteria_schema.rng - 123 lines
 >> 
+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-= 

 >>
 >>
 >> I did not do an extensive review of this xml.
 >>
 >>
 >>
 >> Clay Baenziger wrote:
 >>> Hi all,
 >>>
 >>> I've updated the webrev, and sent out a new code tar-ball for folks to
 >>> work with.
 >>>
 >>> This update supports a "universal manifest" (based off the criteria
 >>> schema) which embeddes the A/I manifest and all SC manifests. This
 >>> universal manifest will be what is served out by the webserver for
 >>> parsing
 >>> by the A/I engine. An example manifest is included as [1] here.
 >>> Unfortunately, this is a bit cludgy as it's a RelaxNG manifest which
 >>> includes XML 1.0 DTD based XML (the SMF SC manifests).
 >>>
 >>> Also, due to this new universal manifest is an updated criteria schema
 >>> allowing one to specify the A/I and SMF manifests in the criteria and
 >>> updates to publish_manifest(1) to correctly verify everything 
handed in.
 >>>
 >>> Lastly, due to some bugs I've found the criteria collision logic got
 >>> a few
 >>> tweaks.
 >>>
 >>> Tar-ball:
 >>>     http://cr.opensolaris.org/~clayb/AI_server/AI_server.finalCut.1.tgz
 >>> Webrev (just diffs off previous):
 >>>     http://cr.opensolaris.org/~clayb/AI_server/webrev1/
 >>>
 >>>                                 Thank you,
 >>>                                 Clay
 >>>
 >>> [1]:
 >>> <ai_criteria_manifest>
 >>>     <ai_embedded_manifest>
 >>>         <ai_manifest name="default">
 >>>             <ai_target_device>
 >>>                 <target_device_name>c0t0d0</target_device_name>
 >>>                 <target_device_type>SCSI</target_device_type>
 >>>                 <target_device_vendor>hitachi</target_device_vendor>
 >>>                 <target_device_size>20480</target_device_size>
 >>>
 >>> 
<target_device_use_solaris_partition>true</target_device_use_solaris_partition> 

 >>>
 >>>
 >>> 
<target_device_overwrite_root_zfs_pool>true</target_device_overwrite_root_zfs_pool>
 

 >>>
 >>>             </ai_target_device>
 >>>             <ai_device_partitioning>
 >>>                 <partition_action>create</partition_action>
 >>>                 <partition_number>1</partition_number>
 >>>                 <partition_start_sector>200</partition_start_sector>
 >>>                 <partition_size>20480</partition_size>
 >>>                 <partition_type>99</partition_type>
 >>>             </ai_device_partitioning>
 >>>             <ai_device_vtoc_slices>
 >>>                 <slice_action>create</slice_action>
 >>>                 <slice_number>4</slice_number>
 >>>                 <slice_size>20480</slice_size>
 >>>             </ai_device_vtoc_slices>
 >>>             <ai_device_zfs_root_pool>
 >>>                 <enable_mirrored_root>true</enable_mirrored_root>
 >>>                 <zfs_options>xyz</zfs_options>
 >>>             </ai_device_zfs_root_pool>
 >>>             <ai_device_swap>
 >>>                 <ai_swap_size>2048</ai_swap_size>
 >>>             </ai_device_swap>
 >>>             <ai_pkg_repo_default_authority>
 >>>                 <main url="http://pkg.opensolaris.org";
 >>> authname="opensolaris.org"/>
 >>>                 <mirror url="" authname=""/>
 >>>             </ai_pkg_repo_default_authority>
 >>>             <ai_packages>
 >>>             </ai_packages>
 >>>         </ai_manifest>
 >>>     </ai_embedded_manifest>
 >>>     <sc_embedded_manifest name = "AI">
 >>>         <!-- <?xml version='1.0'?>
 >>> <!DOCTYPE service_bundle SYSTEM
 >>> "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
 >>> <service_bundle type="profile" name="name">
 >>>           <service name="ai_properties" version="1" type="service">
 >>>             <instance name="default" enabled="true">
 >>>               <property_group name="ai" type="application">
 >>>                 <propval name="username" type="astring" value="jack"/>
 >>>                 <propval name="password" type="astring" value="jack"/>
 >>>               </property_group>
 >>>             </instance>
 >>>           </service>
 >>>         </service_bundle>
 >>>      -->
 >>>     </sc_embedded_manifest>
 >>>     </ai_criteria_manifest>
 >>> _______________________________________________
 >>> caiman-discuss mailing list
 >>> caiman-discuss at opensolaris.org
 >>> http://mail.opensolaris.org/mailman/listinfo/caiman-discuss
 >>
 >> _______________________________________________
 >> caiman-discuss mailing list
 >> caiman-discuss at opensolaris.org
 >> http://mail.opensolaris.org/mailman/listinfo/caiman-discuss
 >>

Reply via email to