This example illustrates several basic operations needed to implement a client that uses the JSON protocol.

import json
from pprint import pprint

domain = 'vcenter.example.com'
credentials = {'userName': '[email protected]', 'password': 'betyoucantguess'}
dc_name = 'DC-1'

def make_url(vc, ver='8.0.1.0', mo='ServiceInstance/ServiceInstance', m_p='content'):
  if isinstance(mo, dict):
    mo = '{}/{}'.format(mo['type'], mo['value'])
  url = 'https://{}/sdk/vim25/{}/{}/{}'.format(vc, ver, mo, m_p)
  return url

def send_request(url, headers=None, body=None):
  from urllib.request import urlopen, Request
  import ssl
  if headers is None: headers = {}
  headers['Content-Type'] = 'application/json'
  # Skip certificate verification on test systems only:
  unverified_context = ssl._create_unverified_context()
  request = Request(url, headers=headers or {}, data=body)
  with urlopen( request, context=unverified_context ) as response :
    response_headers = response.headers
    response_body = response.read()
  return( response_headers, response_body )

def get_service_content(vc):
  url = make_url(vc)
  (response_headers, response_body) = send_request(url)
  json_body = json.loads( response_body )
  return( json_body )

def basic_auth(domain, credentials):
  si_content = get_service_content(domain)
  moref = si_content['sessionManager']
  method = 'Login'
  url = make_url(domain, mo=moref, m_p=method)
  request_headers = {}
  request_headers['Content-Type'] = 'application/json'
  request_body = json.dumps(credentials).encode('utf-8')
  (response_headers, response_body) = send_request(url, headers=request_headers, body=request_body)
  print('Response:')
  print(response_headers)
  print(json.loads(response_body))
  token = response_headers['vmware-api-session-id']
  return(token)

def logout(domain, session_moref) :
  request_body = {}
  method = 'Logout'
  url = make_url(domain, mo=session_moref, m_p=method)
  request_headers = {}
  request_headers['vmware-api-session-id'] = token
  request_headers['Content-Type'] = 'application/json'
  (response_headers, response_body) = send_request(url, headers=request_headers, body=request_body)
  return(response_headers)

def get_datacenter_moref(domain, dc_name, token):
  si_content = get_service_content(domain)
  moref = si_content['searchIndex']
  method = 'FindByInventoryPath'
  url = make_url(domain, mo=moref, m_p=method)
  body_dict = {'inventoryPath': dc_name}
  request_body = json.dumps(body_dict).encode('utf-8')
  request_headers = {}
  request_headers['vmware-api-session-id'] = token
  request_headers['Content-Type'] = 'application/json'
  (response_headers, response_body) = send_request(url, headers=request_headers, body=request_body)
  json_body = json.loads(response_body)
  return(json_body)
 
def get_vm_power_states(domain, dc_moref, token):
  # MO type & properties to retrieve.
  propSet = [ {'_typeName': 'PropertySpec', 
               'type': 'VirtualMachine', 'pathSet': ['runtime.powerState'], 'all': False}]
  # Work backwards to define the steps in the traversal path.
  # traversalspec = type to traverse, path out, skip next?, (selectSet).
  # Traverse any nested folders inside vmFolder:
  traverse_folder = {'_typeName': 'TraversalSpec'}
  traverse_folder['name'] = 'traverse_folder'
  traverse_folder['type'] = 'Folder'
  traverse_folder['path'] = 'childEntity'
  traverse_folder['skip'] = False
  traverse_folder['selectSet'] = [{'_typeName': 'SelectionSpec',
                                   'name': 'traverse_folder'}]
  # Traverse Datacenter to vmFolder:
  dc_to_vmfolder = {'_typeName': 'TraversalSpec'}
  dc_to_vmfolder['name'] = 'dc_to_vmfolder'
  dc_to_vmfolder['type'] = 'Datacenter'
  dc_to_vmfolder['path'] = 'vmFolder'
  dc_to_vmfolder['skip'] = True
  dc_to_vmfolder['selectSet'] = [traverse_folder]
  # objectSet = Starting MO + traversal steps to retrieval objects.
  objectSet = [{'_typeName': 'ObjectSpec',
                'obj': dc_moref, 'skip': False, 
                'selectSet': [dc_to_vmfolder]}]
  # specSet = total filter specification.
  specSet = [{'_typeName': 'PropertyFilterSpec',
              'propSet': propSet, 'objectSet': objectSet}]
  # Params to RetrievePropertiesEx():
  param_dict = {'options': {'_typeName': 'RetrieveOptions',
                            'maxObjects': 1000}, 'specSet': specSet}
  # Build request message.
  request_body = json.dumps(param_dict).encode('utf-8')
  moref = si_content['propertyCollector']
  method = 'RetrievePropertiesEx'
  url = make_url(domain, mo=moref, m_p=method)
  request_headers = {}
  request_headers['vmware-api-session-id'] = token
  request_headers['Content-Type'] = 'application/json'
  (response_headers, response_body) = send_request(url, headers=request_headers, body=request_body)  
  json_body = json.loads(response_body)
  return(json_body)

# MAIN

si_content = get_service_content(domain)
pprint(si_content); print()

token = basic_auth(domain, credentials)
print('Session token: {}'.format(token)); print()

dc_moref = get_datacenter_moref(domain, dc_name, token)
print('{} MOref = {}'.format(dc_name, dc_moref)); print()

response_body = get_vm_power_states(domain, dc_moref, token)
print('Response body:'); pprint(response_body)

moref = si_content['sessionManager']
headers = logout(domain, moref)
print('Logging out:')
print(headers)