On 3/7/11 10:17 AM, Keith Mitchell wrote:
Hi Alok,

As promised, here's my review of section (a), as well as one comment about the shadow_xxx files

- Keith

General:

Shadow* files comment:
The files are placed in:
.../vendor-packages/solaris_install/target/shadow/shadow_<something>.py

I think that should be .../vendor-packages/solaris_install/target/shadow/<something>.py

The extra "shadow" component is redundant, especially when importing.

Fixed.  The leading "shadow_" has been removed from all the shadow files.

Nit: Are we using triple single-quotes or triple double-quotes for docstrings? I think most of our code leans toward the former - consistency would be nice (though I don't think we've had a 'formal' decision)

I don't honestly know. I tend to use double-quotes for docstrings. I'll talk with Alok and try to standardize.

td.py:
Is there any reason not to name this something less terse? Perhaps "discovery.py" (so the import path becomes "solaris_install.target.discovery").

Fixed. td.py has been renamed discovery.py and ti.py has been renamed instantiation.py


84: Since TD is one of the longer running checkpoints, I'm hoping this method will get fleshed out.

Alok and I are at a loss on this one. Setting the progress_estimate varies wildly due to the complexity and architecture of the system being discovered. If you've got any ideas on this one, we're both all ears.

99-100: Could be combined with the block that starts at 118

Fixed.


118: May be worth moving this whole block to a separate function. May not be. Up to you.

Moving the drive_media parsing out of this section doesn't really buy us anything.


202-216: You have no idea how happy this makes me.

We aim to please.   :D


251: search_name appears to be unused

Fixed.  Added a check for it.


267: Popen call looks out of date - should be Popen.check_call()
I see a few other places in need of updating as well. (Apologies for changing this syntax out from under you guys, but I promise it was for the best, long-term!)

*all* of the Popen calls have been modernized with the iterations and bug fixes you and I have done.


270: Could use "p.stdout.splitlines()"
271-272: I'm surprised this is necessary, though hopefully it doesn't come up enough to be an issue.

Fixed to use splitlines(). One day I'll remember that function. 271-272 is no longer needed once splitlines is used.


276: Change to:
self.logger.debug("Populating DOC for zpool: %s", zpool_name) # Comma, not %

Done.


291: You could (outside the 'for' loop) run:
# zpool list -H -o name,bootfs

And then store the output for use in when looking at each zpool. Or you can give it a pool name:
# zpool list -H -o bootfs <pool>

And then you just have the value - that route might be more stable.

Fixed with option #2.


300: Can you clarify what this value is used for? I'm concerned that, since data pools can set this to arbitrary values, if we're using it as anything more than information for the user we could end up with problems.

Yes, users can set this to whatever they'd like. We're simply querrying the system for whatever the mountpoint of the pool is and storing for information purposes. I do not believe anything is currently using the mountpoint of the zpool from the Target.DISCOVERED tre.


308: At this point in the code, we start getting pretty deep indentation levels. Please break some of this out into separate function calls for readability.

Fixed.


