UCS, Python and Racktables

Version 1

    Physical inventory management is always a challenge.    Most people might use spreadsheets.   But spreadsheets don't really scale well, nor do they capture multiple relationships and factors (row, rack, slots, equipment type, network port mgmt, equipment connectivity/relationship, etc...)

     

    A large user of Cisco UCS showed me how they use Racktables : an open-source, community maintained project, founded by people who actively manage very large and growing datacenters of their own.   And it sure made a lot of sense once I saw it firsthand.

     

    If you want to see it firsthand, they have an active online demo that you can actually play with.

     

    I thought this would be a great proof-point for the newly developed UCS Python SDK

    The UCS PowerShell Provider is incredible.   But not everyone is going to look favorably towards Windows-based administration of UCS.

     

    After much constructuve discussion with the RackTables code maintainers, I was able to submit code that allows for the automatic discovery/inventory of UCS domains and would automatically populate the internal Racktables database.   Here you can see the UCS Python source that does the UCS inventory.

     

    It's quite simple.  Focusing on just the relevant snippets, this code first makes sure that the UCS Python SDK is present:

     

    try:

    from UcsSdk import *

    handle = UcsHandle()

    except Exception, err:

    sys.stderr.write('UCS Python SDK is missing\n')

    sys.exit(2)

     

    And then this code walks the 3 physical equipment classes (NetworkElement, EquipmentChassis, ComputeBlade) to print out the attributes needed by the Racktables database:

     

    print "COLUMNS type,serial,DN,model,OOB"

    for mo in handle.GetManagedObject(None, NetworkElement.ClassId()):

    print "ROW NetworkElement,"   + mo.Serial + "," + mo.Dn + "," + mo.Model + "," +mo.OobIfIp

    print "COLUMNS type,serial,DN,model"

    for ch in handle.GetManagedObject(None, EquipmentChassis.ClassId()):

    print "ROW EquipmentChassis," + ch.Serial + "," + ch.Dn + "," + ch.Model

    print "COLUMNS type,serial,DN,model,assigned,slot"

    for bl in handle.GetManagedObject(None, ComputeBlade.ClassId()):

    print "ROW ComputeBlade,"     + bl.Serial + "," + bl.Dn + "," + bl.Model + "," +bl.AssignedToDn + "," + bl.SlotId

     

    For those interested in exploring more, the Racktables Wiki has all the documentation/guides you'd need to get started.

    And for integrating the UCS aspect,  I did a write-up on the UCS Blogs:

     

    Managing datacenter inventory, location, addresses and relationships can be painful.   That's why I use RackTables in my own lab now.   Hopefully, this might make life easier for you and/or your customers.

     

    -------------------------------------------------------------------------------------------------------------------------------------

     

    The above example, though, may create more questions than answers: 

      • "What are the other available methods, besides 'GetManagedObject'?"
      • "What are the other available classes, besides the ones shown above?"
      • "And how do I find the attributes/properties for any given object"

     

    Well as first step, you might want to read the most-excellent UCS Python User Guide

    What's most different about the UCS Python tool (than the UCS PowerTool) is that you need to know the actual names of managed objects and classes.    The PowerTool essentially provided a cmdlet for each object.   Not so for Python.  To use the UCS Python tool, you need more familiarity with the UCS Managed Object Model.

     

    In the UCS Python tool, the most common methods you'll likely use are{Get/Set/Add/Remove}ManagedObject().   So what classes of objects are available as arguments?

     

    Just take a look at the UCS Python source code.

     

    The UCS Python source code is "code generated" from the same UCS Managed Object Model that's used to generate most of the UCSM data-management-engine (DME), the GUI, the CLI, and the UCS PowerTool.    So just take a look at the Mos.py file and you'll see managed objects and attributes, such as :

     

    class IppoolPool(ManagedObject):

            def __init__(self):

                    ManagedObject.__init__(self,"IppoolPool")


            @staticmethod

            def ClassId():

                    return "ippoolPool"

     

            ASSIGNED = "Assigned"

            DESCR = "Descr"

            DN = "Dn"

            NAME = "Name"

            RN = "Rn"

            SIZE = "Size"

            STATUS = "Status"


    And if you want to see the list of all classes :

     

    [root]# grep "class.*ManagedObject" Mos.py | more

    class EquipmentLocalDiskControllerCapRef(ManagedObject):

    class FabricChassisEp(ManagedObject):

    class MacpoolPool(ManagedObject):

    class ExtmgmtArpTargets(ManagedObject):

    class SyntheticFile(ManagedObject):

    class AaaPreLoginBanner(ManagedObject):

    class VmEp(ManagedObject):

    class ProcessorEnvStats(ManagedObject):

    class AdaptorHostEthIfProfile(ManagedObject):

    class ComputePoolable(ManagedObject):

    [...]


     

    But let's say you were discovering an object, and dynamically resolving all its child objects as well.   Do you have to consult the source code everytime you want to know an object's attributes?    No, not all.    Taking advantage of the UcsUtils().GetUcsPropertyMetaAttributeList(classname)method will return a list of all attributes for a given object class.    Some of the properties might be "internal" or "read-only", but these can be identified withUcsUtils().GetUcsPropertyMeta(classname, prop).   Attributes can then be displayed for any given managed object with the objects gettattr(val) method, as in the following example:

       

    #! /usr/local/bin/python

    #

    # sh_attrs : Given an Object class and an MO, display all attributes and values

    #

     

    import sys

    import re

    from UcsSdk import *

    from local_creds import *

     

    if (len(sys.argv) != 3):

    print "Usage: sh_attrs class mo"

    sys.exit()

     

    classname = sys.argv[1]

    Dn = sys.argv[2]

     

    try:

              handle = UcsHandle()

              handle.Login(ucsm_ip, user, password)

              mo = None

     

              rdn = handle.ConfigResolveDn(Dn, False, None)

              if (rdn != None):

          for l in rdn.OutConfig.GetChild():

      mo = l

     

              props = UcsUtils().GetUcsPropertyMetaAttributeList(classname)

              for prop in props:

              tstr = ""

              if prop == "Meta":

          continue

              propMeta = UcsUtils().GetUcsPropertyMeta(classname, prop)

              if (propMeta.access == UcsPropertyMeta.Internal):

          continue

              if (propMeta.access == UcsPropertyMeta.ReadOnly):

          continue

              tstr = tstr + prop + " : "

              if (mo != None):

          val = mo.getattr(prop)

              if (val != None and val != ""):

          tstr = tstr + val

              print tstr

     

    except Exception, err:

        print "Exception:", str(err)

        import traceback, sys

        print '-'*60

        traceback.print_exc(file=sys.stdout)

        print '-'*60

     

    ---------------------------------------------------------------------------------------------------------------------------------------

     

    Now let's take it one step further.   What if the real problem is identifying the internal managed objects that correspond to familiar activities, such as creating boot-policies, or managing objects through the GUI?   UCS PowerTool has this terrific capability to capture actions from the GUI and translate them in to the corresponding UCS PowerTool commands.   Well the 1.0 version of PowerTool goes even further and lets you translate actions in to the corresponding UCS Pythoncommands(!).    Wow!    So for example, if I wanted to create a SAN-Boot Policy, which is a multi-stage transaction, then issuing this PowerTool command before creating the Boot Policy in the GUI:

     

    PS C:\> ConvertTo-UcsCmdlet -python


    will give the corresponding Python code on output:

     

    handle.StartTransaction()

    obj = handle.GetManagedObject(None, None, {"Dn":"org-root"})

    mo = handle.AddManagedObject(obj, "lsbootPolicy", {"Name":"SanBoot",

    "PolicyOwner":"local", "RebootOnUpdate":"no", "Descr":"",

    "Dn":"org-root/boot-policy-SanBoot", "EnforceVnicName":"yes"})

    mo_1 = handle.AddManagedObject(mo, "lsbootLan",

    {"Dn":"org-root/boot-policy-SanBoot/lan", "Prot":"pxe", "Order":"3"}, True)

    mo_1_1 = handle.AddManagedObject(mo_1, "lsbootLanImagePath",

    {"ImgSecPolicyName":"", "BootIpPolicyName":"", "ISCSIVnicName":"",

    "Dn":"org-root/boot-policy-SanBoot/lan/path-primary",

    "ProvSrvPolicyName":"", "ImgPolicyName":"", "Type":"primary", "VnicName":"eth0"})

    mo_2 = handle.AddManagedObject(mo, "lsbootVirtualMedia",

    {"Dn":"org-root/boot-policy-SanBoot/read-only-vm", "Access":"read-only", "Order":"1"})

    mo_3 = handle.AddManagedObject(mo, "lsbootStorage",

    {"Dn":"org-root/boot-policy-SanBoot/storage", "Order":"2"}, True)

    mo_3_1 = handle.AddManagedObject(mo_3, "lsbootSanImage",

    {"Dn":"org-root/boot-policy-SanBoot/storage/san-primary", "VnicName":"fc0", "Type":"primary"})

    mo_3_1_1 = handle.AddManagedObject(mo_3_1, "lsbootSanImagePath",

    {"Lun":"0", "Wwn":"50:08:99:78:DE:AD:BE:EF",

    "Dn":"org-root/boot-policy-SanBoot/storage/san-primary/path-primary", "Type":"primary"})

    mo_3_1_2 = handle.AddManagedObject(mo_3_1, "lsbootSanImagePath",

    {"Lun":"0", "Wwn":"50:08:99:99:88:77:66:55",

    "Dn":"org-root/boot-policy-SanBoot/storage/san-primary/path-secondary", "Type":"secondary"})

    handle.CompleteTransaction()

     


    I live and breath this stuff everyday.  But even sometimes it's hard for me to contain my enthusiasm!   Is this cool or what?