Software Development Kit (SDK) and API Discussions

Enhancing the 'NaServer.invoke' call...

NETAPPACT
3,259 Views

Afternoon all

I've recently started looking at streamlining some of the code used in my Puppet NetApp network device module.

The majority of my code using NaServer.invoke, which is nice and straight-forward to understand and use.

However some have been forced to use NaServer.invoke_elem due to the additional complexity in the API.

A good example of this is the nfs-exportfs-append-rules-2 api, which has a lot of additional NaElement constructs below it...

However I started to wonder why I couldn't just use the invoke call, whilst also passing the NaElement fields where required.

This lead me to check out the invoke def in the ruby sdk, which initially looks like this:

   #A convenience routine which wraps invoke_elem().

   #It constructs an NaElement with name $api, and for

   #each argument name/value pair, adds a child element

   #to it.  It's an error to have an even number of

   #arguments to this function.

   #Example: myserver->invoke('snapshot-create',

   #                                'snapshot', 'mysnapshot',

   #                            'volume', 'vol0');

   #

  def invoke(api, *args)

    num_parms = args.length   

    if ((num_parms & 1) != 0)

        return self.fail_response(13001, "in Zapi::invoke, invalid number of parameters")

    end   

    xi = NaElement.new(api)

    i = 0

    while(i < num_parms)

        key = args[i]

    i = i + 1

    value = args[i]

    i = i + 1

    xi.child_add(NaElement.new(key, value))

    end

    return invoke_elem(xi)

  end

So if I try and feed in a NaElement field to invoke, I was getting an error caused by the NaElement construct going into the @contents value rather than the @children value, as shown below:

xi Request looks like:

#<NaElement:0x7f9039184b08

@attrkeys=[],

@attrvals=[],

@children=

  [#<NaElement:0x7f9039184978

    @attrkeys=[],

    @attrvals=[],

    @children=[],

    @content="true",

    @name="persistent">,

   #<NaElement:0x7f90391847e8

    @attrkeys=[],

    @attrvals=[],

    @children=[],

    @content=

     #<NaElement:0x7f9039195638

      @attrkeys=[],

      @attrvals=[],

      @children=

       [#<NaElement:0x7f9039195520

         @attrkeys=[],

         @attrvals=[],

         @children=[],

         @content="/vol/v_puppet_test1007131448.",

         @name="pathname">],

      @content="",

      @name="pathname-info">,

    @name="pathnames">],

@content="",

@name="nfs-exportfs-delete-rules">

INPUT

<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE netapp SYSTEM 'file:/etc/netapp_filer.dtd'>

<netapp version='1.13' xmlns='http://www.netapp.com/filer/admin'><nfs-exportfs-delete-rules><persistent>true</persistent><pathnames>#&lt;NaElement:0x7f9039195638&gt;</pathnames></nfs-exportfs-delete-rules></netapp>Invalid number of pathnames

So looking closer at 'invoke', I can see that it's treating the arguments passed to it as key/value pairs, and is constructing a new NaElement for every key/value pair. Hence the issue I'm seeing above with pathnames containing a NaElement value.

After a few tweaks, I came up with the following:

  def invoke(api, *args)

    num_parms = args.length

    if ((num_parms & 1) != 0)

        return self.fail_response(13001, "in Zapi::invoke, invalid number of parameters")

    end

    xi = NaElement.new(api)

    i = 0

    while(i < num_parms)

      key = args[i]

      i = i + 1

      value = args[i]

      i = i + 1

      if value.class == NaElement

        x = NaElement.new(key)

        x.child_add(value)

        xi.child_add(x)

      else

        xi.child_add(NaElement.new(key, value))

      end

    end

    return invoke_elem(xi)

  end

So, what do people think of the above change? Is this something that could be fed back into the core API SDK?

Cheers

Gavin

2 REPLIES 2

sens
3,259 Views

Hi Gavin,

Thanks for showing such interest in NMSDK (Ruby).

We have gone through the changes you have proposed.

We can see that the changes will construct NaElement (from simple parameters) and pass it to invoke_elem().

However, for APIs with complex parameters in input (i.e. containing multiple levels in XML hierarchy and sometimes iterative/nested inputs), one has to construct the NaElement structure before passing it to invoke() method. So, it does not relieve the user from creating NaElement structures.

The primary problem that you seem to be trying to solve is to do away with the need of switching between invoke() and invoke_elem() methods [please correct me if my understanding is wrong]. If that is the case, I would recommend you use "invoke_elem()" method all through your scripts and do away with invoke() method.

Regards,

Sen.

NETAPPACT
3,259 Views

Sen

Cheers for taking the time to respond.

Yes, the fundamental driver behind my changes was to remove the need for me to use invoke_elem().

This is due to functionality in my NetApp Puppet module to create wrapper defs around the various api calls required. This can be seen here: https://github.com/fatmcgav/fatmcgav-netapp/blob/master/lib/puppet/provider/netapp.rb#L27-58

And yes, it does still require some NAElement elements to be constructed prior to submitting to the invoke call, however as would be doing that anyway for invoke_elem, it's no further effort.

A good example of this is: https://github.com/fatmcgav/fatmcgav-netapp/blob/master/lib/puppet/provider/netapp_export/netapp_export.rb#L141-195

Currently, i've got this bundled as a patch which users need to apply to the SDK in order to use it with Puppet. So it's no major issue if this doesn't get incorporated back into the SDK... 🙂

Regards

Gavin

Public