7 Replies Latest reply: Mar 1, 2017 2:35 PM by David Baril RSS

    Sample Python class for working with the Nimble Storage REST API

    Casey Crawford Wayfarer

      GitHub - caseycrawford/nimblestorage_python: Nimble Storage Python examples using API

       

      At Capella University we recently introduced 6 individual CS700s (no grouping) connected by fiber channel. We use a much more robust Python class like this in our automated processes alongside UCS SDK and Custom Fabric MDS wrapper. This is a stripped down version I have been re-writing in my spare time to give other people a basic framework to start automating their Nimble Storage environments. You will find bugs! I will try to add and fix what I can, but would appreciate any contributions/fixes/logging.


      The more people that rely and make operational demands of the Nimble Storage REST API, the more resources they will apply to the API development team(s).

       

      Current Nimble RFE(s)

      "Update initiator alias with API." - Allow Initiator's aliases to be renamed through the API (there is a workaround in the GUI). This would only be an issue for you if you are constantly recycling WWPNs (Cisco UCS blades).

      "ALL/DETAIL endpoint for snapshots" - Get limited amounts of information about every snapshot on the array (instead of having to loop through every volume and running a query for each volume)

       

      Bruce Kyro

      Brian Knopp

      Robert Regan

       

      Thank you,

      - Casey Crawford

        • Re: Sample Python class for working with the Nimble Storage REST API
          David Richey Wayfarer

          Beautiful work! I wish I would have found this a day earlier as I already started automating some of our tasks with python and writing  my own 'class'. I really need to jump to the next level here and start building classes for my work but alas, thank you for yours!

           

          I will work on getting some of my code on a github to contribute here and now especially using your class, it will be a breeze!

          • Re: Sample Python class for working with the Nimble Storage REST API
            David Richey Wayfarer

            Casey,

             

            After integrating your class into my work, I have my first suggestion. I dont know if this is the correct place or not but I will post here for now. Im comfortable with github but I have not contributed to a project in the past and I am unsure of the etiquette.

             

            My discovery came after an attempt to retrieve all of our initiators for a given array and I noticed I was getting 'None' on the returns. After some digging through your code I have noticed that during most of the 'GET' functions where you are building the dictionaries, you iterate through the nimble JSON data and filter on a secondary key. In our arrays, pre 2.3 I believe, you were not required to have an 'alias' for the initiator, thus the reason for the 'None' results. Once switching the 'alias' key for 'iqn' or any number of other keys, I can get my results.

             

            My suggestion would be to continue filtering on 'data' as I have done the exact same with my own work but dumping the entire data JSON dict into your corresponding dict to allow the user to access the entire dataset.

             

            For example.

             

            def initiator_read(self):
                    request_json = self.query(request_type = 'read', request_endpoint = 'initiators/detail')
                    for item in request_json['data']:
                        self.dict_initiators[item['alias']] = item
            

             

            this assumes the users arrays have an alias defined and limits the amount of returnable data to work with. I propose

             

            def initiator_read(self):
                    request_json = self.query(request_type = 'read', request_endpoint = 'initiators/detail')
                    self.dict_initiators = request_json['data']
            

             

            what do you think?

             

            I have slightly modified your class to work this way for the code I want to publish. Im not sure how the approval for this works?

              • Re: Re: Sample Python class for working with the Nimble Storage REST API
                Casey Crawford Wayfarer

                Right now I don't know if the class should only return/load Nimble's 'data' structure (as you suggested), or if it should be doing normalizing (human readable names) like I am dependent on right now in the automation i'm doing (or perhaps those dictionaries should be generated by other functions for 'initiator_dict_by_id', 'initiator_dict_by_alias')?

                 

                How about a mix of both for now? If your alias is None then it's placed into the dictionary by it's ID so at the very least you can generate a report of all of your initiators?

                 

                    def initiator_read(self):
                        request_json = self.query(request_type = 'read', request_endpoint = 'initiators/detail')
                        for item in request_json['data']:
                            if item['alias'] == None:
                                self.dict_initiators[item['id']] = item
                            else:
                                self.dict_initiators[item['alias']] = item
                

                 

                Added into github for you: https://github.com/caseycrawford/nimblestorage_python/commit/9ce55b9d3971bbaa35671bd67f2c1adcdedc4db9

                 

                Thank you for finding this bug... I am sure you're going to find more as you go on. I am completely open to any changes, additions... make any pull requests you think would help other Nimble customers.

                 

                - Casey Crawford

                  • Re: Re: Re: Sample Python class for working with the Nimble Storage REST API
                    David Richey Wayfarer

                    That is the big question, to normalize or dump the raw data structure and a case can be made for each.

                     

                    Another question/suggestion I have is in regards to your assigning the returned JSON to an internal class dictionary. This may be my ignorance here, but the only way I could find a way to get the data back to my script, was to hunt down the dictionary name you use and then reference that directly in my code as follows:

                     

                    nimble.initiator_read()
                    print nimble.dict_initiators
                    
                    

                     

                    Would it be possible to allow a return of all 'read' functions and still have the internal dictionary assignment for class function work? My sample code looks as follows and works fine:

                     

                    for item in request_json['data']:
                         if item['alias'] == None:
                              self.dict_initiators[item['id']] = item
                        else:
                              self.dict_initiators[item['alias']] = item
                    return self.dict_initiators    
                    
                    

                     

                    and that allows me to do this:

                    initiators = nimble.initiator_read()
                    print initiators
                    
                    

                     

                    and lastly, for some reason (I have yet to dig hard) the new additional code you posted does not seem to be appending to the dictionary for my arrays and only returns the last iter of item.

                     

                    Im trying to educate myself on how to work with people on their public Git so we dont have to keep the conversation going here. Or if you dont mind, we can... either or.

                     

                    My first script is almost ready to publish here so Im trying to iron out these last bits in the class.

                     

                    edit!

                     

                    it only returns the last iter because ' == None' cannot be true because the 'alias' key is returning an empty string, not "None".

                     

                    Recommending change as follows:

                     

                    for item in request_json['data']:
                         if not item['alias']:
                              self.dict_initiators[item['id']] = item
                         else:
                              self.dict_initiators[item['alias']] = item
                    return self.dict_initiators
                    

                     

                    Works beautifully and I can grab my IQN

                      • Re: Re: Re: Sample Python class for working with the Nimble Storage REST API
                        Casey Crawford Wayfarer

                        I've updated the code to 'if not item['alias']' and it's up on github.

                         

                        As for the internal data structure, we use it this way here at Capella so that if you start doing operations that same dictionary is constantly being updated/refreshed with the latest information (if you add 20 initiators, they will be in that dictionary at the end so you can do validation, etc).

                         

                        In your workflow you would have to re-run initiators = nimble.initiator_read()

                         

                        Either way we can still return the json dictionaries whenever it's ran-- that is not a problem. You might have to wait until later in the week unless you plan on doing it yourself and pushing it?

                         

                        - Casey Crawford

                  • Re: Sample Python class for working with the Nimble Storage REST API
                    David Baril Wayfarer

                    Hi Casey,

                     

                    Thank you for your work creating a Python class for the Nimble REST API.

                     

                    Several months have gone by and I have been surprised that there have been no comments from Nimble related to an "official" Python class for the Nimble API ... perhaps not unlike the PowerShell Toolkit that Nimble created for Windows PowerShell users.

                     

                    Has anyone heard any news about Python/REST API topics from Nimble?

                     

                    I am planning on creating a relatively simple script to switch a Nimble volume from one Linux server to another Linux server to provide a poor-man's-failover capability.  I hope to use your Python class to jumpstart my work on that script.

                     

                    Thanks again, Casey for taking the time to contribute your work.

                     

                    Regards,

                     

                    Dave B.