318: some_str.rpartition() will always return a tuple of length 3 with the leading "/dev/dsk" removed (note that's Rpartition, not partition), so 317 isn't needed. This is particularly valuable given that line 321 assumes that "entry" has been set to something...

Fixed.  Didn't know about rpartition().


321, 328: You should probably use rpartition for these (you likely want to ensure that we're partitioning this string from the right, not the left).

Fixed.


337: It's probably worth adding a "break" after you've finished processing the match

Fixed.


376: Please add a comment here explaining why we want to skip the "root" vdev_type.

Fixed.


384-385: The first dataset is the root dataset, not the pool. It just happens to require the same name as the pool, but it can be mounted, used and have properties set just like any other dataset, as far as I understand. Should we really skip it? If it does need to be skipped, should you use the "-s" (sort) flag to the zfs list call to ensure that the sorting is exactly how we want it?

I went ahead an removed the slice so we're walking the entire the pool.


397-398: Comment could be clearer: Explain that the output from zfs list returns values like "37G" and "3.2M" and that Size() expects "37GB" and "3.2MB"

Fixed.


426: Nit: The first portion of the comparison ("if zpool_name") is redundant. The second comparison will end up failing properly whether zpool_name is None, an empty string, or a different pool name.

Fixed.


455: Is setup_iscsi() only ever going to be needed by td.py? Or would it be worth having in a separate location?

520: If TD is run twice (or two separate TD checkpoints are run), will setup_iscsi() behave appropriately?

Alok already answered this.


550: Is there any concern that, e.g., self.search_type might be "some_random_string"?

Maybe, but I'm not too worried about it. discovery runs fairly quickly (even on a t2000 with 3150 attached to it), so if the user searches for something not "disk" or "zpool", it'll just discover the entire system. We can look into tightening this if needed.


test_td.py:

test_td.py was mostly incomplete when Alok spun the webrev. It's been updated to use solaris_install.Popen and cleaned up a little bit.


33: Nit: Import from solaris_install.

Fixed.


38-39: "from x import *" is generally frowned upon. Preferable to use, for example, import solaris_install.target.logical as logical; logical.my_func().

Fixed. For the most part I totally agree. With test code though, I don't really care so much.



151-169: Enclose in a "def main():", and then add:
if __name__ == '__main__':
    main()

Done.


vdevs.py:

General: What changes in the ZFS library do we need to be aware of to prevent incompatibility in this module?

We're not accessing *any* libzfs structures with this code so the only thing we need to watch for is any changes to the global open/close of a libzfs handle, the open/close of a zpool_handle and modification of a 3 line function (zpool_get_config()) which returns an nvlist.


126: retrival -> retrieval

I spel gud.


141: I'm confused by this comment. The iteration is over nvlists, not the pairs within those lists, right? If the nvlist names are non-unique, doesn't the assignment on 159 override any previous assignments from nvlists with the same name?

This function has been completely removed. There's no need to search for exported zpools because libdiskmgt already does that for us in discovery.py


size.py:

General: The "if/elif/elif/..." blocks could be condensed with a dictionary that maps unit strings to unit values. e.g.:

units = { "kb" : 2 ** 10,
          2 ** 10 : "kb",
          "mb" : 2 ** 20,
          2 ** 20 : "mb"}
# Mappings in both directions was intentional
self.byte_value = self.value * units[self.suffix.lower()]

Fixed.


Sectors would still need to be handled specially though (since you'd want probably want the units dict to be at the class level, and sectors is an instance variable)

sectors and bytes are their own special look up.


60, 63: I don't see much value in storing the value/suffix parts as attributes - would recommend using local vars and ensuring everything uses self.byte_value.

Done.  They're locals now.


65: Yes, we care. Would rather raise a ValueError here than have an odd AttributeError on line 69 when we try to access self.suffix.

Done.


86-93: Should this really be settable? (If so, then it doesn't need to be a property yet)

Removed the get/set entirely. I thought we were going to need something like this, but a comment made during code walkthrough of discovery.py (set the blocksize directly from libdiskmgt when Size() objects are created), made this unnecessary.


117: __repr__ should return a string that could be pasted into a Python interpreter to recreate the object, e.g.:
>>> repr(my_size)
Size("456b")

For precision, it should probably also always use the "bytes" value (which shouldn't be cast to a float...)

Done.


However, the current __repr__ function would make a fine __str__ function (although both functions should use units consistent with what it accepts, i.e., "TB" instead of "T")

Done.


The get() method should be case-insensitive.

Done.


Lots of room for enhancements to this class: subclass long instead of object, include methods for __add__, __sub__, etc. (I'm sure none of those are strictly necessary, but at the time I'm writing this, I'm just kicking things around on a Friday afternoon)

Once I find that giant bucket of time, I'll look into this. Since we're not currently performing basic math operations on Size() objects, there's really no need for it. It's a good idea though and something we should consider.


test_zpool_vdevs.py:

27, 46: :comments:

Fixed.


setUp/tearDown: See usr/src/lib/install_engine/test/engine_test_utils.py for helper functions for tests that need to create/destroy/reset the InstallEngine singleton. (Drew may have already addressed this)

Fixed.


122, 123: Use self.assertEquals(). Also, a subtle "nit" - reverse the order. (When the test fails, it's more convenient to see "Test failure: <vdev_map_root object> != <f1 object>")
This comment also applies to 165-166, 217-218, and 224-229

Fixed.


Thank you so very much, Keith!

-Drew
_______________________________________________
caiman-discuss mailing list
[email protected]
http://mail.opensolaris.org/mailman/listinfo/caiman-discuss

Reply via email to