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:
- It has very few nested elements
- 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>