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!
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.
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?
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
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.
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
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
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.