Tutorial 3: Python objects representing HMC resources

This tutorial explains how the zhmcclient package maps the HMC operations and the resources exposed by the HMC to Python objects, and how to navigate between these objects. This tutorial mostly uses the CPC and its partitions as example resources, but the same principles apply to nearly all types of resources exposed by the HMC.

In order to keep the code in these tutorials simple, the creation of the Session and Client objects has been moved into a function make_client() in a utility module tututils.

The following code section creates a logged-on client for the specified HMC. When invoked for the first time in a notebook, make_client() asks for userid and password and saves that in the module. On subsequent invocations (within the same notebook), it uses the saved userid and password.

In [ ]:
import tututils
zhmc = '9.152.150.65'  # edit this to your HMC's IP address or host name
user = 'ensadmin'      # edit this to the userid on that HMC
client = tututils.make_client(zhmc, user)

In the zhmcclient package, all resources exposed by the HMC are encapsulated as Python objects. The following code section lists the CPCs managed by the HMC and examines the first Cpc object in the list:

In [ ]:
from pprint import pprint
cpcs = client.cpcs.list()
cpc = cpcs[0]
print(type(cpc))
print("Public symbols:")
pprint([s for s in sorted(dir(cpc)) if not s.startswith('_')])
print("Resource properties:")
pprint(cpc.properties)

The public symbols are (Python) properties or methods and are described in the zhmcclient documentation (see Cpc).

This Cpc object has only three resource properties: name, object-uri, and status. The zhmcclient package provides these resource properties as a dictionary in the properties instance variable of the Cpc object. The names of these resource properties are unchanged from what the HMC API book defines. The zhmcclient documentation refers to the HMC API book for a list and description of the resource properties.

The list() method only returned these three resource properties, but a CPC resource has many more properties. In the HMC API, list operations generally return only a small set of the most important properties, mostly for identification and status of the resource.

The following code retrieves the full set of resource properties for that CPC and prints them:

In [ ]:
cpc.pull_full_properties()
print("Properties:")
pprint(cpc.properties)

Because of this behavior, a Python object representing a resource may not always have all properties of the resource present. The get_property() method allows accessing a specific named property, and retrieves it from the HMC if not currently present in the Python object.

The following code section again lists the CPCs, creating a Cpc object with only three resource properties. The get_property() method is then used to access a property that is not among the initial three properties. This causes all resource properties to be retrieved from the HMC and stored in the Cpc object. The requested one is returned from the method:

In [ ]:
cpcs = client.cpcs.list()
cpc = cpcs[0]
print("Cpc object returned by list() has {} properties".format(len(cpc.properties)))

print("Accessing a property that is not yet present ...")
machine_type = cpc.get_property('machine-type')
print("CPC machine type: {}".format(machine_type))
print("After retrieving machine-type, the Cpc object has {} properties".format(len(cpc.properties)))

The Cpc object knows that it now has the full set of resource properties, so it uses them without further communication with the HMC:

In [ ]:
print("CPC machine model: {}".format(cpc.get_property('machine-model')))

Accessing invalid resource properties (i.e. properties not described in the HMC API book for the resource) causes a KeyError exception to be raised:

In [ ]:
try:
    print("CPC foo: {}".format(cpc.get_property('foo')))
except Exception as exc:
    print("{}: {}".format(exc.__class__.__name__, exc))

The prop() method returns a resource property value and allows specifying a default value in case the property is invalid:

In [ ]:
print("CPC foo: {}".format(cpc.prop('foo', 'invalid')))

The resources in the HMC are organized as a tree. The zhmcclient package reflects that in the organization of the Python objects representing these resources. The top-level object is Client which represents the HMC. It allows navigating to the CPCs managed by the HMC via its cpcs property.

Each Python object representing a resource allows navigating down to its child resources, and each child resource allows navigating up to its parent resource. For example, a Cpc object represents a CPC, and its lpars instance variable allows navigating to the LPARs of the CPC, represented by Lpar objects. An Lpar object allows navigating up to its parent Cpc object via the generic manager.parent instance variable, and also via the specific manager.cpc instance variable that is named according to the type of parent.

The following code navigates from a Cpc object to its partitions (Lpar or Partition dependent on the CPC mode) and navigates back up from the first partition to its parent resource, which is the same Cpc Python object we started from:

In [ ]:
# We use the cpc object from above
print("CPC: name={}, Python object id={}".format(cpc.prop('name'), id(cpc)))

if cpc.dpm_enabled:
    parts = cpc.partitions.list()
else:
    parts = cpc.lpars.list()
part = parts[0]
kind = part.__class__.__name__

print("Found {} partitions ({} child resources)".format(len(parts), kind))
print("First {}: name={}, Python object id={}".format(kind, part.prop('name'), id(part)))

p_cpc = part.manager.cpc
print("Parent CPC: name={}, Python object id={}".format(p_cpc.prop('name'), id(p_cpc)))
print("Same Cpc Python objects: {}".format(cpc is p_cpc))

The find() method retrieves a resource by specifying the value of one (or more) of its properties.

The following code finds the CPC we already know, based upon its name:

In [ ]:
cpc_name = cpc.prop('name')  # could also have been specified as input

print("Finding CPC by name={} ...".format(cpc_name))
cpc2 = client.cpcs.find(name=cpc_name)

print("Found CPC: name={}, Python object id={}".format(cpc2.prop('name'), id(cpc2)))
print("Same Cpc Python objects: {}".format(cpc is cpc2))

Note that the found Cpc Python object is not the same as the original Cpc Python object. These two Python objects represent the same CPC resource, but their state may be different (e.g. different resource properties present, properties obtained at different points in time, etc.).

You generally cannot rely that the zhmcclient API always returns the same Python object for a specific HMC resource. The zhmcclient package tries to minimize the use of different objects (as we saw in the case of navigating back to the parent resource), but sometimes it cannot be avoided to return multiple Python objects for the same resource. The zhmcclient is a very thin client that abstracts the HMC API into a Python API without adding things like a shared resource cache.