~ubuntu-branches/ubuntu/vivid/ceilometer/vivid

« back to all changes in this revision

Viewing changes to ceilometer/hardware/inspector/snmp.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2014-03-06 14:44:28 UTC
  • mto: (28.1.1 utopic-proposed) (1.2.1)
  • mto: This revision was merged to the branch mainline in revision 19.
  • Revision ID: package-import@ubuntu.com-20140306144428-rvphsh4igwyulzf0
Tags: upstream-2014.1~b3
Import upstream version 2014.1~b3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- encoding: utf-8 -*-
 
2
#
 
3
# Copyright © 2014 ZHAW SoE
 
4
#
 
5
# Authors: Lucas Graf <graflu0@students.zhaw.ch>
 
6
#          Toni Zehnder <zehndton@students.zhaw.ch>
 
7
#
 
8
# Licensed under the Apache License, Version 2.0 (the "License"); you may
 
9
# not use this file except in compliance with the License. You may obtain
 
10
# a copy of the License at
 
11
#
 
12
#      http://www.apache.org/licenses/LICENSE-2.0
 
13
#
 
14
# Unless required by applicable law or agreed to in writing, software
 
15
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
16
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
17
# License for the specific language governing permissions and limitations
 
18
# under the License.
 
19
"""Inspector for collecting data over SNMP"""
 
20
 
 
21
import urlparse
 
22
 
 
23
from ceilometer.hardware.inspector import base
 
24
from pysnmp.entity.rfc3413.oneliner import cmdgen
 
25
 
 
26
 
 
27
class SNMPException(Exception):
 
28
    pass
 
29
 
 
30
 
 
31
def parse_snmp_return(ret):
 
32
    """Check the return value of snmp operations
 
33
 
 
34
    :param ret: a tuple of (errorIndication, errorStatus, errorIndex, data)
 
35
                returned by pysnmp
 
36
    :return: a tuple of (err, data)
 
37
             err: True if error found, or False if no error found
 
38
             data: a string of error description if error found, or the
 
39
                   actual return data of the snmp operation
 
40
    """
 
41
    err = True
 
42
    (errIndication, errStatus, errIdx, varBinds) = ret
 
43
    if errIndication:
 
44
        data = errIndication
 
45
    elif errStatus:
 
46
        data = "%s at %s" % (errStatus.prettyPrint(),
 
47
                             errIdx and varBinds[int(errIdx) - 1] or "?")
 
48
    else:
 
49
        err = False
 
50
        data = varBinds
 
51
    return (err, data)
 
52
 
 
53
 
 
54
class SNMPInspector(base.Inspector):
 
55
    #CPU OIDs
 
56
    _cpu_1_min_load_oid = "1.3.6.1.4.1.2021.10.1.3.1"
 
57
    _cpu_5_min_load_oid = "1.3.6.1.4.1.2021.10.1.3.2"
 
58
    _cpu_15_min_load_oid = "1.3.6.1.4.1.2021.10.1.3.3"
 
59
    #Memory OIDs
 
60
    _memory_total_oid = "1.3.6.1.4.1.2021.4.5.0"
 
61
    _memory_used_oid = "1.3.6.1.4.1.2021.4.6.0"
 
62
    #Disk OIDs
 
63
    _disk_index_oid = "1.3.6.1.4.1.2021.9.1.1"
 
64
    _disk_path_oid = "1.3.6.1.4.1.2021.9.1.2"
 
65
    _disk_device_oid = "1.3.6.1.4.1.2021.9.1.3"
 
66
    _disk_size_oid = "1.3.6.1.4.1.2021.9.1.6"
 
67
    _disk_used_oid = "1.3.6.1.4.1.2021.9.1.8"
 
68
    #Network Interface OIDs
 
69
    _interface_index_oid = "1.3.6.1.2.1.2.2.1.1"
 
70
    _interface_name_oid = "1.3.6.1.2.1.2.2.1.2"
 
71
    _interface_bandwidth_oid = "1.3.6.1.2.1.2.2.1.5"
 
72
    _interface_mac_oid = "1.3.6.1.2.1.2.2.1.6"
 
73
    _interface_ip_oid = "1.3.6.1.2.1.4.20.1.2"
 
74
    _interface_received_oid = "1.3.6.1.2.1.2.2.1.10"
 
75
    _interface_transmitted_oid = "1.3.6.1.2.1.2.2.1.16"
 
76
    _interface_error_oid = "1.3.6.1.2.1.2.2.1.20"
 
77
    #Default port and security name
 
78
    _port = 161
 
79
    _security_name = 'public'
 
80
 
 
81
    def __init__(self):
 
82
        super(SNMPInspector, self).__init__()
 
83
        self._cmdGen = cmdgen.CommandGenerator()
 
84
 
 
85
    def _get_or_walk_oid(self, oid, host, get=True):
 
86
        if get:
 
87
            func = self._cmdGen.getCmd
 
88
            ret_func = lambda x: x[0][1]
 
89
        else:
 
90
            func = self._cmdGen.nextCmd
 
91
            ret_func = lambda x: x
 
92
        ret = func(cmdgen.CommunityData(self._get_security_name(host)),
 
93
                   cmdgen.UdpTransportTarget((host.hostname,
 
94
                                              host.port or self._port)),
 
95
                   oid)
 
