Package: mistifi
MistifiMistifi is a highly scalable Python module enabling full interfacing with the Mist RestAPI.MotivationTo provide a scalable, easy to use and easy to contribute to module that will be able to interface to the fullest with the Mist Systems cloud for wired and wireless.InstallationThe module can be pip installedpip install mistifior usingpip3if using python3.The module is imported withimportmistififrommistifiimportMistiFiUsageThe usage workflow intended is:Create an instance with passing in the cloud and authentication options.Initiate communication with thecomms()method.Interface with the API with the use of either a specific endpoint method (likewlans()for example) or theresource()method.Create an instanceSelecting a cloudWhen creating an instance pass in thecloudoption to specify a direct instance of a cloud.There are currently two cloud options to select from. EitherEUorUS, withUSbeing the default if not provided with thecloudattribute.
They default toUS = api.mist.comEU = api.eu.mist.comIf not passed in, the defaultUSwill be used.Ex. 1: Using the defaultUScloudmist=MistiFi()In this case not only will theUScloud be used but also a username/password option for user login (Look at next section for explanation on this).Ex. 2: Specifying theEUcloudmist=MistiFi(cloud="EU")Note that the cloud parameter is case-insensitive. In the below example theUScloud will be used.mist=MistiFi(cloud="us")Using a token or username/passwordEx. 1: Using a tokenIn below example a tokenthetokenis used with the US cloud. You can create a user token by followingthese instructionsmist=MistiFi(token="thetoken")An alternative with specifying the EU cloud would be.mist=MistiFi(cloud="EU",token="thetoken")The token always has preference before username/password or other option, so in the below example a token would be used.mist=MistiFi(token="thetoken",username="theuser@mistifi.com",password="thepass")Ex. 2: Using username and password.Currently 2FA and OAUTH aren't supported.The minimum required for this option is to create an instance without any attributes like below.mist=MistiFi()In this case you are asked for username and password.You can provide one or both when creating a new instance and be asked about the other once thecomms()method is run.mist=MistiFi(cloud='us',username="theuser@mistifi.com")Communicating with the cloudOnce the cloud and authentication options are selected you must run thecomms()method which correctly sets up the headers depending on the authentication method used. For exampleX-CSRFTOKENis setup for the username/password option.mist=comms()Interfacing with the cloud URIsIf a specific resource method for a specific URI is not defined the main method that can be used is theresource()one. The resource methods defined start withResource methodin the docstring.For example, GET-ing/selfcan be achieved by either theresource()method or thewhoami()one.>>>whoami=mist.whoami()>>>rwhoami=mist.resource("GET",uri="/self")>>>print(whoami==rwhoami)TrueUnderstanding the resource() methodThe main method all others use on isresource(). You can pass keyword arguments into it. Pretty much anything will work, but there are some rules.First thing is that those kwargs are used to build the URL to the Mist cloud endpoint, therefore passing in proper parameters is necessary. Some parameters are special and handled differently.Example of special kwargs isparams. If passing in that kwarg, it will be handled differently so that it is passed into therequests.Session()asparams.If passing inorg_id=':org_id',site_id='site_id',uri='some_uri'will create URL properly with theorg_idfirstsite_idsecond and then theuri.All other kwargs will be added at the end to the URL, so make sure that URL exists. Error 400 is thrown otherwise.Example:mist.resource("GET",site_id=":site_id123",wlan_id=":wlan_id123",org_id=":org_id123",blah="/blah",params={"paramA":"valueA",'paramB':'valueB'})builds the URL tohttps://api.mist.com/api/v1/orgs/:org_id123/sites/:site_id123/wlans/:wlan_id123/blahandparamsare added at the end when passed in the requests asparams.AdditionalDebuggingThe default debug level isERROR, which can be changed per method call by preempting it withlogzero.loglevel(logging.LEVEL)whereLEVELis the debug level.
Each method then resets logging toERROR, so you need to set logging level before each one.You can import the below for thisimportloggingimportlogzerofromlogzeroimportloggerEx. 1: DEBUG level>>>logzero.loglevel(logging.DEBUG)>>>mist.whoami()[I 200326 14:48:17 mistifi:547] Calling whoami()
[I 200326 14:48:17 mistifi:548] kwargs in: {}
[I 200326 14:48:17 mistifi:511] Calling resource()
[D 200326 14:48:17 mistifi:512] kwargs in: {'uri': '/self'}
[I 200326 14:48:17 mistifi:471] Calling _params()
[I 200326 14:48:17 mistifi:472] kwargs in: {'uri': '/self'}
[D 200326 14:48:17 mistifi:479] Returned params: {}
[I 200326 14:48:17 mistifi:395] Calling _resource_url()
[I 200326 14:48:17 mistifi:396] kwargs in: {'uri': '/self'}
[D 200326 14:48:17 mistifi:450] URL to endpoint: https://api.mist.com/api/v1/self
[I 200326 14:48:17 mistifi:333] Calling _api_call()
[I 200326 14:48:17 mistifi:334] Method is: GET
[I 200326 14:48:17 mistifi:335] Calling URL: https://api.mist.com/api/v1/self
[D 200326 14:48:17 mistifi:336] With headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}
[I 200326 14:48:18 mistifi:346] Response status code: 200
[D 200326 14:48:18 mistifi:356] Response HEAD: {'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': 'https://manage.mist.com', 'Access-Control-Expose-Headers': 'X-CSRFTOKEN,X-Requested-With,X-Page-Page,X-Page-Total', 'Allow': 'GET, OPTIONS, DELETE, PUT', 'Cache-Control': 'no-cache, no-store', 'Content-Type': 'application/json', 'Date': 'Thu, 26 Mar 2020 14:48:18 GMT', 'Pragma': 'no-cache', 'Server': 'gunicorn/19.10.0', 'Set-Cookie': 'sessionid=8trv1zr79sknwk0n7sz2pim8x26g84mh; Domain=.mist.com; expires=Fri, 27-Mar-2020 14:48:18 GMT; HttpOnly; Max-Age=86400; Path=/; Secure', 'Vary': 'Origin', 'Via': 'kong/0.9.3', 'X-Frame-Options': 'SAMEORIGIN', 'X-Kong-Proxy-Latency': '0', 'X-Kong-Upstream-Latency': '39', 'Content-Length': '608', 'Connection': 'keep-alive'}
[D 200326 14:48:18 mistifi:357] The response: {'email': 'blah@mist.com'...}Ex. 2: INFO level>>>logzero.loglevel(logging.INFO)>>>mist.whoami()[I 200326 14:58:23 mistifi:547] Calling whoami()
[I 200326 14:58:23 mistifi:548] kwargs in: {}
[I 200326 14:58:23 mistifi:511] Calling resource()
[I 200326 14:58:23 mistifi:471] Calling _params()
[I 200326 14:58:23 mistifi:472] kwargs in: {'uri': '/self'}
[I 200326 14:58:23 mistifi:395] Calling _resource_url()
[I 200326 14:58:23 mistifi:396] kwargs in: {'uri': '/self'}
[I 200326 14:58:23 mistifi:333] Calling _api_call()
[I 200326 14:58:23 mistifi:334] Method is: GET
[I 200326 14:58:23 mistifi:335] Calling URL: https://api.mist.com/api/v1/self
[I 200326 14:58:23 mistifi:346] Response status code: 200Ex. 3: Examples of error outputHere no log level was set.>>>mist.whoami()[E 200326 14:58:24 mistifi:351] Response Error:
    {"detail":"Method \"GET\" not allowed."}
[E 200326 14:58:24 mistifi:351] Response Error:
    {"detail":"CSRF Failed: CSRF token missing or incorrect."}TODOThe general TODO list is:add more/all URIsContributingThank you for helping us develop Mistifi. We're happy to accept contribution of any kind. Feel free to submit feature requests and bug reports under Issues.Submitting a pull request guidelinesAll pull requests require a code review.Any merge conflicts needs to be resolved.Include unit tests when you contribute new features and bugs, as they help to a) prove that your code works correctly, and b) guard against future breaking changes to lower the maintenance cost.All tests needs to pass before we will review your PR.When you respond to changes based on comments from a code review, please reply with "Done." so that we get a notification.ContributorsBen CardyPrimoz Marinsek