summaryrefslogtreecommitdiffstats
path: root/src/pcp/lmi/pcp/metric.py
blob: 454f54aee4e2c4da698e59c37c105edfae0c0334 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
"""Python Provider for PCP_Metric_*
Instruments the CIM class family PCP_Metric_*
"""

from pywbem.cim_provider2 import CIMProvider2
import pywbem
from pcp import pmapi
import cpmapi as c_api
import datetime

context = None  # persistent pcp context


# Since we serve a whole slew of PCP_Metric_** subclasses, we can't
# use a straight classname->provider-class dictionary.
#
#def get_providers(env): 
#    return {'PCP_Metric_****': PCP_MetricProvider} 
#
# Instead, we implement the one-hop-higher proxy-level function calls,
# namely the IM_* functions at the bottom.


# Undo mangling done by PCP_pmns2mofreg.sh
def MOFname_to_PCPmetric (op):
    assert (op.namespace == 'root/cimv2')
    assert (op.classname[0:11] == 'PCP_Metric_')
    return op.classname[11:].replace('__', '.')


# Search the given PM_ResultSet for a given instance number (if any);
# return formatted CIM of the value (or CIM None)
def PCP_CIMValueString (context, result, desc, inst):
    for i in range (0,result.contents.get_numval(0)):
        value = result.contents.get_vlist(0,i)
        iv = value.inst
        if (inst is not None and inst != iv):
            continue
        atom = context.pmExtractValue (result.contents.get_valfmt(0),
                                       value,
                                       desc.contents.type,
                                       desc.contents.type)
        atomValue = atom.dref(desc.contents.type) # nb: atomValue could be numeric etc.
        return pywbem.CIMProperty(name='ValueString',
                                  value=str(atomValue), # stringify it here
                                  type='string')

    return pywbem.CIMProperty(name='ValueString',
                              value=None,
                              type='string')


def PCP_CIMStatisticTime (result):
    dt = datetime.datetime.fromtimestamp(float(str(result.contents.timestamp)))
    return pywbem.CIMDateTime(dt)


# generic payload generator, used for
# - iterating across instance domains (keys_only=1)
# - fetching metric values
# - fetching metric metadata (for those model/filter fields set)
def get_instance (env, op, model, keys_only):
    metric = MOFname_to_PCPmetric (op)
    global context

    try:
        if (context == None):
            context = pmapi.pmContext() # localhost or equivalent
        context.pmReconnectContext() # in case it was nuked recently
    except pmapi.pmErr, e:
        context = None
        raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Unable to connect to local PMCD:" + str(e))
        
    pmids = context.pmLookupName(metric)
    pmid = pmids[0]
    desc = context.pmLookupDesc(pmid)

    if ('InstanceID' in model):
        selected_instanceid = model['InstanceID']
    else:
        selected_instanceid = None
    
    model.path.update({'InstanceID':None})

    if (not keys_only):
        model['PMID'] = pywbem.Uint32(pmid)
        model['ElementName'] = metric
        # must not fail, or else we have no metric value data worth sharing
        try:
            results = context.pmFetch(pmids)
        except pmapi.pmErr, e:
            # fatal
            raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "PCP pmFetch failed:" + str(e))
        # cannot fail
        model['Units'] = context.pmUnitsStr(desc.contents.units)
        model['Type'] = context.pmTypeStr(desc.contents.type)
        # these may fail, but not fatally
        try:
            model['Caption'] = context.pmLookupText(pmid)
        except pmapi.pmErr:
            pass
        try:
            model['Description'] = context.pmLookupText(pmid, c_api.PM_TEXT_HELP)
        except pmapi.pmErr:
            pass

    try:
        instL, nameL = context.pmGetInDom(desc)
        for iL, nL in zip(instL, nameL):
            new_instanceid = 'PCP:'+metric+':'+nL
            if (selected_instanceid is None or
                new_instanceid == selected_instanceid):
                model['InstanceNumber'] = pywbem.Uint32(iL)
                model['InstanceName'] = nL
                model['InstanceID'] = new_instanceid
                if (not keys_only):
                    model['StatisticTime'] = PCP_CIMStatisticTime (results)
                    model['ValueString'] = PCP_CIMValueString (context, results, desc, iL)
                yield model
    except pmapi.pmErr: # pmGetInDom is expected to fail for non-instance (PM_INDOM_NULL) metrics 
        new_instanceid = 'PCP:'+metric
        if (selected_instanceid is None or
            new_instanceid == selected_instanceid):
            model['InstanceNumber'] = pywbem.CIMProperty(name='InstanceNumber',
                                                         value=None,type='uint32')
            model['InstanceName'] = pywbem.CIMProperty(name='InstanceName',
                                                       value=None,type='string')
            model['InstanceID'] = new_instanceid
            if (not keys_only):
                model['StatisticTime'] = PCP_CIMStatisticTime (results)
                model['ValueString'] = PCP_CIMValueString (context, results, desc, None)
            yield model
        
# hooks for impersonating CIMProvider2 functions

    
def MI_enumInstanceNames (env, op):
    model = pywbem.CIMInstance(classname = op.classname, path=op)
    for x in get_instance (env, op, model, True):
        yield x.path

def MI_enumInstances (env, op, plist):
    model = pywbem.CIMInstance(classname = op.classname, path=op)
    return get_instance (env, op, model, False)

def MI_getInstance (env, op, plist):
    proplist = None
    if plist is not None:
        proplist = [s.lower() for s in propertyList]
        proplist+= [s.lower() for s in op.keybindings.keys()]
    model = pywbem.CIMInstance(classname=op.classname, path=op,
                               property_list=proplist)
    model.update(model.path.keybindings)
    for x in get_instance (env, op, model, False):
        return x # XXX: first one

def MI_createInstance (env, pinst):
    raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED)

def MI_modifyInstance (env, pinst, plist):
    raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED)

def MI_deleteInstance (env, piname):
    raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED)

# See also extra MI_* functions for associations, etc.;
# cmpi-bindings.git swig/python/cmpi_pywbem_bindings.py