96
        (error, data) = parse_snmp_return(ret)
 
97
        if error:
 
98
            raise SNMPException("An error occurred, oid %(oid)s, "
 
99
                                "host %(host)s, %(err)s" % dict(oid=oid,
 
100
                                host=host.hostname, err=data))
 
101
        else:
 
102
            return ret_func(data)
 
103
 
 
104
    def _get_value_from_oid(self, oid, host):
 
105
        return self._get_or_walk_oid(oid, host, True)
 
106
 
 
107
    def _walk_oid(self, oid, host):
 
108
        return self._get_or_walk_oid(oid, host, False)
 
109
 
 
110
    def inspect_cpu(self, host):
 
111
        #get 1 minute load
 
112
        cpu_1_min_load = \
 
113
            str(self._get_value_from_oid(self._cpu_1_min_load_oid, host))
 
114
        #get 5 minute load
 
115
        cpu_5_min_load = \
 
116
            str(self._get_value_from_oid(self._cpu_5_min_load_oid, host))
 
117
        #get 15 minute load
 
118
        cpu_15_min_load = \
 
119
            str(self._get_value_from_oid(self._cpu_15_min_load_oid, host))
 
120
 
 
121
        yield base.CPUStats(cpu_1_min=float(cpu_1_min_load),
 
122
                            cpu_5_min=float(cpu_5_min_load),
 
123
                            cpu_15_min=float(cpu_15_min_load))
 
124
 
 
125
    def inspect_memory(self, host):
 
126
        #get total memory
 
127
        total = self._get_value_from_oid(self._memory_total_oid, host)
 
128
        #get used memory
 
129
        used = self._get_value_from_oid(self._memory_used_oid, host)
 
130
 
 
131
        yield base.MemoryStats(total=int(total), used=int(used))
 
132
 
 
133
    def inspect_disk(self, host):
 
134
        disks = self._walk_oid(self._disk_index_oid, host)
 
135
 
 
136
        for disk in disks:
 
137
            for object_name, value in disk:
 
138
                path_oid = "%s.%s" % (self._disk_path_oid, str(value))
 
139
                path = self._get_value_from_oid(path_oid, host)
 
140
                device_oid = "%s.%s" % (self._disk_device_oid, str(value))
 
141
                device = self._get_value_from_oid(device_oid, host)
 
142
                size_oid = "%s.%s" % (self._disk_size_oid, str(value))
 
143
                size = self._get_value_from_oid(size_oid, host)
 
144
                used_oid = "%s.%s" % (self._disk_used_oid, str(value))
 
145
                used = self._get_value_from_oid(used_oid, host)
 
146
 
 
147
                disk = base.Disk(device=str(device),
 
148
                                 path=str(path))
 
149
                stats = base.DiskStats(size=int(size),
 
150
                                       used=int(used))
 
151
 
 
152
                yield (disk, stats)
 
153
 
 
154
    def inspect_network(self, host):
 
155
        net_interfaces = self._walk_oid(self._interface_index_oid, host)
 
156
 
 
157
        for interface in net_interfaces:
 
158
            for object_name, value in interface:
 
159
                ip = self._get_ip_for_interface(host, value)
 
160
                name_oid = "%s.%s" % (self._interface_name_oid,
 
161
                                      str(value))
 
162
                name = self._get_value_from_oid(name_oid, host)
 
163
                mac_oid = "%s.%s" % (self._interface_mac_oid,
 
164
                                     str(value))
 
165
                mac = self._get_value_from_oid(mac_oid, host)
 
166
                bw_oid = "%s.%s" % (self._interface_bandwidth_oid,
 
167
                                    str(value))
 
168
                # bits/s to byte/s
 
169
                bandwidth = self._get_value_from_oid(bw_oid, host) / 8
 
170
                rx_oid = "%s.%s" % (self._interface_received_oid,
 
171
                                    str(value))
 
172
                rx_bytes = self._get_value_from_oid(rx_oid, host)
 
173
                tx_oid = "%s.%s" % (self._interface_transmitted_oid,
 
174
                                    str(value))
 
175
                tx_bytes = self._get_value_from_oid(tx_oid, host)
 
176
                error_oid = "%s.%s" % (self._interface_error_oid,
 
177
                                       str(value))
 
178
                error = self._get_value_from_oid(error_oid, host)
 
179
 
 
180
                adapted_mac = mac.prettyPrint().replace('0x', '')
 
181
                interface = base.Interface(name=str(name),
 
182
                                           mac=adapted_mac,
 
183
                                           ip=str(ip))
 
184
                stats = base.InterfaceStats(bandwidth=int(bandwidth),
 
185
                                            rx_bytes=int(rx_bytes),
 
186
                                            tx_bytes=int(tx_bytes),
 
187
                                            error=int(error))
 
188
                yield (interface, stats)
 
189
 
 
190
    def _get_security_name(self, host):
 
191
        options = urlparse.parse_qs(host.query)
 
192
        return options.get('security_name', [self._security_name])[-1]
 
193
 
 
194
    def _get_ip_for_interface(self, host, interface_id):
 
195
        ip_addresses = self._walk_oid(self._interface_ip_oid, host)
 
196
        for ip in ip_addresses:
 
197
            for name, value in ip:
 
198
                if value == interface_id:
 
199
                    return str(name).replace(self._interface_ip_oid + ".", "")