Hi Jean,
        Thank you for the clarification on the phone yesterday. I think we 
came to a consensus on all the various points of the code review. All 
changes we discussed were made.
        I think the biggest issues comes to removing files in the 
individual functions which find the files versus removing them all at one 
in a list (as is done).
Pros to removing them in each function:
*Files are removed immediately
*No return from the function has to be dealt with
  (eases debugging to some)

Pros to removing them in a list:
*Feedback to user is separated into two stages:
  Finding files and Removing files
*List of files to delete provides a clean way to debug ordering of file
  removal and seeing all files which are to be removed (akin to a dry-run)

I think we came to an agreement that both approaches are closely equal in 
usefulness and largely a stylistic difference.
                                                Thank you,
                                                Clay

On Wed, 30 Sep 2009, jeanm wrote:

> Clay Baenziger wrote:
>> Hi Jean,
>>     Thank you for the review! My comments are in-line.
>>                             Thank you,
>>                             Clay
>> 
>> On Mon, 28 Sep 2009, jeanm wrote:
>> 
>>> 
>>> I found time to do this when I thought I wouldn't. Using the following 
>>> webrev:
>>> http://cr.opensolaris.org/~clayb/delete_service/webrev2. I haven't checked 
>>> to see
>>> if others have commented on these items. Pardon me if they have.
>>> 
>>> Also, if you just want to discuss this in the office instead of an email 
>>> thread I'm fine with that.
>>> Sometimes it's easier.
>>> 
>>> Jean
>>> 
>>> 
>>> usr/src/cmd/installadm/delete_client.py.html
>>> 
>>> General:
>>> This is the delete-client file but there are references to delete-service 
>>> throughout. That causes me to be confused
>>> since I know they are different and have different functionality. Is this 
>>> a cut and paste issue? Or similar functionality
>>> between the two?
>> 
>> I only see delete_service mentioned when the delete_service module is 
>> called for various functions. This is a shared code approach as 
>> delete_client is a subset of the functionality exported by delete_service.
> And line 26 which is a general overview of the file. The comment you just 
> made might be nice somewhere since it does explain why
> delete-service is in the delete-client code.
>
>> 
>>> line 78-81: Since you're hardcoding the first %s to installadm why bother 
>>> with the %s in the first place? I actually
>>> don't think you even need the 2nd %s. This is run in delete-client. If 
>>> prog is something other than that, this message
>>> would be extremely confusing.
>> 
>> This is just to make it more modular as these commands will hopefully all 
>> collapse down to installadm as soon as create-service becomes Python. Until 
>> then this just prevents hard coding bits. Yes, prog should be delete-client 
>> actually to mimick how delete-client reports errors today.
> This makes sense then. If eventually it will be just one function call with 
> parameters then I'm fine with leaving it in for now.
>> 
>> This is achieved using the /usr/lib/installadm/delete-client symlink which 
>> points to /usr/lib/installadm/delete_client.py. The reason for printing the 
>> program name is just since it has these two execution possibilities. The 
>> reason for having the delete_client is so that the module is importable by 
>> Python (modules needing to be [a-zA-Z0-9_].py.
>> 
>>> line 43: Wouldn't it be more helpful to say a tuple representing....
>> 
>> You want me to be helpful now, that's just too much! Thanks for the catch, 
>> I've changed it to:
>>
>>     Returns: A tuple of a class object representing client to delete
>>              and an options object
> Thanks.
>> 
>>> line 62: Why did you hang this off of options?
>> 
>> This is an option the functions expect to be set. This comes from 
>> delete_service being able to delete an image, so as the comment says:
>> "we do not deleteImage for a delete-client so set it False"
> So you're saying that the delete-service functionality might need this, 
> correct? In which case I'm fine with it.
>> 
>> Further, looking at line 89 (the only place options is really used) we see 
>> that indeed deleteImage is used there, and we can correlate from line 60 
>> (the comment) image deletion is hard coded off.
> But if this was really the only reason we would just return a boolean. If 
> however as stated above, delete-service would use it then you have it right.
>> 
>> Note: I swapped line 60 (the comment for line 62) and line 61. I 
>> accidentally got them out of order.
>> 
>>> usr/src/cmd/installadm/delete_service.py.html
>>> 
>>> lines 837-840 : same comment as lines 78-81 in delete-client.py
>> 
>> Same reasons as with delete_client
>> 
>>> line 64: this really returns a tuple. Same comment as line 62 of 
>>> delete_client.py
>> 
>> Same fix as delete_client
>> 
>>> General comment: I find that putting comments into the middle of a group 
>>> of
>>>   code that is line continued makes the code difficult to read.
>>> Ex.
>>> 
>>> 377             files = [image_path,
>>> 378                 # must strip the leading path separator from 
>>> image_path as
>>> 379                 # os.join won't concatenate two absolute paths
>>> 380                 os.path.join('/var/ai/image-server/images/',
>>> 381                 image_path.lstrip(os.sep))]
>> 
>> Hrm, I know we talked about this. I find this breaks up the logic so I can 
>> see the intention behind it. I see the list files consists of only two 
>> elements:
>> image_path
>> os.path.join('var/ai/image-server/images/',image_path.strip(os.sep))
>> 
>> Further, following better formatting allowed by PEP8 I think this should be 
>> formatted as follows which more clearly shows that it's two separate 
>> elements in the list:
>> files = [image_path,
>>          # must strip the leading path separator from image_path as
>>          # os.join won't concatenate two absolute paths
>>          os.path.join('/var/ai/image-server/images/',
>>                       image_path.lstrip(os.sep))]
>> 
>> Also, do you use an editor or viewer which does syntax highlighting? I just 
>> realized since my vi is configured for syntax highlighting, comments are 
>> lighter than code, so I don't even visually notice them -- unless I 
>> question what the code's doing and this lessens the distraction immensely.
> No and the code review utility didn't either. In this particular case I'm 
> fine with leaving this. Other cases it becomes much more distracting. Usually 
> where you have multi line list comprehensions.
>> 
>>> Another general comment. There are lots of hard coded paths. This makes 
>>> changes
>>> to these paths in the future very difficult to maintain in the code.
>> 
>> Yes, I'm not fond of them. This is tracked in 4402 (Pull fixed strings in 
>> A/I server python code out to a separate module) which is a holder for 
>> finding an elegant way to pull out these various paths. It seems we should 
>> have a module we import for various install components and their paths but 
>> perhaps there's better or different -- it's too big to design that here 
>> though.
> Great. Thanks.
>> 
>>> line 196:
>>> It would be cleaner to just do
>>> if not return_val
>>>   return 1
>>> return return_val
>>> 
>>> But you should be sure that return_val is None at the top. Certainly is 
>>> easier to read and cleaner.
>> 
>> This was accidentally left in from some tinkering I could've sworn I'd 
>> gotten them.
>> 
>> This is further incredibly inexcusable, as I'm returning -1, 0, 1 which is 
>> asinine in the days of Python. It should have been something transparently 
>> obvious to a developer and user (e.g. "failure", "okay", "human assistance 
>> needed"). I've now ensured these returns are stripped from stop_service() 
>> and remove_DHCP_macro().
> Thanks.
>> 
>>> line 403-425: Seems like there should be a lot simpler way of just 
>>> removing a line from vfstab.
>>> Is there?
>> 
>> Um, this seems pretty short?
>> 
>> We've gotta open the file and handle the file not existing, opening, etc. 
>> (first except on IOError).
>> 
>> Next, we've gotta look for the entry (which will throw a 
>> ValueError/IndexError depending on where we fail - if we fail).
>> 
>> Lastly, we need to remove the line and need to check that the write took 
>> (second IOError exception).
>> 
>> Am I missing how this could be streamlined though?
> Well this went with the comment much further down about parsing the files in 
> general. The idea is that if you got rid of all of the code it would be 
> simpler. However from your response below it appears that having this is good 
> so I'll shut up. ;-)
>
>> 
>>> line 455-456: Boy that looks unmaintainable. If there is a more 
>>> maintainable way to do this I
>>> would suggest it. If not, you need a big old comment there.
>> 
>> Thanks to Ethan's code review comments this was changed. Please see 457-458 
>> from 
>> http://cr.opensolaris.org/~clayb/delete_service/webrev3.ethan/usr/src/cmd/installadm/delete_service.py.html
>>  
>> 
>> However, this was just a simple regex looking for:
>> "<anything>-s <anything up to a space, stored as path><anything to EOL>"
>> and replaced that whole string with what was found and stored as path.
> The point was that a lot of people aren't that familiar with reg ex's. Very 
> prone to maintenance mistakes so explaining what it's doing
> and maybe even how would be nice.
>> 
>>> lines 556-559: Seems a little long for list comprehension. I believe we 
>>> had discussed anything past about
>>> 2 lines should be considered for breaking up. Could this be done? It would 
>>> make the code easier to read
>>> and probably easier to maintain.
>> 
>> Sure, this was two lines but I was asked to expand fn to filename by 
>> another reviewer. How does it work if just pulled out of the for loop. It 
>> is three lines still but we get a much cleaner presentation (as it's only 
>> three statements in three lines):
>> 
>> # build a list of grub menus from baseDir
>> menus =  [filename for filename in os.listdir(baseDir) if
>>       # only select files which start with grub menu prefix
>>           filename.startswith(grub_menu_prefix) and
>>       # do not select the menu file the service uses
>>           filename != os.path.basename(menuLst.file_name)]
> OK.
>> 
>>> line 584: Realistically, could this be in any other field than mountpoint? 
>>> If not, could this code be simplified?
>> 
>> I'm not sure what code there is to simplify. Line 584 is a comment and the 
>> next line of code seems trivial to the extreme (just seeing if a string is 
>> in a list):
>> 
>> (line 587)
>> if boot_archive in com.MNTTab().fields.MOUNT_POINT:
> Same response as above wrt to mountpoint in /etc/vfstab
>> 
>>> line 612: why? It's not already able to be executed? Are we fixing 
>>> something here that should be fixed elsewhere?
>> 
>> That's the problem is that it's not executable, we're setting it so that we 
>> can run it. To set the <tftpdir>/rm.<service name> script so we can run it, 
>> we have to chmod it.
> OK. Seems like something would be wrong it it wasn't executable but it's nice 
> you're fixing the situation since you can. Why abort if you can fix as you're 
> doing.
>> 
>> Yes, create-service should get rid of the rm.<service name> scripts. See 
>> bug: 10853 (create-service:Should consider removing 
>> /tftpboot/rm.<service|client> scripts). Until then it's an interface were 
>> someone might stash something so let's honor it until we get rid of them.
>> 
>> As an aside, in the meantime - partially thanks to the 30 create-service 
>> bugs, the majority of this file is to give us a working foothold from which 
>> to clean things up. See Drew's comments about how bizarre it is to have a 
>> script which reverse engineers the entirety of an AI service.
>> 
>>> lines 625-634: Since the point of this function is to remove the tftpboot 
>>> files, why don't you just remove these files
>>> if the rmCmd hasn't? It certainly would be more efficient that appending 
>>> them to files now and removing them later.
>>> And clearer as to the state of the system after this function is called. 
>>> Plus, the header comments say the function removes them.
>> 
>> Ah thanks I've fixed the comment. The intention is to not remove anything 
>> except in the main function body, as this aids in debugging since it 
>> provides a central list and order, as well as allowing breadcrumbs until 
>> we've gathered all we can since we're piecing together what's left of a 
>> service.
> I'd have to disagree. I'd love to see things removed in the appropriate 
> functions. So then you would know if you return from function 
> removeTFTPBootFiles that all the tftpboot files are gone. I'd be confused it 
> they weren't.
>> 
>> The comment now reads:
>> Handle file removal in /tftpboot by building a list of files to remove:
>> First, adds pxegrub.<directory pointed to by /tftpboot/<service
>>  name> i.e. pxegrub.I86PC.OpenSolaris-1
>> Unmounts directory which is boot archive (will be something like
>>  I86PC.OpenSolaris-4) and removes /etc/vfstab entry for mount point
>> 
>> Calls /tftpboot/rm.<service name> which should remove:
>>     /tftpboot/<service name>
>>     /tftpboot/menu.lst.<service name>
>>     (if the above aren't removed by the rm.<service name> script they
>>          are added to the remove list)
>> Adds /tftpboot/rm.<service name>
>> 
>> Returns: If unable to find tftp root - None
>>          Success - A list of file paths to remove
>> 
>>> Why not have check_wanboot_conf also make sure everything is cleaned up. 
>>> Then you don't need the code at 696 ad 699 to
>>> add onto the fileToRemove list. Could we also then get rid of 714+? I 
>>> think all that would be left is then explicit files which
>>> could then just be rm'd. In general this seems more complicated than it 
>>> needs to be.
>> 
>> We need to remove the files provided by the list filesToRemove which has 
>> the paths returned by:
>> find_service_directory
>> find_image_path
> Can they be removed in the functions?
>> 
>> As well as (for services):
>> check_wanboot_conf (for SPARC)
>>        -  or  -
>> removeTFTPBootFiles (X86)
>> 
> But if these actually removed the files then you wouldn't need them to be 
> gone here.
>> So 714+ gets rid of these collections, not just check_wanboot_conf or 
>> removeTFTPBootFiles. Further, 696 and 699 are not the same; one is for 
>> SPARC and thus check_wanboot_conf, while the other is for X86 and thus 
>> removeTFTPBootFiles.
>> 
>> I'm perhaps missing something in your suggestion here?
> I think so. Right now you're checking to see if you need to remove a file and 
> placing it in a list. The list is later parsed and the file removed. That's 
> extra computation and complexity. Why not check to see if you need to remove 
> the file and remove it? Unless the file is needed later it's much simpler.
>> 
>>> usr/src/cmd/installadm/installadm_common.py
>>> 
>>> I lied. I say Ethan's comment about Unix. I agree.
>> 
>> I've changed UnixFile() to File_()
>> 
>>> lines 393-494: do we really need to do this in this manner? For example 
>>> VFSTab creates a database of the vfstab file. So far I've seen the 
>>> mountpoint field looked at for the boot_archive. Seems like overkill for 
>>> that. If we foresee needed more detailed parsability in the future I'm 
>>> fine with it. Otherwise I wonder....
>> 
>> Yup, we only use a few fields from each file but this is pretty simple now. 
>> Many people felt this functionality would be good to have available for 
>> general extensibility (and as the inetd.conf was a nit request which took 
>> ten minutes to add (the time for me to man -s 4 inetd.conf and type) it 
>> seems pretty trivial now (one just needs to give field names and a file 
>> name).
>> 
>> I'm not sure what you're asking here, other than is this easy? Yes
> The greater extensibility answer was appropriate for my question. Guess I 
> wasn't clear. Sorry. It was a long code review.
>
> Jean
>
>> 
>>> Jean
>>> 
>>> 
>>> 
>>> 
>>> 
>
>

Reply via email to