Thursday, February 23, 2012

NetApp SDK for Java Part 2

Last time I gave a very basic example of the NetApp SDK using Java so I thought I would post something a bit more complex today. Most of the API calls use a String or boolean as the required type but some need nested NaElement objects. This isn't terribly difficult in itself but I find sorting through the documentation when nesting can be a bit tricky. To illustrate this I'm going to use the removal of an NFS export for two reasons:
  1. It has very few nested elements
  2. It has a bug in the documentation
Here is the API entry to remove an NFS export:
nfs-exportfs-delete-rules
Input Name Range Type Description
all-pathnames boolean
optional
Default value is false. Set to true to delete all rules. 'pathnames' option must be left empty if this option is true.
pathnames pathname-info[]
optional
In the Data ONTAP 7-Mode, these must be the pathnames to be deleted from the exports table. In Data ONTAP Cluster-Mode, the junction paths of the volumes to be unexported must be provided.
persistent boolean
optional
In Data ONTAP 7-Mode, default value is false. Modify the etc/exports file to delete the rules permanently. CAUTION: If 'all-pathnames' and 'persistent' are both true, all exports are removed permanently. In Data ONTAP Cluster-Mode, the export entries are always persistent. Default value is true. If false, an error will be returned.
verbose boolean
optional
Return a verbose output of what occurred. If there is an error after deleting only a few rules, 'deleted-pathnames' will return which rules were deleted. Default value is false.
The first thing to notice is that the pathname-info[] type looks like its an array. What the API really means to say is pathname-info is another node in our XML document of type NaElement. If we click on that link we get another entry shown here:
Element definition: pathname-info
Name Range Type Description
pathname string
pathname of the file. Pathname must be of the format /vol//
To complete our request, we are going to need to have multiple NaElements to represent each node in our XML document. I'm only going to reference the request code here, you can look at the previous post for netappServer details.
NaElement request = new NaElement("nfs-exportfs-delete-rules");
request.addNewChild("persistent", "true");
NaElement pathName = new NaElement("name", "/vol/volume");
NaElement pathNameInfo = new NaElement("pathname-info");
pathNameInfo.addChildElem(pathName);
NaElement pathNames = new NaElement("pathnames");
pathNames.addChildElem(pathNameInfo);
request.addChildElem(pathNames);
try {
   response = netappServer.invokeElem(request);
} catch (Exception e) {
   e.printStackTrace();
}
Walking through the code, the first two lines are pretty simple. The main NaElement named "request" is created with our desired action and I've added an option titled "persistent" to save the changes to the exports file. After that, I've kind of worked backwards. The pathnames input requires another element called pathname-info, and that requires an element called "pathname".

The "pathname" element is created with the line NaElement pathName = new NaElement("name", "/vol/volume");. Notice how it doesn't say "pathname" like the documentation states but rather "name". This is the bug I spent several hours of my life on. I found a reference dating back to 2008 on version 3.0R1 of the API. I'm using SDK 4.1 and it's still wrong. If you run the code with "pathname" as the documentation states you'll get an error that looks like this.
netapp.manage.NaAPIFailedException: Element 'name' is NULL (errno=13114)
However, after having worked that out, we create the required "pathname-info" and add the child element we just created as shown in these two lines.
NaElement pathNameInfo = new NaElement("pathname-info");
pathNameInfo.addChildElem(pathName);
We then create the element we originally wanted, called "pathnames", and add "pathname-info" to it.
NaElement pathNames = new NaElement("pathnames");
pathNames.addChildElem(pathNameInfo);
And finally, we add that whole assembly to the original request.
request.addChildElem(pathNames);
Using a graphical representation, we end up with this.
The SDK developers have done a nice job of NaElement's toString() method which will dump the XML for you to see what's going on. The above code will produce the following when request.toString() is called.
<nfs-exportfs-delete-rules>
  <persistent>true</persistent>
  <pathnames>
    <pathname-info>
      <name>/vol/volume</name>
    </pathname-info>
  </pathnames>
</nfs-exportfs-delete-rules>

No comments:

Post a Comment