text: 
  # PLEASE READ DISCLAIMER
  #
  #    This class demonstrates sample IxNetwork REST API usage for
  #    demo and reference purpose only.
  #    It is subject to change for updates without warning.
  #
  # REQUIREMENTS
  #    - Python 2.7 (Supports Python 2 and 3)
  #    - Python modules: requests
  #
  
  from __future__ import absolute_import, print_function, division
  import os, re, sys, requests, json, time, subprocess, traceback, time, datetime, platform
  
  class IxNetRestApiException(Exception):
      def __init__(self, msg=None):
          if platform.python_version().startswith('3'):
              super().__init__(msg)
  
          if platform.python_version().startswith('2'):
              super(IxNetRestApiException, self). __init__(msg)
  
          if Connect.robotStdout is not None:
              Connect.robotStdout.log_to_console(msg)
  
          showErrorMsg = '\nIxNetRestApiException error: {0}\n\n'.format(msg)
          print(showErrorMsg)
          if Connect.enableDebugLogFile:
              with open(Connect.debugLogFile, 'a') as restLogFile:
                  restLogFile.write(showErrorMsg)
  
  class Connect:
      # For IxNetRestApiException
      debugLogFile = None
      enableDebugLogFile = False
      robotStdout = None
  
      def __init__(self, apiServerIp=None, serverIpPort=None, serverOs='windows', linuxChassisIp=None, manageSessionMode=False,
                   webQuickTest=False, username=None, password='admin', licenseServerIp=None, licenseMode=None, licenseTier=None,
                   deleteSessionAfterTest=True, verifySslCert=False, includeDebugTraceback=True, sessionId=None, httpsSecured=False,
                   apiKey=None, generateLogFile=True, robotFrameworkStdout=False, linuxApiServerTimeout=120):
          """
          Description
             Initializing default parameters and making a connection to the API server
  
          Notes
              Starting IxNetwork 8.50, https will be enforced even for Windows connection.
              If you still want to use http, you need to add -restInsecure to the IxNetwork.exe appliaction under "target".
  
          Examples
              Right click on "IxNetwork API server", select properties and under target
              ixnetwork.exe -restInsecure -restPort 11009 -restOnAllInterfaces -tclPort 8009
  
          Parameters
             apiServerIp: (str): The API server IP address.
             serverIpPort: (str): The API server IP address socket port.
             serverOs: (str): windows|windowsConnectionMgr|linux
             linuxChassisIp: (str): Connect to a Linux OS chassis IP address.
             webQuickTest: (bool): True: Using IxNetwork Web Quick Test. Otherwise, using IxNetwork.
             includeDebugTraceback: (bool):
                                     True: Traceback messsages are included in raised exceptions.
                                     False: No traceback.  Less verbose for debugging.
             username: (str): The login username. For Linux API server only.
             password: (str): The login password. For Linux API server only.
             licenseServerIp: (str): The license server IP address.
             licenseMode: (str): subscription | perpetual | mixed
             licenseTier: (str): tier1 | tier2 | tier3
             linuxApiServerTimeout: (int): For Linux API server start operation timeout. Defaults to 120 seconds.
             deleteSessionAfterTest: (bool): True: Delete the session.
                                             False: Don't delete the session.
             verifySslCert: (str): Optional: Include your SSL certificate for added security.
             httpsSecured: (bool): This parameter is only used by Connection Mgr when user wants to connect to
                                   an existing session.
                                   True = IxNetwork ReST API server is using HTTPS.
                                   This parameter must also include sessionId and serverIpPort=<the ssl port number>
  
             serverOs: (str): Defaults to windows. windows|windowsConnectionMgr|linux.
             includeDebugTraceback: (bool): True: Include tracebacks in raised exceptions.
             sessionId: (str): The session ID on the Linux API server or Windows Connection Mgr to connect to.
             apiKey: (str): The Linux API server user account API-Key to use for the sessionId connection.
             generateLogFile: True|False|<log file name>.  If you want to generate a log file, provide
                                  the log file name.
                                  True = Then the log file default name is ixNetRestApi_debugLog.txt
                                  False = Disable generating a log file.
                                  <log file name> = The full path + file name of the log file to create.
             robotFrameworkStdout: (bool):  True = Print to stdout.
             httpInsecure: (bool): This parameter is only for Windows connections.
                                       True: Using http.  False: Using https.
                                       Starting 8.50: IxNetwork defaults to use https.
                                       If you are using versions prior to 8.50, it needs to be a http connection.
                                       In this case, set httpInsecure=True.
  
          Notes
              Class attributes
                 self._session: The requests initial Session().
                 self.serverOs: windows|windowsConnectionMgr|linux
  
                 self.httpHeader: http://{apiServerIp}:{port}
                 self.sessionId : http://{apiServerIp}:{port}/api/v1/sessions/{id}
                 self.sessionUrl: http://{apiServerIp}:{port}/api/v1/sessions/{id}/ixnetwork
                 self.headlessSessionId: /api/v1/sessions/{id}
                 self.apiSessionId:      /api/v1/sessions/{id}/ixnetwork
  
                 self.jsonHeader: The default header: {"content-type": "application/json"}
                 self.apiKey: For Linux API server only. Automatically provided by the server when login
                              successfully authenticated.
                              You could also provide an API-Key to connect to an existing session.
                              Get the API-Key from the Linux API server user account.
  
          Examples:
             Steps to connect to Linux API server steps:
                 1> POST: https://{apiServerIp}/api/v1/auth/session
                    DATA: {"username": "admin", "password": "admin"}
                    HEADERS: {'content-type': 'application/json'}
  
                 2> POST: https://{apiServerIp:{port}/api/v1/sessions
                    DATA: {"applicationType": "ixnrest"}
                    HEADERS: {'content-type': 'application/json', 'x-api-key': 'd9f4da46f3c142f48dddfa464788hgee'}
  
                 3> POST: https://{apiServerIp}:443/api/v1/sessions/4/operations/start
                    DATA: {}
                    HEADERS: {'content-type': 'application/json', 'x-api-key': 'd9f4da46f3c142f48dddfa464788hgee'}
  
                 sessionId = https://{apiServerIp}:443/api/v1/sessions/{id}
  
             Steps to connect to Linux Web Quick Test:
                 1> POST: https://{apiServerIp}:443/api/v1/auth/session
                    DATA: {"username": "admin", "password": "admin"}
                    HEADERS: {'content-type': 'application/json'}
  
                 2> POST: https://{apiServeIp}:443/api/v1/sessions
                    DATA: {'applicationType': 'ixnetwork'}
  
                 3> POST: https://{apiServerIp}:443/api/v1/sessions/2/operations/start
                    DATA: {'applicationType': 'ixnetwork'}
  
              sessionId = https://{apiServerIp}/ixnetworkweb/api/v1/sessions/{id}
  
             Notes
                To connect to an existing configuration.
                   Windows: Nothing special to include. The session ID is always "1".
                   Linux API server: Include the api-key and sessionId that you want to connect to.
                   Windows Connection Manager: Include just the sessionId: For example: 8021.
          """
          from requests.exceptions import ConnectionError
          from requests.packages.urllib3.connection import HTTPConnection
  
          # Disable SSL warnings
          requests.packages.urllib3.disable_warnings()
  
          # Disable non http connections.
          from requests.packages.urllib3.exceptions import InsecureRequestWarning
          requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  
          self._session = requests.Session()
  
          self.httpScheme = 'http' ;# This will change to https in createWindowsSession and connectToLinuxApiServer
          if httpsSecured:
              # For Windows Connection Mgr only.
              # When creating a new session, there is no way to know by doing a POST for a new session to
              # understand if it's for http or https.  You must enter https for the POST to create a new session.
              self.httpScheme = 'https'
  
          self.serverOs = serverOs ;# windows|windowsConnectionMgr|linux
          self.jsonHeader = {"content-type": "application/json"}
          self.username = username
          self.password = password
          self.apiKey = apiKey
          self.verifySslCert = verifySslCert
          self.linuxApiServerIp = apiServerIp
          self.manageSessionMode = manageSessionMode
          self.apiServerPort = serverIpPort
          self.webQuickTest = webQuickTest
          self.generateLogFile = generateLogFile
          self.robotFrameworkStdout = robotFrameworkStdout
          self.linuxChassisIp = linuxChassisIp
          self.linuxApiServerTimeout = linuxApiServerTimeout
  
          if generateLogFile:
              if generateLogFile == True:
                  # Default the log file name
                  self.restLogFile = 'ixNetRestApi_debugLog.txt'
                  Connect.enableDebugLogFile = True
                  Connect.debugLogFile = self.restLogFile
  
              if type(generateLogFile) != bool:
                  self.restLogFile = generateLogFile
  
              # Instantiate a new log file here.
              with open(self.restLogFile, 'w') as restLogFile:
                  restLogFile.write('Date: {0}\nTime: {1}\n\n'.format(self.getDate, self.getTime))
  
          # Make Robot print to stdout
          if self.robotFrameworkStdout:
              from robot.libraries.BuiltIn import _Misc
              self.robotStdout = _Misc()
              Connect.robotStdout = self.robotStdout
  
          if linuxChassisIp:
              self.connectToLinuxIxosChassis(self.linuxChassisIp, self.username, self.password)
              return
  
          if serverOs == 'windows':
              self.createWindowsSession(apiServerIp, serverIpPort)
  
          if serverOs == 'windowsConnectionMgr':
              # User connecting to existing sessionId
              # 
              # Starting 8.50, IxNetwork API server supports https on Windows.
              # If connecting to an existing session with the api server set to https::
              #     - Pass in apiServerIp, serverIpPort, httpsSecured and  sessionId
              #     - Although the serverIpPort default is 443 for https, this could change in the future.
              
              if sessionId:
                  url = '{0}://{1}:{2}/api/v1/sessions/{3}'.format(self.httpScheme, apiServerIp, serverIpPort, str(sessionId))
                  try:
                      response = self._session.request('GET', url, verify=self.verifySslCert, allow_redirects=False)
                      if '3' in str(response.status_code):
                          self.httpScheme = 'https'
                          # Here, needs to set to use https.
                          url = '{0}://{1}:{2}/api/v1/sessions/{3}'.format(self.httpScheme, apiServerIp, serverIpPort, str(sessionId))
  
                  except requests.exceptions.RequestException as errMsg:
                      errMsg = 'Connecting to existing config failed on a GET: {0}'.format(errMsg)
                      raise IxNetRestApiException(errMsg)
  
                  self.logInfo('Connecting to existing session: {}'.format(url))
                  self.sessionUrl = url + '/ixnetwork'
                  self.sessionId = '{0}://{1}:{2}/api/v1/sessions/{3}'.format(self.httpScheme, apiServerIp,
                                                                              serverIpPort, str(sessionId))
                  self.apiSessionId = '/api/v1/sessions/{0}/ixnetwork'.format(str(sessionId))
                  self.httpHeader = self.sessionUrl.split('/api')[0]
              else:
                  # Create a new session
                  self.createWindowsSession(apiServerIp, serverIpPort)
  
          if serverOs == 'linux':
              if self.apiServerPort == None:
                  self.apiServerPort = 443
  
              # Connect to no session ID. Connects to a Linux API server to get and delete open sessions.
              if self.manageSessionMode:
                  if self.apiKey == None:
                      response = self.post('https://{}:{}/api/v1/auth/session'.format(self.linuxApiServerIp, self.apiServerPort),
                                           data={"username": "admin", "password": "admin"},
                                           headers={'content-type': 'application/json'})
  
                  self.jsonHeader = {'content-type': 'application/json', 'x-api-key': self.apiKey}
                  self.sessionUrl = 'https://{0}:{1}/ixnetworkweb/api/v1/sessions'.format(self.linuxApiServerIp, self.apiServerPort)
                  return
  
              # Connect to an existing session on the Linux API server
              if sessionId:
                  if self.apiKey == None:
                      url = 'https://{0}:{1}/api/v1/auth/session'.format(self.linuxApiServerIp, self.apiServerPort)
                      response = self.post(url, data={'username': username, 'password': password}, ignoreError=True)
                      if not str(response.status_code).startswith('2'):
                          raise IxNetRestApiException('\nLogin username/password failed\n')
  
                      self.apiKey = response.json()['apiKey']
  
                  self.sessionId = 'https://{0}:{1}/api/v1/sessions/{2}'.format(self.linuxApiServerIp,
                                                                                self.apiServerPort, str(sessionId))
                  self.sessionUrl = self.sessionId + '/ixnetwork'
                  self.httpHeader = self.sessionUrl.split('/ixnetworkweb')[0]
                  self.jsonHeader = {'content-type': 'application/json', 'x-api-key': self.apiKey}
  
                  response = self.get('https://{0}:{1}/api/v1/sessions/{2}'.format(self.linuxApiServerIp, self.apiServerPort, str(sessionId)))
  
                  if self.webQuickTest == False:
                      # https://192.168.70.108/ixnetworkweb/api/v1/sessions/4
                      self.sessionId = response.json()['links'][0]['href']
                      # Remove the redirect /ixnetworkweb from the URL. IxNetwork 8.50 will resolve this.
                      self.sessionId = self.sessionId.replace('ixnetworkweb/', '')
  
                      # https://192.168.70.108/ixnetworkweb/api/v1/sessions/4/ixnetork
                      self.sessionUrl = self.sessionId + '/ixnetwork'
  
                      # /api/v1/sessions/4/ixnetwork
                      match = re.match('.*(/api.*)', self.sessionId)
                      self.apiSessionId = match.group(1) + '/ixnetwork'
  
                      # https://10.10.10.1:443
                      matchHeader = re.match('(https://[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(:[0-9]+)?)', self.sessionId)
                      self.httpHeader = matchHeader.group(1)
  
                  if self.webQuickTest:
                      self.sessionId = 'https://{0}:{1}/ixnetwork/api/v1/sessions/{2}'.format(self.linuxApiServerIp,
                                                                                                 self.apiServerPort, str(sessionId))
                      self.sessionUrl = self.sessionId
                      self.httpHeader = self.sessionUrl.split('/ixnetworkweb')[0]
  
              # Create new session: connectToLinuxApiServer API knows whether to create a new session or connect to an existing
              #                     session by looking at the self.apiKey.
              if apiKey == None and sessionId == None:
                  self.connectToLinuxApiServer(self.linuxApiServerIp, self.apiServerPort, username=username, password=password,
                                               verifySslCert=verifySslCert, timeout=self.linuxApiServerTimeout)
  
              if licenseServerIp or licenseMode or licenseTier:
                  self.configLicenseServerDetails(licenseServerIp, licenseMode, licenseTier)
  
          # For Linux API Server and Windoww Connection Mgr only: Delete the session when script is done if deleteSessionAfterTest = True.
          self.deleteSessionAfterTest = deleteSessionAfterTest
  
          match = re.match('http.*(/api.*/sessions/[0-9]+)/ixnetwork', self.sessionUrl)
          self.headlessSessionId = match.group(1)
  
          if includeDebugTraceback == False:
              sys.tracebacklimit = 0
  
      def get(self, restApi, data={}, stream=False, silentMode=False, ignoreError=False):
          """
          Description
              A HTTP GET function to send REST APIs.
  
          Parameters
             restApi: (str): The REST API URL.
             data: (dict): The data payload for the URL.
             silentMode: (bool):  To display on stdout: URL, data and header info.
             ignoreError: (bool): True: Don't raise an exception.  False: The response will be returned.
  
          Syntax
              /api/v1/sessions/1/ixnetwork/operations
          """
          if silentMode is False:
              #self.logInfo('\n\tGET: {0}\n\tHEADERS: {1}'.format(restApi, self.jsonHeader))
              self.logInfo('\n\tGET: {0}'.format(restApi))
  
          try:
              # For binary file
              if stream:
                  response = self._session.request('GET', restApi, stream=True, headers=self.jsonHeader, allow_redirects=True, verify=self.verifySslCert)
  
              if stream == False:
                  response = self._session.request('GET', restApi, headers=self.jsonHeader, allow_redirects=True, verify=self.verifySslCert)
  
              if silentMode is False:
                  for redirectStatus in response.history:
                      if '307' in str(response.history):
                          self.logInfo('\t{0}: {1}'.format(redirectStatus, response.url), timestamp=False)
  
                  self.logInfo('\tSTATUS CODE: {0}'.format(response.status_code), timestamp=False)
  
              if not str(response.status_code).startswith('2'):
                  if ignoreError == False:
                      if 'message' in response.json() and response.json()['messsage'] != None:
                          self.logWarning('\n%s' % response.json()['message'])
  
                      errMsg = 'GET Exception error: {0}'.format(response.text)
                      raise IxNetRestApiException(errMsg)
  
              return response
  
          except requests.exceptions.RequestException as errMsg:
              errMsg = 'GET Exception error: {0}'.format(errMsg)
              raise IxNetRestApiException(errMsg)
  
      def post(self, restApi, data={}, headers=None, silentMode=False, noDataJsonDumps=False, ignoreError=False):
          """
          Description
             A HTTP POST function to create and start operations.
  
          Parameters
             restApi: (str): The REST API URL.
             data: (dict): The data payload for the URL.
             headers: (str): The special header to use for the URL.
             silentMode: (bool):  To display on stdout: URL, data and header info.
             noDataJsonDumps: (bool): True: Use json dumps. False: Accept the data as-is.
             ignoreError: (bool): True: Don't raise an exception.  False: The response will be returned.
          """
          if headers != None:
              originalJsonHeader = self.jsonHeader
              self.jsonHeader = headers
  
          if noDataJsonDumps == True:
              data = data
          else:
              data = json.dumps(data)
  
          if silentMode == False:
              #self.logInfo('\n\tPOST: {0}\n\tDATA: {1}\n\tHEADERS: {2}'.format(restApi, data, self.jsonHeader))
              self.logInfo('\n\tPOST: {0}\n\tDATA: {1}'.format(restApi, data))
  
          try:
              if self.linuxChassisIp and json.loads(data) == {}:
                  # Interacting with LinuxOS chassis doesn't like empty data payload. So excluding it here.
                  response = self._session.request('POST', restApi, headers=self.jsonHeader, allow_redirects=True, verify=self.verifySslCert)
              else:
                  response = self._session.request('POST', restApi, data=data, headers=self.jsonHeader, allow_redirects=True,
                                           verify=self.verifySslCert)
  
              # 200 or 201
              if silentMode == False:
                  for redirectStatus in response.history:
                      if '307' in str(response.history):
                          self.logInfo('\t{0}: {1}'.format(redirectStatus, response.url), timestamp=False)
  
                  self.logInfo('\tSTATUS CODE: %s' % response.status_code, timestamp=False)
  
              if str(response.status_code).startswith('2') == False:
                  if ignoreError == False:
                      if 'errors' in response.json():
                          errMsg = 'POST Exception error: {0}\n'.format(response.json()['errors'])
                          raise IxNetRestApiException(errMsg)
  
                      raise IxNetRestApiException('POST error: {0}\n'.format(response.text))
  
              # Change it back to the original json header
              if headers != None:
                  self.jsonHeader = originalJsonHeader
  
              return response
  
          except requests.exceptions.RequestException as errMsg:
              errMsg = 'POST Exception error: {0}'.format(errMsg)
              raise IxNetRestApiException(errMsg)
  
      def patch(self, restApi, data={}, silentMode=False, ignoreError=False):
          """
          Description
             A HTTP PATCH function to modify configurations.
  
          Parameters
             restApi: (str): The REST API URL.
             data: (dict): The data payload for the URL.
             silentMode: (bool):  To display on stdout: URL, data and header info.
          """
          if silentMode == False:
              #self.logInfo('\n\tPATCH: {0}\n\tDATA: {1}\n\tHEADERS: {2}'.format(restApi, data, self.jsonHeader))
              self.logInfo('\n\tPATCH: {0}\n\tDATA: {1}'.format(restApi, data))
  
          try:
              response = self._session.request('PATCH', restApi, data=json.dumps(data), headers=self.jsonHeader, allow_redirects=True, 
                                        verify=self.verifySslCert)
  
              if silentMode == False:
                  for redirectStatus in response.history:
                      if '307' in str(response.history):
                          self.logInfo('\t{0}: {1}'.format(redirectStatus, response.url), timestamp=False)
  
                  self.logInfo('\tSTATUS CODE: %s' % response.status_code, timestamp=False)
  
                  if ignoreError == False:
                      if not str(response.status_code).startswith('2'):
                          if response.json() and  'errors' in response.json():
                              errMsg = 'PATCH Exception error: {0}\n'.format(response.json()['errors'])
                              raise IxNetRestApiException('PATCH error: {0}\n'.format(errMsg))
  
              return response
  
          except requests.exceptions.RequestException as errMsg:
              errMsg = 'PATCH Exception error: {0}\n'.format(errMsg)
              raise IxNetRestApiException(errMsg)
  
      def options(self, restApi, data={}, silentMode=False, ignoreError=False):
          """
          Description
              A HTTP OPTIONS function to send REST APIs.
  
          Parameters
             restApi: (str): The REST API URL.
             silentMode: (bool):  To display on stdout: URL, data and header info.
             ignoreError: (bool): True: Don't raise an exception.  False: The response will be returned.
  
          """
          if silentMode is False:
              #self.logInfo('\n\tOPTIONS: {0}\n\tHEADERS: {1}'.format(restApi, self.jsonHeader))
              self.logInfo('\n\tOPTIONS: {0}'.format(restApi))
  
          try:
              # For binary file
              response = self._session.request('OPTIONS', restApi, headers=self.jsonHeader, allow_redirects=True, verify=self.verifySslCert)
  
              if silentMode is False:
                  for redirectStatus in response.history:
                      if '307' in str(response.history):
                          self.logInfo('\t{0}: {1}'.format(redirectStatus, response.url), timestamp=False)
  
                  self.logInfo('\tSTATUS CODE: {0}'.format(response.status_code), timestamp=False)
  
              if not str(response.status_code).startswith('2'):
                  if ignoreError == False:
                      if 'message' in response.json() and response.json()['messsage'] != None:
                          self.logWarning('\n%s' % response.json()['message'])
  
                      errMsg = 'OPTIONS Exception error: {0}'.format(response.text)
                      raise IxNetRestApiException(errMsg)
              return response
  
          except requests.exceptions.RequestException as errMsg:
              errMsg = 'OPTIONS Exception error: {0}'.format(errMsg)
              raise IxNetRestApiException(errMsg)
  
      def delete(self, restApi, data={}, headers=None):
          """
          Description
             A HTTP DELETE function to delete the session.
             For Linux and Windows Connection Mgr API server only.
  
          Paramters
             restApi: (str): The REST API URL.
             data: (dict): The data payload for the URL.
             headers: (str): The headers to use for the URL.
          """
          if headers != None:
              self.jsonHeader = headers
  
          #self.logInfo('\n\tDELETE: {0}\n\tDATA: {1}\n\tHEADERS: {2}'.format(restApi, data, self.jsonHeader))
          self.logInfo('\n\tDELETE: {0}\n\tDATA: {1}'.format(restApi, data))
  
          try:
              response = self._session.request('DELETE', restApi, data=json.dumps(data), headers=self.jsonHeader, allow_redirects=True, 
                                         verify=self.verifySslCert)
  
              for redirectStatus in response.history:
                  if '307' in str(response.history):
                      self.logInfo('\t{0}: {1}'.format(redirectStatus, response.url), timestamp=False)
  
              self.logInfo('\tSTATUS CODE: %s' % response.status_code, timestamp=False)
              if not str(response.status_code).startswith('2'):
                  self.showErrorMessage()
                  errMsg = 'DELETE Exception error: {0}\n'.format(response.text)
                  self.logError(errMsg)
                  raise IxNetRestApiException(errMsg)
              return response
  
          except requests.exceptions.RequestException as errMsg:
              errMsg = 'DELETE Exception error: {0}\n'.format(errMsg)
              self.logError(errMsg)
              raise IxNetRestApiException(errMsg)
  
      def getDate(self):
          dateAndTime = str(datetime.datetime.now()).split(' ')
          return dateAndTime[0]
  
      def getTime(self):
          dateAndTime = str(datetime.datetime.now()).split(' ')
          return dateAndTime[1]
  
      def getSelfObject(self):
          """
          Description
             For Robot Framework support only.
  
          Return
             The instance object.
          """
          return self
  
      def createWindowsSession(self, ixNetRestServerIp, ixNetRestServerPort='11009'):
          """
          Description
             Connect to a Windows IxNetwork API Server. This is
             for both Windows and Windows server with IxNetwork Connection Manager.
             This will set up the session URL to use throughout the test.
  
          Parameter
            ixNetRestServerIp: (str): The Windows IxNetwork API Server IP address.
            ixNetRestServerPort: (str): Default: 11009.  Provide a port number to connect to.
                                 On a Linux API Server, a socket port is not needed. State "None".
          """
          # Handle __import__(IxNetRestApi) to not error out
          if ixNetRestServerIp == None: return
  
          url = '{0}://{1}:{2}/api/v1/sessions'.format(self.httpScheme, ixNetRestServerIp, ixNetRestServerPort)
  
          if self.serverOs == 'windowsConnectionMgr':
              try:
                  self.logInfo('Please wait while IxNetwork Connection Mgr starts up an IxNetwork session...')
                  self.logInfo('\t{}'.format(url), timestamp=False)
                  response = self._session.request('POST', url, data={}, verify=self.verifySslCert, allow_redirects=True)
  
              except requests.exceptions.RequestException as errMsg:
                  errMsg = 'Creating new session failed: {0}'.format(errMsg)
                  raise IxNetRestApiException(errMsg)
  
              sessionIdNumber = response.json()['links'][0]['href'].split('/')[-1]
              response = self._session.request('GET', url+'/'+str(sessionIdNumber), verify=self.verifySslCert, allow_redirects=False)
  
              if str(response.status_code).startswith('3'):
                  # >= 8.50
                  self.httpScheme = 'https'
                  # https://192.168.70.3:443/api/v1/sessions/8020
                  self.sessionId = response.headers['location']
                  match = re.match('https://.*:([0-9]+)/api.*', self.sessionId)
                  ixNetRestServerPort = match.group(1)
              else:
                  # < 8.50
                  self.sessionId = url + '/'+str(sessionIdNumber)
  
              self.sessionUrl = '{httpScheme}://{apiServer}:{port}/api/v1/sessions/{id}/ixnetwork'.format(
                  httpScheme=self.httpScheme,
                  apiServer=ixNetRestServerIp,
                  port=ixNetRestServerPort,
                  id=sessionIdNumber)
  
              counterStop = 10
              for counter in range(1, counterStop+1):
                  response = self.get(self.sessionId)
                  if type(response.json()) == list:
                      currentState = response.json()[0]['state']
                  else:
                      currentState = response.json()['state']
  
                  self.logInfo('\n\tNew Windows session current state: {0}'.format(currentState), timestamp=False)
                  if currentState != 'ACTIVE' and counter < counterStop:
                      self.logInfo('\tWaiting {0}/{1} seconds'.format(counter, counterStop), timestamp=False)
                      time.sleep(1)
  
                  if currentState != 'ACTIVE' and counter == counterStop:
                      raise IxNetRestApiException('New Windows session state failed to become ACTVIE state')
  
                  if currentState == 'ACTIVE' and counter < counterStop:
                      break
  
              # Version < 8.50 requires more waiting time. And we cannot verify the version number at this point.
              time.sleep(25)
  
          if self.serverOs == 'windows':
              # windows sessionId is always 1 because it only supports one session.
              self.sessionUrl = url + '/1/ixnetwork'
  
              try:
                  self.logInfo('\nVerifying API server connection: {}'.format(self.sessionUrl))
                  response = self._session.request('GET', self.sessionUrl, allow_redirects=False, verify=self.verifySslCert)
                  if '307' in str(response.status_code) and response.headers['location'].startswith('https'):
                      # Overwrite the sessionUrl with the redirected https URL
                      self.sessionUrl = response.headers['location']
  
              except requests.exceptions.RequestException as errMsg:
                  errMsg = 'Connection failed: {0}'.format(errMsg)
                  raise IxNetRestApiException(errMsg)
  
              # http://192.168.70.127:11009/api/v1/sessions/1
              self.sessionId = self.sessionUrl.split('/ixnetwork')[0]
  
          # http://192.168.70.127:11009
          self.httpHeader = self.sessionUrl.split('/api')[0]
  
          # /api/v1/sessions/{id}/ixnetwork
          self.apiSessionId = '/api/v1/sessions/{0}/ixnetwork'.format(str(self.sessionId))
  
          self.get(self.sessionUrl)
  
      def deleteSession(self):
          """
          Description
             Delete the instance session ID. For Linux and Windows Connection Manager only.
          """
          if self.deleteSessionAfterTest:
              self.delete(self.sessionId)
  
      def logInfo(self, msg, end='\n', timestamp=True):
          """
          Description
             An internal function to print info to stdout
  
          Parameters
             msg: (str): The message to print.
          """
          currentTime = self.getTime()
  
          if timestamp:
              msg = '\n' + currentTime + ': ' + msg
          else:
              # No timestamp and no newline are mainly for verifying states and status
              msg = msg
  
          print('{0}'.format(msg), end=end)
          if self.generateLogFile:
              with open(self.restLogFile, 'a') as restLogFile:
                  restLogFile.write(msg+end)
  
          if self.robotFrameworkStdout:
              self.robotStdout.log_to_console(msg)
  
      def logWarning(self, msg, end='\n', timestamp=True):
          """
          Description
             An internal function to print warnings to stdout.
  
          Parameter
             msg: (str): The message to print.
          """
          currentTime = self.getTime()
  
          if timestamp:
              msg = '\n{0}: Warning: {1}'.format(currentTime, msg)
          else:
              # No timestamp and no newline are mainly for verifying states and status
              msg = msg
  
          print('{0}'.format(msg), end=end)
          if self.generateLogFile:
              with open(self.restLogFile, 'a') as restLogFile:
                  restLogFile.write('Warning: '+msg+end)
  
          if self.robotFrameworkStdout:
              self.robotStdout.log_to_console(msg)
  
      def logError(self, msg, end='\n', timestamp=True):
          """
          Description
             An internal function to print error to stdout.
  
          Parameter
             msg: (str): The message to print.
          """
          currentTime = self.getTime()
  
          if timestamp:
              msg = '\n{0}: Error: {1}'.format(currentTime, msg)
          else:
              # No timestamp and no newline are mainly for verifying states and status
              msg = '\nError: {0}'.format(msg)
  
          print('{0}'.format(msg), end=end)
          if self.generateLogFile:
              with open(self.restLogFile, 'a') as restLogFile:
                  restLogFile.write('Error: '+msg+end)
  
          if self.robotFrameworkStdout:
              self.robotStdout.log_to_console(msg)
  
      def getIxNetworkVersion(self):
          """
          Description
             Get the IxNetwork version.
  
          Syntax
              GET: /api/v1/sessions/{id}/globals
          """
          response = self.get(self.sessionUrl+'/globals', silentMode=True)
          return response.json()['buildNumber']
  
      def getAllSessionId(self):
          """
          Show all opened session IDs.
  
          Return
             A list of opened session IDs.
  
             {4: {'startedOn': '2018-10-06 12:09:18.333-07:00',
                'state': 'Active',
                'subState': 'Ready',
                'userName': 'admin'},
              5: {'startedOn': '2018-10-06 18:49:05.691-07:00',
                'state': 'Active',
                'subState': 'Ready',
                'userName': 'admin'}
             }
          """
          response = self.get(self.httpHeader+'/api/v1/sessions', silentMode=True)
          sessionId = {}
          for eachSessionId in response.json():
              sessionId.update({eachSessionId['id']: {'userName': eachSessionId['userName'],
                                                      'createdOn': eachSessionId['createdOn'].replace('T', ' '),
                                                      'state': eachSessionId['state'],
                                                      'subState': eachSessionId['subState']
                                                  }
                            })
  
              print('\nSessionId: {}'.format(eachSessionId['id']))
              print('   UserName: {}'.format(eachSessionId['userName']))
              print('   StartedOn: {}'.format(eachSessionId['createdOn'].replace('T', ' ')))
              print('   State: {}'.format(eachSessionId['state']))
              print('   SubState: {}'.format(eachSessionId['subState']))
  
          print()
          return sessionId
  
      def showErrorMessage(self, silentMode=False):
          """
          Description
             Show all the error messages from IxNetwork.
  
          Parameter
            silentMode: (bool): True: Don't print the REST API on stdout.
  
          Syntax
              GET: /api/v1/sessions/{id}/globals/appErrors/error
          """
          errorList = []
          response = self.get(self.sessionUrl+'/globals/appErrors/error', silentMode=silentMode)
          print()
          for errorId in response.json():
              if errorId['errorLevel'] == 'kError':
                  print('CurrentErrorMessage: {0}'.format(errorId['name']))
                  print('\tDescription: {0}'.format(errorId['lastModified']))
                  errorList.append(errorId['name'])
          print()
          return errorList
  
      def waitForComplete(self, response='', url='', silentMode=False, ignoreException=False, httpAction='get', timeout=90):
          """
          Description
             Wait for an operation progress to complete.
  
          Parameters
             response: (json response/dict): The POST action response.  Generally, after an /operations action.
                           Such as /operations/startallprotocols, /operations/assignports.
             silentMode: (bool):  If True, display info messages on stdout.
             ignoreException: (bool): ignoreException is for assignPorts.  Don't want to exit test.
                              Verify port connectionStatus for: License Failed and Version Mismatch to report problem immediately.
  
             httpAction: (get|post): Defaults to GET. For chassisMgmt, it uses POST.
             timeout: (int): The time allowed to wait for success completion in seconds.
          """
          if silentMode == False:
              self.logInfo('\nwaitForComplete:', timestamp=False)
              self.logInfo("\tState: %s " % response.json()["state"], timestamp=False)
  
          if response.json() == []:
              raise IxNetRestApiException('waitForComplete: response is empty.')
  
          if response.json() == '' or response.json()['state'] == 'SUCCESS':
              return response
  
          if 'errors' in response.json():
              raise IxNetRestApiException(response.json()["errors"][0])
  
          if response.json()['state'] in ["ERROR", "EXCEPTION"]:
              raise IxNetRestApiException('WaitForComplete: STATE=%s: %s' % (response.json()['state'], response.text))
  
          for counter in range(1,timeout+1):
              if httpAction == 'get':
                  response = self.get(url, silentMode=True)
              if httpAction == 'post':
                  response = self.post(url, silentMode=True)
  
              state = response.json()["state"]
              if silentMode == False:
                  if state != 'SUCCESS':
                      self.logInfo("\tState: {0}: Wait {1}/{2} seconds".format(state, counter, timeout), timestamp=False)
                  if state == 'SUCCESS':
                      self.logInfo("\tState: {0}".format(state), timestamp=False)
  
              if counter < timeout and state in ["IN_PROGRESS", "down"]:
                  time.sleep(1)
                  continue
  
              if counter < timeout and state in ["ERROR", "EXCEPTION"]:
                  # ignoreException is for assignPorts.  Don't want to exit test.
                  # Verify port connectionStatus for: License Failed and Version Mismatch to report problem immediately.
                  if ignoreException:
                      return response
                  raise IxNetRestApiException(response.text)
  
              if counter < timeout and state == 'SUCCESS':
                  return response
  
              if counter == timeout and state != 'SUCCESS':
                  if ignoreException:
                      return response
                  raise IxNetRestApiException('waitForComplete failed: %s' % response.json())
  
      def connectToLinuxIxosChassis(self, chassisIp, username, password):
          url = 'https://{0}/platform/api/v1/auth/session'.format(chassisIp)
          response = self.post(url, data={'username': username, 'password': password})
          self.apiKey = response.json()['apiKey']
          self.jsonHeader = {'content-type': 'application/json', 'x-api-key': self.apiKey}
  
          # userAccountUrl: https://{ip}/platform/api/v1/auth/users/{id}
          self.userSessionId = response.json()['userAccountUrl']
  
          self.ixosHeader = 'https://{0}/chassis/api/v2/ixos'.format(chassisIp)
          self.chassisPlatformHeader = 'https://{0}/platform/api/v2'.format(chassisIp)
          self.diagnosticsHeader = 'https://{0}/chassis/api/v1/diagnostics'.format(chassisIp)
          self.authenticationHeader = 'https://{0}/chassis/api/v1/auth'.format(chassisIp)
          self.sessionUrl = self.ixosHeader
  
      def connectToLinuxApiServer(self, linuxServerIp, linuxServerIpPort, username='admin', password='admin', verifySslCert=False, timeout=120):
          """
          Description
             Connect to a Linux API server.
  
          Parameters
             linuxServerIp: (str): The Linux API server IP address.
             username: (str): Login username. Default = admin.
             password: (str): Login password. Default = admin.
             verifySslCert: (str): Default: None.  The SSL Certificate for secure access verification.
             timeout: (int): Default:120.  The timeout to wait for the Linux API server to start up.
                             Problem: In case the linux api server is installed in a chassis and the DNS is misconfigured,
                                      it takes longer to start up.
  
         Syntax
              POST: /api/v1/auth/session
          """
          self.verifySslCert = verifySslCert
  
          if self.apiKey is None:
              # 1: Connect to the Linux API server
              url = 'https://{0}:{1}/api/v1/auth/session'.format(linuxServerIp, linuxServerIpPort)
              self.logInfo('connectToLinuxApiServer: %s' % url)
              response = self.post(url, data={'username': username, 'password': password}, ignoreError=True)
              if not str(response.status_code).startswith('2'):
                  raise IxNetRestApiException('\nLogin username/password failed\n')
              self.apiKey = response.json()['apiKey']
  
              url = 'https://{0}:{1}/api/v1/sessions'.format(linuxServerIp, linuxServerIpPort)
              if self.webQuickTest == False:
                  data = {'applicationType': 'ixnrest'}
              if self.webQuickTest == True:
                  data = {'applicationType': 'ixnetwork'}
  
              self.jsonHeader = {'content-type': 'application/json', 'x-api-key': self.apiKey}
              self.logInfo('linuxServerCreateSession')
              response = self.post(url, data=data, headers=self.jsonHeader)
  
              self.sessionIdNumber = response.json()['id']
              response = self.get(url+'/'+str(self.sessionIdNumber))
  
              # https://192.168.70.108/ixnetworkweb/api/v1/sessions/7
              self.sessionId = response.json()['links'][0]['href']
              # Remove the redirect /ixnetworkweb from the URL. IxNetwork 8.50 will resolve this.
              self.sessionId = self.sessionId.replace('ixnetworkweb/', '')
  
              # https://10.10.10.1:443
              matchHeader = re.match('(https://[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(:[0-9]+)?)', self.sessionId)
              self.httpHeader = matchHeader.group(1)
  
              if ':' not in self.httpHeader:
                  self.httpHeader + '/' + linuxServerIpPort
  
              self.sessionUrl = self.sessionId+'/ixnetwork'
  
              # /api/v1/sessions/4/ixnetwork
              match = re.match('.*(/api.*)', self.sessionId)
              self.apiSessionId = match.group(1) + '/ixnetwork'
  
              # 3: Start the new session
              response = self.post(self.sessionId+'/operations/start')
              if self.linuxServerWaitForSuccess(response.json()['url'], timeout=timeout) == 1:
                  raise IxNetRestApiException
  
              if self.webQuickTest == True:
                  self.sessionId = 'https://{0}/ixnetworkweb/api/v1/sessions/{1}'.format(linuxServerIp, self.sessionIdNumber)
                  self.sessionUrl = 'https://{0}/ixnetworkweb/api/v1/sessions/{1}/ixnetwork'.format(linuxServerIp, self.sessionIdNumber)
                  self.httpHeader = self.sessionUrl.split('/api')[0]
  
          # If an API-Key is provided, then verify the session ID connection.
          if self.apiKey:
              self.get(self.sessionId)
  
      def linuxServerGetGlobalLicense(self, linuxServerIp):
          """
          Description
             Get the global license server details from the Linux API server.
  
          Paramters
             linuxServerIp: (str): The IP address of the Linux API server.
  
          Syntax
              GET: /api/v1/sessions/9999/ixnetworkglobals/license
          """
          staticUrl = 'https://{linuxServerIp}/api/v1/sessions/9999/ixnetworkglobals/license'.format(linuxServerIp=linuxServerIp)
          self.logInfo('linuxServerGetGlobalLicense: %s ' % linuxServerIp)
          response = self.get(staticUrl, silentMode=False)
          licenseServerIp = response.json()['servers'][0]
          licenseServerMode = response.json()['mode']
          licenseServerTier = response.json()['tier']
          self.logInfo('linuxServerGetGlobalLicenses:')
          self.logInfo('\t%s' % licenseServerIp)
          self.logInfo('\t%s' % licenseServerMode)
          self.logInfo('\t%s' % licenseServerTier)
          return licenseServerIp,licenseServerMode,licenseServerTier
  
      def configLicenseServerDetails(self, licenseServer=None, licenseMode=None, licenseTier=None):
          """
          Description
             Configure license server details: license server IP, license mode and license tier.
  
          Parameters
             licenseServer: (str): License server IP address(s) in a list.
             licenseMode: (str): subscription | perpetual | mixed
             licenseTier: (str): tier1 | tier2 | tier3 ...
  
          Syntax
             PATCH: /api/v1/sessions/{id}/ixnetwork/globals/licensing
          """
          # Each new session requires configuring the new session's license details.
          data = {}
          if licenseServer:
              data.update({'licensingServers': licenseServer})
          if licenseMode:
              data.update({'mode': licenseMode})
          if licenseTier:
              data.update({'tier': licenseTier})
  
          response = self.patch(self.sessionUrl+'/globals/licensing', data=data)
          self.showLicenseDetails()
  
      def showLicenseDetails(self):
          """
          Description
             Display the new session's license details.
  
          Syntax
              GET: /api/v1/sessions/{id}/globals/licensing
          """
          response = self.get(self.sessionUrl+'/globals/licensing')
          self.logInfo('\nVerifying sessionId license server: %s' % self.sessionUrl, timestamp=False)
          self.logInfo('\t%s' % response.json()['licensingServers'], timestamp=False)
          self.logInfo('\t%s'%  response.json()['mode'], timestamp=False)
          self.logInfo('\t%s' % response.json()['tier'], timestamp=False)
  
      def getAllOpenSessionIds(self):
          """
          Description
             Get a list of open session IDs and some session metas.
             
          Syntax
              GETE: /api/v1/sessions
  
          Return
              A dict
              
          """
          response = self.get(self.sessionUrl)
          sessionIdDict = {}
          from pprint import pprint
          pprint(response.json())
          return
          for session in response.json():
              href = session['links'][0]['href']
              id = session['id']
              username = session['userName']
              state = session['state']
              createOn = session['createdOn']
  
              sessionIdDict[id] = {'id': id, 'sessionIdUrl': href, 'username': username, 'state': state, 'createdOn': createOn}
  
          return sessionIdDict
  
      def linuxServerStopAndDeleteSession(self):
          """
          Description
             Wrapper to stop and delete the session ID on the Linux API server.
  
          Requirements
             linuxServerStopOperations()
             linuxServerDeleteSession()
  
          Syntax
             GET = /api/v1/sessions/{id}
          """
          if self.serverOs == 'linux' and self.deleteSessionAfterTest==True:
              self.linuxServerStopOperations()
              self.linuxServerDeleteSession()
  
      def linuxServerStopOperations(self, sessionId=None):
          """
          Description
             Stop the session ID on the Linux API server.
  
          Parameter
             sessionId: (str): The session ID to stop.
  
          Requirement
             self.linuxServerWaitForSuccess()
  
          Syntax
              POST: /api/v1/sessions/{id}/operations/stop
          """
          if sessionId != None:
              sessionId = sessionId
          else:
              sessionId = self.sessionId
  
          response = self.post(sessionId+'/operations/stop')
          if self.linuxServerWaitForSuccess(response.json()['url'], timeout=90) == 1:
              raise IxNetRestApiException
  
      def linuxServerDeleteSession(self, sessionId=None):
          """
          Description
             Delete the session ID on the Linux API server.
  
          Paramter
            sessionId: (str): The session ID to delete on the Linux API server.
  
          Syntax
              DELETE: /api/v1/sessions/{id}/operations/stop
          """
          if sessionId != None:
              sessionId = sessionId
          else:
              sessionId = self.sessionId
  
          response = self.delete(sessionId)
  
      def linuxServerWaitForSuccess(self, url, timeout=120):
          """
          Description
             Wait for a success completion on the Linux API server.
  
          Paramters
             url: (str): The URL's ID of the operation to verify.
             timeout: (int): The timeout value.
          """
          data = {'applicationType': 'ixnrest'}
          jsonHeader = {'content-type': 'application/json', 'x-api-key': self.apiKey}
          self.logInfo('linuxServerWaitForSuccess')
          for counter in range(1,timeout+1):
              response = self.get(url, data=data, silentMode=True)
              currentStatus = response.json()['message']
              self.logInfo('\tCurrentStatus: {0}:  {1}/{2} seconds'.format(currentStatus, counter, timeout), timestamp=False)
              if counter < timeout+1 and currentStatus != 'Operation successfully completed':
                  time.sleep(1)
  
              if counter == timeout+1 and currentStatus != 'Operation successfully completed':
                  return 1
  
              if counter < timeout+1 and currentStatus == 'Operation successfully completed':
                  return 0
  
      def newBlankConfig(self):
          """
          Description
             Start a new blank configuration.
  
          Requirement
              self.waitForComplete()
  
          Syntax:
             /api/v1/sessions/{1}/ixnetwork/operations/newconfig
          """
          url = self.sessionUrl+'/operations/newconfig'
          response = self.post(url)
          url = self.sessionUrl+'/operations/newconfig/'+response.json()['id']
          self.waitForComplete(response, url)
  
      def refreshHardware(self, chassisObj):
          """
          Description
             Refresh the chassis
  
          Parameter
             chassisObj: (str):The chassis object.
                             Ex: /api/v1/sessions/{1}/ixnetwork/availableHardware/chassis/1
  
          Requirement
             self.waitForComplete()
  
          Syntax
              /api/v1/sessions/{1}/ixnetwork/availableHardware/chassis/operations/refreshinfo
          """
          response = self.post(self.sessionUrl+'/availableHardware/chassis/operations/refreshinfo', data={'arg1': [chassisObj]})
          self.waitForComplete(response, self.sessionUrl+'/availableHardware/chassis/operations/refreshinfo')
  
      def query(self, data, silentMode=False):
          """
          Description
             Query for objects using filters.
  
          Paramater
             silentMode: (bool): True: Don't display any output on stdout.
  
          Notes
              Assuming this is a BGP configuration, which has two Topologies.
              Below demonstrates how to query the BGP host object by
              drilling down the Topology by its name and the specific the BGP attributes to modify at the
              BGPIpv4Peer node: flap, downtimeInSec, uptimeInSec.
              The from '/' is the entry point to the API tree.
              Notice all the node. This represents the API tree from the / entry point and starting at
              Topology level to the BGP host level.
  
          Notes
             Use the API Browser tool on the IxNetwork GUI to view the API tree.
              data: {'from': '/',
                      'nodes': [{'node': 'topology',    'properties': ['name'], 'where': [{'property': 'name', 'regex': 'Topo1'}]},
                                {'node': 'deviceGroup', 'properties': [], 'where': []},
                                {'node': 'ethernet',    'properties': [], 'where': []},
                                {'node': 'ipv4',        'properties': [], 'where': []},
                                {'node': 'bgpIpv4Peer', 'properties': ['flap', 'downtimeInSec', 'uptimeInSec'], 'where': []}]
                  }
  
          Requirements
              self.waitForComplete()
  
          Examples
              response = restObj.query(data=queryData)
              bgpHostAttributes = response.json()['result'][0]['topology'][0]['deviceGroup'][0]['ethernet'][0]['ipv4'][0]['bgpIpv4Peer'][0]
  
              # GET THE BGP ATTRIBUTES TO MODIFY
              bgpHostFlapMultivalue = bgpHostAttributes['flap']
              bgpHostFlapUpTimeMultivalue = bgpHostAttributes['uptimeInSec']
              bgpHostFlapDownTimeMultivalue = bgpHostAttributes['downtimeInSec']
  
              restObj.configMultivalue(bgpHostFlapMultivalue, multivalueType='valueList', data={'values': ['true', 'true']})
              restObj.configMultivalue(bgpHostFlapUpTimeMultivalue, multivalueType='singleValue', data={'value': '60'})
              restObj.configMultivalue(bgpHostFlapDownTimeMultivalue, multivalueType='singleValue', data={'value': '30'})
          """
          url = self.sessionUrl+'/operations/query'
          reformattedData = {'selects': [data]}
          response = self.post(url, data=reformattedData, silentMode=silentMode)
          self.waitForComplete(response, url+'/'+response.json()['id'], silentMode=silentMode)
          return response
  
      def configMultivalue(self, multivalueUrl, multivalueType, data):
          """
          Description
             Configure multivalues.
  
          Parameters
             multivalueUrl: (str): The multivalue: /api/v1/sessions/{1}/ixnetwork/multivalue/1
             multivalueType: (str): counter|singleValue|valueList
             data: (dict): singleValue: data={'value': '1.1.1.1'})
                               valueList:   data needs to be in a [list]:  data={'values': [list]}
                               counter:     data={'start': value, 'direction': increment|decrement, 'step': value}
          """
          if multivalueType == 'counter':
              # Examples: macAddress = {'start': '00:01:01:00:00:01', 'direction': 'increment', 'step': '00:00:00:00:00:01'}
              #          data=macAddress)
              self.patch(self.httpHeader+multivalueUrl+'/counter', data=data)
  
          if multivalueType == 'singleValue':
              # data={'value': value}
              self.patch(self.httpHeader+multivalueUrl+'/singleValue', data=data)
  
          if multivalueType == 'valueList':
              # data={'values': ['item1', 'item2']}
              self.patch(self.httpHeader+multivalueUrl+'/valueList', data=data)
  
      def getMultivalueValues(self, multivalueObj, silentMode=False):
          """
          Description
             Get the multivalue values.
  
          Parameters
             multivalueObj: (str): The multivalue object: /api/v1/sessions/{1}/ixnetwork/multivalue/208
             silentMode: (bool): True=Display the GET and status code. False=Don't display.
  
          Requirements
             self.waitForComplete()
          """
          response = self.get(self.httpHeader+multivalueObj+'?includes=count', silentMode=silentMode)
          count = response.json()['count']
          if silentMode == False:
              self.logInfo('getMultivalueValues: {0} Count={1}'.format(multivalueObj, count))
          data = {'arg1': multivalueObj,
                  'arg2': 0,
                  'arg3': count
                  }
          response = self.post(self.sessionUrl+'/multivalue/operations/getValues', data=data, silentMode=silentMode)
          self.waitForComplete(response, self.sessionUrl+'/operations/multivalue/getValues'+response.json()['id'])
          return response.json()['result']
  
      def getObjAttributeValue(self, obj, attribute):
          """
          Description
             Based on the object handle, get any property attribute and return the value.
  
          Parameter
             obj: <str:obj>: An object handle:
                  For example: If you want the ethernet MTU, then pass in the ethernet object handle:
                              /api/v1/sessions/{id}/ixnetwork/topology/{id}/deviceGroup/{id}/ethernet/{id}
                              and set attribute='mtu'
  
          Note:
             Where to get the object's attribute names:
                - Use the API browser and go to your object.
                - All the attributes are listed on the right pane.
          """
          response = self.get(self.httpHeader + obj)
  
          # value: Could be /api/v1/sessions/{id}/ixnetwork/multivalue/{id} or the actual value
          value = response.json()[attribute]
          if type(value) == str and 'multivalue' in value:
              multivalueObj = value
              value = self.getMultivalueValues(multivalueObj)
              return value
          else:
              return value
  
      def stdoutRedirect(self):
          """
          Description
             For Robot Framework.  Robot captures the stdout. This stdoutRedirect
             will redirect the output back to stdout so you could see the test progress
             and to troubleshoot.
          """
          for attr in ('stdin', 'stdout', 'stderr'):
              setattr(sys, attr, getattr(sys, '__%s__' %attr))
  
      @staticmethod
      def prettyprintAllOperations(sessionUrl):
          """
          Description
             A staticmethod to rendering a nice output of an operations options and descriptions.
  
          Parameter
             sessionUrl: (str): http://{apiServerIp}:{port}/api/v1/sessions/1/ixnetwork
  
          Syntax:
              /api/v1/sessions/{1}/ixnetwork/operations
          """
          response = self._session.request('GET', sessionUrl+'/operations')
          for item in response.json():
              if 'operation' in item.keys():
                  print('\n', item['operation'])
                  print('\t%s' % item['description'])
                  if 'args' in item.keys():
                      for nestedKey,nestedValue in item['args'][0].items():
                          print('\t\t%s: %s' % (nestedKey, nestedValue))
  
      @staticmethod
      def printDict(obj, nested_level=0, output=sys.stdout):
          """
          Description
             Print each dict key with indentions for human readability.
          """
          spacing = '   '
          spacing2 = ' '
          if type(obj) == dict:
              print( '%s' % ((nested_level) * spacing), file=output)
              for k, v in obj.items():
                  if hasattr(v, '__iter__'):
                      print('%s%s:' % ( (nested_level+1) * spacing, k), file=output, end='')
                      IxNetRestMain.printDict(v, nested_level+1, output)
                  else:
                      print('%s%s: %s' % ( (nested_level + 1) * spacing, k, v), file=output)
  
              print('%s' % (nested_level * spacing), file=output)
          elif type(obj) == list:
              print('%s[' % ((nested_level) * spacing), file=output)
              for v in obj:
                  if hasattr(v, '__iter__'):
                      IxNetRestMain.printDict(v, nested_level + 1, file=output)
                  else:
                      print('%s%s' % ((nested_level + 1) * spacing, v), file=output)
              print('%s]' % ((nested_level) * spacing), output)
          else:
              print('%s%s' % ((nested_level * spacing2), obj), file=output)
  
      def placeholder():
          pass
  
  
  