├── .github └── workflows │ └── build-and-publish.yaml ├── .gitlab-ci.yml ├── COPYING ├── Dockerfile ├── README.md └── msa_exporter.py /.github/workflows/build-and-publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish Docker image 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | push_to_registry: 9 | name: Push Docker image to Docker Hub 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check out the repo 13 | uses: actions/checkout@v3 14 | 15 | - name: Log in to Docker Hub 16 | uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a 17 | with: 18 | username: ${{ secrets.DOCKER_USERNAME }} 19 | password: ${{ secrets.DOCKER_PASSWORD }} 20 | 21 | - name: Extract metadata (tags, labels) for Docker 22 | id: meta 23 | uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 24 | with: 25 | images: enix/hpmsa_exporter 26 | 27 | - name: Build and push Docker image 28 | uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 29 | with: 30 | context: . 31 | file: ./Dockerfile 32 | push: true 33 | tags: ${{ steps.meta.outputs.tags }} 34 | # labels: ${{ steps.meta.outputs.labels }} 35 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: docker:20.10 2 | 3 | before_script: 4 | - docker info 5 | 6 | build: 7 | stage: build 8 | script: 9 | - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN docker-registry.enix.io 10 | - docker build -t docker-registry.enix.io/docker/msa-exporter . 11 | - docker push docker-registry.enix.io/docker/msa-exporter:latest 12 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright 2018 © Enix SAS 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | The Software is provided "as is", without warranty of any kind, express or 14 | implied, including but not limited to the warranties of merchantability, 15 | fitness for a particular purpose and noninfringement. In no event shall the 16 | authors or copyright holders be liable for any claim, damages or other 17 | liability, whether in an action of contract, tort or otherwise, arising from, 18 | out of or in connection with the software or the use or other dealings in the 19 | Software. 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | MAINTAINER Antoine Millet 3 | 4 | RUN apt update && apt install -y python3-lxml python3-prometheus-client python3-requests 5 | COPY msa_exporter.py /bin/msa_exporter 6 | RUN chmod +x /bin/msa_exporter 7 | 8 | EXPOSE 8000 9 | CMD /bin/msa_exporter "$HOST" "$LOGIN" "$PASSWORD" 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HP MSA exporter 2 | 3 | A prometheus exporter for the HP MSA Storage SAN. 4 | 5 | ## Usage 6 | 7 | ./msa_exporter.py --port 8000 --interval 60 msa_san_hostname msa_san_username msa_san_password 8 | 9 | ## Metrics 10 | 11 | This exporter exposes the following metrics: 12 | 13 | | Name | Description | Labels | 14 | |---------------------------------------|----------------------------|------------------------------| 15 | | msa_hostport_data_read | Data Read | port | 16 | | msa_hostport_data_written | Data Written | port | 17 | | msa_hostport_avg_resp_time_read | Read Response Time | port | 18 | | msa_hostport_avg_resp_time_write | Write Response Time | port | 19 | | msa_hostport_avg_resp_time | I/O Response Time | port | 20 | | msa_hostport_queue_depth | Queue Depth | port | 21 | | msa_hostport_reads | Reads | port | 22 | | msa_hostport_writes | Writes | port | 23 | | msa_disk_temperature | Temperature | location, serial | 24 | | msa_disk_iops | IOPS | location, serial | 25 | | msa_disk_bps | Bytes per second | location, serial | 26 | | msa_disk_avg_resp_time | Average I/O Response Time | location, serial | 27 | | msa_disk_ssd_life_left | SSD Life Remaining | location, serial | 28 | | msa_disk_health | Health | location, serial | 29 | | msa_disk_power_on_hours | Power on hours | location, serial | 30 | | msa_disk_errors | Errors | location, port, serial, type | 31 | | msa_volume_health | Health | volume | 32 | | msa_volume_iops | IOPS | volume | 33 | | msa_volume_bps | Bytes per second | volume | 34 | | msa_volume_reads | Reads | volume | 35 | | msa_volume_writes | Writes | volume | 36 | | msa_volume_data_read | Data Read | volume | 37 | | msa_volume_data_written | Data Written | volume | 38 | | msa_volume_shared_pages | Shared Pages | volume | 39 | | msa_volume_read_hits | Read-Cache Hits | volume | 40 | | msa_volume_read_misses | Read-Cache Misses | volume | 41 | | msa_volume_write_hits | Read-Cache Hits | volume | 42 | | msa_volume_write_misses | Read-Cache Misses | volume | 43 | | msa_volume_small_destage | Small Destages | volume | 44 | | msa_volume_full_stripe_write_destages | Full Stripe Write Destages | volume | 45 | | msa_volume_read_ahead_ops | Read-Ahead Operations | volume | 46 | | msa_volume_write_cache_space | Write Cache Space | volume | 47 | | msa_volume_write_cache_percent | Write Cache Percentage | volume | 48 | | msa_volume_size | Size | volume | 49 | | msa_volume_total_size | Total Size | volume | 50 | | msa_volume_allocated_size | Total Size | volume | 51 | | msa_volume_blocks | Blocks | volume | 52 | | msa_volume_tier_distribution | Volume tier distribution | tier, volume | 53 | | msa_pool_data_read | Data Read | serial, pool | 54 | | msa_pool_data_written | Data Written | serial, pool | 55 | | msa_pool_avg_resp_time | I/O Response Time | serial, pool | 56 | | msa_pool_avg_resp_time_read | Read Response Time | serial, pool | 57 | | msa_pool_total_size | Total Size | serial, pool | 58 | | msa_pool_available_size | Available Size | serial, pool | 59 | | msa_pool_snapshot_size | Snapshot Size | serial, pool | 60 | | msa_pool_allocated_pages | Allocated Pages | serial, pool | 61 | | msa_pool_available_pages | Available Pages | serial, pool | 62 | | msa_pool_metadata_volume_size | Metadata Volume Size | serial, pool | 63 | | msa_pool_total_rfc_size | Total RFC Size | serial, pool | 64 | | msa_pool_available_rfc_size | Available RFC Size | serial, pool | 65 | | msa_pool_reserved_size | Reserved Size | serial, pool | 66 | | msa_pool_unallocated_reserved_size | Unallocated Reserved Size | serial, pool | 67 | | msa_tier_reads | Reads | serial, pool, tier | 68 | | msa_tier_writes | Writes | serial, pool, tier | 69 | | msa_tier_data_read | Data Read | serial, pool, tier | 70 | | msa_tier_data_written | Data Written | serial, pool, tier | 71 | | msa_tier_avg_resp_time | I/O Response Time | serial, pool, tier | 72 | | msa_tier_avg_resp_time_read | Read Response Time | serial, pool, tier | 73 | | msa_tier_avg_resp_time_write | Write Response Time | serial, pool, tier | 74 | | msa_enclosure_power | Power consumption in watts | wwn, id | 75 | | msa_controller_cpu | CPU Load | controller | 76 | | msa_controller_iops | IOPS | controller | 77 | | msa_controller_bps | Bytes per second | controller | 78 | | msa_controller_read_hits | Read-Cache Hits | controller | 79 | | msa_controller_read_misses | Read-Cache Misses | controller | 80 | | msa_controller_write_hits | Write-Cache Hits | controller | 81 | | msa_controller_write_misses | Write-Cache Misses | controller | 82 | | msa_psu_health | Power-supply unit health | psu, serial | 83 | | msa_psu_status | Power-supply unit status | psu, serial | 84 | | msa_system_health | System health | | 85 | 86 | ## Compatible hardware 87 | 88 | This exporter has been tested on the following hardware: 89 | 90 | - HP MSA 2050/2052 series using 3.5" and 2.5" backplanes with or without external JBODs 91 | - DELL ME4024 with 2.5" backplanes 92 | 93 | It can probably work on : 94 | - Dothill/Seagate AssuredSan product 95 | - Lenovo DS S2200 / S3200 96 | -------------------------------------------------------------------------------- /msa_exporter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import hashlib 4 | import time 5 | import argparse 6 | import traceback 7 | 8 | import urllib3 9 | import requests 10 | import prometheus_client 11 | import lxml.etree 12 | 13 | 14 | import xml.etree.ElementTree as ET 15 | 16 | 17 | PREFIX = 'msa_' 18 | HOSTPORTSTATS_PROPERTIES_AS_LABEL_MAPPING = {'durable-id': 'port'} 19 | DISK_PROPERTIES_AS_LABEL_MAPPING = {'location': 'location', 20 | 'serial-number': 'serial'} 21 | VOLUME_PROPERTIES_AS_LABEL_MAPPING = {'volume-name': 'volume'} 22 | POOLSTATS_PROPERTIES_AS_LABEL_MAPPING = {'pool': 'pool', 'serial-number': 'serial'} 23 | POOL_PROPERTIES_AS_LABEL_MAPPING = {'name': 'pool', 'serial-number': 'serial'} 24 | TIER_PROPERTIES_AS_LABEL_MAPPING = {'tier': 'tier', 'pool': 'pool', 'serial-number': 'serial'} 25 | CONTROLLER_PROPERTIES_AS_LABEL_MAPPING = {'durable-id': 'controller'} 26 | PSU_PROPERTIES_AS_LABEL_MAPPING = {'durable-id': 'psu', 'serial-number': 'serial'} 27 | 28 | 29 | METRICS = { 30 | 'hostport_data_read': { 31 | 'description': 'Data Read', 32 | 'sources': { 33 | 'path': 'host-port-statistics', 34 | 'object_selector': './OBJECT[@name="host-port-statistics"]', 35 | 'property_selector': './PROPERTY[@name="data-read-numeric"]', 36 | 'properties_as_label': HOSTPORTSTATS_PROPERTIES_AS_LABEL_MAPPING 37 | } 38 | }, 39 | 'hostport_data_written': { 40 | 'description': 'Data Written', 41 | 'sources': { 42 | 'path': 'host-port-statistics', 43 | 'object_selector': './OBJECT[@name="host-port-statistics"]', 44 | 'property_selector': './PROPERTY[@name="data-written-numeric"]', 45 | 'properties_as_label': HOSTPORTSTATS_PROPERTIES_AS_LABEL_MAPPING 46 | } 47 | }, 48 | 'hostport_avg_resp_time_read': { 49 | 'description': 'Read Response Time', 50 | 'sources': { 51 | 'path': 'host-port-statistics', 52 | 'object_selector': './OBJECT[@name="host-port-statistics"]', 53 | 'property_selector': './PROPERTY[@name="avg-read-rsp-time"]', 54 | 'properties_as_label': HOSTPORTSTATS_PROPERTIES_AS_LABEL_MAPPING 55 | } 56 | }, 57 | 'hostport_avg_resp_time_write': { 58 | 'description': 'Write Response Time', 59 | 'sources': { 60 | 'path': 'host-port-statistics', 61 | 'object_selector': './OBJECT[@name="host-port-statistics"]', 62 | 'property_selector': './PROPERTY[@name="avg-write-rsp-time"]', 63 | 'properties_as_label': HOSTPORTSTATS_PROPERTIES_AS_LABEL_MAPPING 64 | } 65 | }, 66 | 'hostport_avg_resp_time': { 67 | 'description': 'I/O Response Time', 68 | 'sources': { 69 | 'path': 'host-port-statistics', 70 | 'object_selector': './OBJECT[@name="host-port-statistics"]', 71 | 'property_selector': './PROPERTY[@name="avg-rsp-time"]', 72 | 'properties_as_label': HOSTPORTSTATS_PROPERTIES_AS_LABEL_MAPPING 73 | } 74 | }, 75 | 'hostport_queue_depth': { 76 | 'description': 'Queue Depth', 77 | 'sources': { 78 | 'path': 'host-port-statistics', 79 | 'object_selector': './OBJECT[@name="host-port-statistics"]', 80 | 'property_selector': './PROPERTY[@name="queue-depth"]', 81 | 'properties_as_label': HOSTPORTSTATS_PROPERTIES_AS_LABEL_MAPPING 82 | } 83 | }, 84 | 'hostport_reads': { 85 | 'description': 'Reads', 86 | 'sources': { 87 | 'path': 'host-port-statistics', 88 | 'object_selector': './OBJECT[@name="host-port-statistics"]', 89 | 'property_selector': './PROPERTY[@name="number-of-reads"]', 90 | 'properties_as_label': HOSTPORTSTATS_PROPERTIES_AS_LABEL_MAPPING 91 | } 92 | }, 93 | 'hostport_writes': { 94 | 'description': 'Writes', 95 | 'sources': { 96 | 'path': 'host-port-statistics', 97 | 'object_selector': './OBJECT[@name="host-port-statistics"]', 98 | 'property_selector': './PROPERTY[@name="number-of-writes"]', 99 | 'properties_as_label': HOSTPORTSTATS_PROPERTIES_AS_LABEL_MAPPING 100 | } 101 | }, 102 | 'disk_temperature': { 103 | 'description': 'Temperature', 104 | 'sources': { 105 | 'path': 'disks', 106 | 'object_selector': "./OBJECT[@name='drive']", 107 | 'property_selector': './PROPERTY[@name="temperature-numeric"]', 108 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING 109 | } 110 | }, 111 | 'disk_iops': { 112 | 'description': 'IOPS', 113 | 'sources': { 114 | 'path': 'disk-statistics', 115 | 'object_selector': "./OBJECT[@name='disk-statistics']", 116 | 'property_selector': './PROPERTY[@name="iops"]', 117 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING 118 | } 119 | }, 120 | 'disk_power_on_hours': { 121 | 'description': 'Power on hours', 122 | 'sources': { 123 | 'path': 'disk-statistics', 124 | 'object_selector': "./OBJECT[@name='disk-statistics']", 125 | 'property_selector': './PROPERTY[@name="power-on-hours"]', 126 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING 127 | } 128 | }, 129 | 'disk_bps': { 130 | 'description': 'Bytes per second', 131 | 'sources': { 132 | 'path': 'disks', 133 | 'object_selector': "./OBJECT[@name='disk-statistics']", 134 | 'property_selector': './PROPERTY[@name="bytes-per-second-numeric"]', 135 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING 136 | } 137 | }, 138 | 'disk_avg_resp_time': { 139 | 'description': 'Average I/O Response Time', 140 | 'sources': { 141 | 'path': 'disks', 142 | 'object_selector': "./OBJECT[@name='drive']", 143 | 'property_selector': './PROPERTY[@name="avg-rsp-time"]', 144 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING 145 | } 146 | }, 147 | 'disk_ssd_life_left': { 148 | 'description': 'SSD Life Remaining', 149 | 'sources': { 150 | 'path': 'disks', 151 | 'object_selector': "./OBJECT[@name='drive']/PROPERTY[@name='architecture'][text()='SSD']/..", 152 | 'property_selector': './PROPERTY[@name="ssd-life-left-numeric"]', 153 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING 154 | } 155 | }, 156 | 'disk_health': { 157 | 'description': 'Health', 158 | 'sources': { 159 | 'path': 'disks', 160 | 'object_selector': "./OBJECT[@name='drive']", 161 | 'property_selector': './PROPERTY[@name="health-numeric"]', 162 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING 163 | } 164 | }, 165 | 'disk_errors': { 166 | 'description': 'Errors', 167 | 'sources': [ 168 | { 169 | 'path': 'disk-statistics', 170 | 'object_selector': "./OBJECT[@name='disk-statistics']", 171 | 'property_selector': './PROPERTY[@name="smart-count-1"]', 172 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 173 | 'labels': {'type': 'smart', 'port': 1} 174 | }, 175 | { 176 | 'path': 'disk-statistics', 177 | 'object_selector': "./OBJECT[@name='disk-statistics']", 178 | 'property_selector': './PROPERTY[@name="smart-count-2"]', 179 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 180 | 'labels': {'type': 'smart', 'port': 2} 181 | }, 182 | { 183 | 'path': 'disk-statistics', 184 | 'object_selector': "./OBJECT[@name='disk-statistics']", 185 | 'property_selector': './PROPERTY[@name="io-timeout-count-1"]', 186 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 187 | 'labels': {'type': 'io-timeout', 'port': 1} 188 | }, 189 | { 190 | 'path': 'disk-statistics', 191 | 'object_selector': "./OBJECT[@name='disk-statistics']", 192 | 'property_selector': './PROPERTY[@name="io-timeout-count-2"]', 193 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 194 | 'labels': {'type': 'io-timeout', 'port': 2} 195 | }, 196 | { 197 | 'path': 'disk-statistics', 198 | 'object_selector': "./OBJECT[@name='disk-statistics']", 199 | 'property_selector': './PROPERTY[@name="no-response-count-1"]', 200 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 201 | 'labels': {'type': 'no-response', 'port': 1} 202 | }, 203 | { 204 | 'path': 'disk-statistics', 205 | 'object_selector': "./OBJECT[@name='disk-statistics']", 206 | 'property_selector': './PROPERTY[@name="no-response-count-2"]', 207 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 208 | 'labels': {'type': 'no-response', 'port': 2} 209 | }, 210 | { 211 | 'path': 'disk-statistics', 212 | 'object_selector': "./OBJECT[@name='disk-statistics']", 213 | 'property_selector': './PROPERTY[@name="spinup-retry-count-1"]', 214 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 215 | 'labels': {'type': 'spinup-retry', 'port': 1} 216 | }, 217 | { 218 | 'path': 'disk-statistics', 219 | 'object_selector': "./OBJECT[@name='disk-statistics']", 220 | 'property_selector': './PROPERTY[@name="spinup-retry-count-2"]', 221 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 222 | 'labels': {'type': 'spinup-retry', 'port': 2} 223 | }, 224 | { 225 | 'path': 'disk-statistics', 226 | 'object_selector': "./OBJECT[@name='disk-statistics']", 227 | 'property_selector': './PROPERTY[@name="number-of-media-errors-1"]', 228 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 229 | 'labels': {'type': 'media-errors', 'port': 1} 230 | }, 231 | { 232 | 'path': 'disk-statistics', 233 | 'object_selector': "./OBJECT[@name='disk-statistics']", 234 | 'property_selector': './PROPERTY[@name="number-of-media-errors-2"]', 235 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 236 | 'labels': {'type': 'media-errors', 'port': 2} 237 | }, 238 | { 239 | 'path': 'disk-statistics', 240 | 'object_selector': "./OBJECT[@name='disk-statistics']", 241 | 'property_selector': './PROPERTY[@name="number-of-nonmedia-errors-1"]', 242 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 243 | 'labels': {'type': 'nonmedia-errors', 'port': 1} 244 | }, 245 | { 246 | 'path': 'disk-statistics', 247 | 'object_selector': "./OBJECT[@name='disk-statistics']", 248 | 'property_selector': './PROPERTY[@name="number-of-nonmedia-errors-2"]', 249 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 250 | 'labels': {'type': 'nonmedia-errors', 'port': 2} 251 | }, 252 | { 253 | 'path': 'disk-statistics', 254 | 'object_selector': "./OBJECT[@name='disk-statistics']", 255 | 'property_selector': './PROPERTY[@name="number-of-block-reassigns-1"]', 256 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 257 | 'labels': {'type': 'block-reassigns', 'port': 1} 258 | }, 259 | { 260 | 'path': 'disk-statistics', 261 | 'object_selector': "./OBJECT[@name='disk-statistics']", 262 | 'property_selector': './PROPERTY[@name="number-of-block-reassigns-2"]', 263 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 264 | 'labels': {'type': 'block-reassigns', 'port': 2} 265 | }, 266 | { 267 | 'path': 'disk-statistics', 268 | 'object_selector': "./OBJECT[@name='disk-statistics']", 269 | 'property_selector': './PROPERTY[@name="number-of-bad-blocks-1"]', 270 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 271 | 'labels': {'type': 'bad-blocks', 'port': 1} 272 | }, 273 | { 274 | 'path': 'disk-statistics', 275 | 'object_selector': "./OBJECT[@name='disk-statistics']", 276 | 'property_selector': './PROPERTY[@name="number-of-bad-blocks-2"]', 277 | 'properties_as_label': DISK_PROPERTIES_AS_LABEL_MAPPING, 278 | 'labels': {'type': 'bad-blocks', 'port': 2} 279 | } 280 | ] 281 | }, 282 | 'volume_health': { 283 | 'description': 'Health', 284 | 'sources': { 285 | 'path': 'volumes', 286 | 'object_selector': './OBJECT[@name="volume"]', 287 | 'property_selector': './PROPERTY[@name="health-numeric"]', 288 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 289 | } 290 | }, 291 | 'volume_iops': { 292 | 'description': 'IOPS', 293 | 'sources': { 294 | 'path': 'volume-statistics', 295 | 'object_selector': './OBJECT[@name="volume-statistics"]', 296 | 'property_selector': './PROPERTY[@name="iops"]', 297 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 298 | } 299 | }, 300 | 'volume_bps': { 301 | 'description': 'Bytes per second', 302 | 'sources': { 303 | 'path': 'volume-statistics', 304 | 'object_selector': './OBJECT[@name="volume-statistics"]', 305 | 'property_selector': './PROPERTY[@name="bytes-per-second-numeric"]', 306 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 307 | } 308 | }, 309 | 'volume_reads': { 310 | 'description': 'Reads', 311 | 'sources': { 312 | 'path': 'volume-statistics', 313 | 'object_selector': './OBJECT[@name="volume-statistics"]', 314 | 'property_selector': './PROPERTY[@name="number-of-reads"]', 315 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 316 | } 317 | }, 318 | 'volume_writes': { 319 | 'description': 'Writes', 320 | 'sources': { 321 | 'path': 'volume-statistics', 322 | 'object_selector': './OBJECT[@name="volume-statistics"]', 323 | 'property_selector': './PROPERTY[@name="number-of-writes"]', 324 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 325 | } 326 | }, 327 | 'volume_data_read': { 328 | 'description': 'Data Read', 329 | 'sources': { 330 | 'path': 'volume-statistics', 331 | 'object_selector': './OBJECT[@name="volume-statistics"]', 332 | 'property_selector': './PROPERTY[@name="data-read-numeric"]', 333 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 334 | } 335 | }, 336 | 'volume_data_written': { 337 | 'description': 'Data Written', 338 | 'sources': { 339 | 'path': 'volume-statistics', 340 | 'object_selector': './OBJECT[@name="volume-statistics"]', 341 | 'property_selector': './PROPERTY[@name="data-written-numeric"]', 342 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 343 | } 344 | }, 345 | 'volume_shared_pages': { 346 | 'description': 'Shared Pages', 347 | 'sources': { 348 | 'path': 'volume-statistics', 349 | 'object_selector': './OBJECT[@name="volume-statistics"]', 350 | 'property_selector': './PROPERTY[@name="shared-pages"]', 351 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 352 | } 353 | }, 354 | 'volume_read_hits': { 355 | 'description': 'Read-Cache Hits', 356 | 'sources': { 357 | 'path': 'volume-statistics', 358 | 'object_selector': './OBJECT[@name="volume-statistics"]', 359 | 'property_selector': './PROPERTY[@name="read-cache-hits"]', 360 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 361 | } 362 | }, 363 | 'volume_read_misses': { 364 | 'description': 'Read-Cache Misses', 365 | 'sources': { 366 | 'path': 'volume-statistics', 367 | 'object_selector': './OBJECT[@name="volume-statistics"]', 368 | 'property_selector': './PROPERTY[@name="read-cache-misses"]', 369 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 370 | } 371 | }, 372 | 'volume_write_hits': { 373 | 'description': 'Read-Cache Hits', 374 | 'sources': { 375 | 'path': 'volume-statistics', 376 | 'object_selector': './OBJECT[@name="volume-statistics"]', 377 | 'property_selector': './PROPERTY[@name="write-cache-hits"]', 378 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 379 | } 380 | }, 381 | 'volume_write_misses': { 382 | 'description': 'Read-Cache Misses', 383 | 'sources': { 384 | 'path': 'volume-statistics', 385 | 'object_selector': './OBJECT[@name="volume-statistics"]', 386 | 'property_selector': './PROPERTY[@name="write-cache-misses"]', 387 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 388 | } 389 | }, 390 | 'volume_small_destage': { 391 | 'description': 'Small Destages', 392 | 'sources': { 393 | 'path': 'volume-statistics', 394 | 'object_selector': './OBJECT[@name="volume-statistics"]', 395 | 'property_selector': './PROPERTY[@name="small-destages"]', 396 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 397 | } 398 | }, 399 | 'volume_full_stripe_write_destages': { 400 | 'description': 'Full Stripe Write Destages', 401 | 'sources': { 402 | 'path': 'volume-statistics', 403 | 'object_selector': './OBJECT[@name="volume-statistics"]', 404 | 'property_selector': './PROPERTY[@name="full-stripe-write-destages"]', 405 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 406 | } 407 | }, 408 | 'volume_read_ahead_ops': { 409 | 'description': 'Read-Ahead Operations', 410 | 'sources': { 411 | 'path': 'volume-statistics', 412 | 'object_selector': './OBJECT[@name="volume-statistics"]', 413 | 'property_selector': './PROPERTY[@name="read-ahead-operations"]', 414 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 415 | } 416 | }, 417 | 'volume_write_cache_space': { 418 | 'description': 'Write Cache Space', 419 | 'sources': { 420 | 'path': 'volume-statistics', 421 | 'object_selector': './OBJECT[@name="volume-statistics"]', 422 | 'property_selector': './PROPERTY[@name="write-cache-space"]', 423 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 424 | } 425 | }, 426 | 'volume_write_cache_percent': { 427 | 'description': 'Write Cache Percentage', 428 | 'sources': { 429 | 'path': 'volume-statistics', 430 | 'object_selector': './OBJECT[@name="volume-statistics"]', 431 | 'property_selector': './PROPERTY[@name="write-cache-percent"]', 432 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 433 | } 434 | }, 435 | 'volume_size': { 436 | 'description': 'Size', 437 | 'sources': { 438 | 'path': 'volumes', 439 | 'object_selector': './OBJECT[@name="volume"]', 440 | 'property_selector': './PROPERTY[@name="size-numeric"]', 441 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 442 | } 443 | }, 444 | 'volume_total_size': { 445 | 'description': 'Total Size', 446 | 'sources': { 447 | 'path': 'volumes', 448 | 'object_selector': './OBJECT[@name="volume"]', 449 | 'property_selector': './PROPERTY[@name="total-size-numeric"]', 450 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 451 | } 452 | }, 453 | 'volume_allocated_size': { 454 | 'description': 'Total Size', 455 | 'sources': { 456 | 'path': 'volumes', 457 | 'object_selector': './OBJECT[@name="volume"]', 458 | 'property_selector': './PROPERTY[@name="allocated-size-numeric"]', 459 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 460 | } 461 | }, 462 | 'volume_blocks': { 463 | 'description': 'Blocks', 464 | 'sources': { 465 | 'path': 'volumes', 466 | 'object_selector': './OBJECT[@name="volume"]', 467 | 'property_selector': './PROPERTY[@name="blocks"]', 468 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING 469 | } 470 | }, 471 | 'volume_tier_distribution': { 472 | 'description': 'Volume tier distribution', 473 | 'sources': [ 474 | { 475 | 'path': 'volume-statistics', 476 | 'object_selector': './OBJECT[@name="volume-statistics"]', 477 | 'property_selector': './PROPERTY[@name="percent-tier-ssd"]', 478 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING, 479 | 'labels': {'tier': 'Performance'} 480 | }, 481 | { 482 | 'path': 'volume-statistics', 483 | 'object_selector': './OBJECT[@name="volume-statistics"]', 484 | 'property_selector': './PROPERTY[@name="percent-tier-sas"]', 485 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING, 486 | 'labels': {'tier': 'Standard'} 487 | }, 488 | { 489 | 'path': 'volume-statistics', 490 | 'object_selector': './OBJECT[@name="volume-statistics"]', 491 | 'property_selector': './PROPERTY[@name="percent-tier-sata"]', 492 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING, 493 | 'labels': {'tier': 'Archive'} 494 | }, 495 | { 496 | 'path': 'volume-statistics', 497 | 'object_selector': './OBJECT[@name="volume-statistics"]', 498 | 'property_selector': './PROPERTY[@name="percent-allocated-rfc"]', 499 | 'properties_as_label': VOLUME_PROPERTIES_AS_LABEL_MAPPING, 500 | 'labels': {'tier': 'RFC'} 501 | }, 502 | ] 503 | }, 504 | 'pool_data_read': { 505 | 'description': 'Data Read', 506 | 'sources': { 507 | 'path': 'pool-statistics', 508 | 'object_selector': './OBJECT[@name="pool-statistics"]', 509 | 'property_selector': './/PROPERTY[@name="data-read-numeric"]', 510 | 'properties_as_label': POOLSTATS_PROPERTIES_AS_LABEL_MAPPING 511 | } 512 | }, 513 | 'pool_data_written': { 514 | 'description': 'Data Written', 515 | 'sources': { 516 | 'path': 'pool-statistics', 517 | 'object_selector': './OBJECT[@name="pool-statistics"]', 518 | 'property_selector': './/PROPERTY[@name="data-written-numeric"]', 519 | 'properties_as_label': POOLSTATS_PROPERTIES_AS_LABEL_MAPPING 520 | } 521 | }, 522 | 'pool_avg_resp_time': { 523 | 'description': 'I/O Response Time', 524 | 'sources': { 525 | 'path': 'pool-statistics', 526 | 'object_selector': './OBJECT[@name="pool-statistics"]', 527 | 'property_selector': './/PROPERTY[@name="avg-rsp-time"]', 528 | 'properties_as_label': POOLSTATS_PROPERTIES_AS_LABEL_MAPPING 529 | } 530 | }, 531 | 'pool_avg_resp_time_read': { 532 | 'description': 'Read Response Time', 533 | 'sources': { 534 | 'path': 'pool-statistics', 535 | 'object_selector': './OBJECT[@name="pool-statistics"]', 536 | 'property_selector': './/PROPERTY[@name="avg-read-rsp-time"]', 537 | 'properties_as_label': POOLSTATS_PROPERTIES_AS_LABEL_MAPPING 538 | } 539 | }, 540 | 'pool_total_size': { 541 | 'description': 'Total Size', 542 | 'sources': { 543 | 'path': 'pools', 544 | 'object_selector': './OBJECT[@name="pools"]', 545 | 'property_selector': './PROPERTY[@name="total-size-numeric"]', 546 | 'properties_as_label': POOL_PROPERTIES_AS_LABEL_MAPPING 547 | } 548 | }, 549 | 'pool_available_size': { 550 | 'description': 'Available Size', 551 | 'sources': { 552 | 'path': 'pools', 553 | 'object_selector': './OBJECT[@name="pools"]', 554 | 'property_selector': './PROPERTY[@name="total-avail-numeric"]', 555 | 'properties_as_label': POOL_PROPERTIES_AS_LABEL_MAPPING 556 | } 557 | }, 558 | 'pool_snapshot_size': { 559 | 'description': 'Snapshot Size', 560 | 'sources': { 561 | 'path': 'pools', 562 | 'object_selector': './OBJECT[@name="pools"]', 563 | 'property_selector': './PROPERTY[@name="snap-size-numeric"]', 564 | 'properties_as_label': POOL_PROPERTIES_AS_LABEL_MAPPING 565 | } 566 | }, 567 | 'pool_allocated_pages': { 568 | 'description': 'Allocated Pages', 569 | 'sources': { 570 | 'path': 'pools', 571 | 'object_selector': './OBJECT[@name="pools"]', 572 | 'property_selector': './PROPERTY[@name="allocated-pages"]', 573 | 'properties_as_label': POOL_PROPERTIES_AS_LABEL_MAPPING 574 | } 575 | }, 576 | 'pool_available_pages': { 577 | 'description': 'Available Pages', 578 | 'sources': { 579 | 'path': 'pools', 580 | 'object_selector': './OBJECT[@name="pools"]', 581 | 'property_selector': './PROPERTY[@name="available-pages"]', 582 | 'properties_as_label': POOL_PROPERTIES_AS_LABEL_MAPPING 583 | } 584 | }, 585 | 'pool_metadata_volume_size': { 586 | 'description': 'Metadata Volume Size', 587 | 'sources': { 588 | 'path': 'pools', 589 | 'object_selector': './OBJECT[@name="pools"]', 590 | 'property_selector': './PROPERTY[@name="metadata-vol-size-numeric"]', 591 | 'properties_as_label': POOL_PROPERTIES_AS_LABEL_MAPPING 592 | } 593 | }, 594 | 'pool_total_rfc_size': { 595 | 'description': 'Total RFC Size', 596 | 'sources': { 597 | 'path': 'pools', 598 | 'object_selector': './OBJECT[@name="pools"]', 599 | 'property_selector': './PROPERTY[@name="total-rfc-size-numeric"]', 600 | 'properties_as_label': POOL_PROPERTIES_AS_LABEL_MAPPING 601 | } 602 | }, 603 | 'pool_available_rfc_size': { 604 | 'description': 'Available RFC Size', 605 | 'sources': { 606 | 'path': 'pools', 607 | 'object_selector': './OBJECT[@name="pools"]', 608 | 'property_selector': './PROPERTY[@name="available-rfc-size-numeric"]', 609 | 'properties_as_label': POOL_PROPERTIES_AS_LABEL_MAPPING 610 | } 611 | }, 612 | 'pool_reserved_size': { 613 | 'description': 'Reserved Size', 614 | 'sources': { 615 | 'path': 'pools', 616 | 'object_selector': './OBJECT[@name="pools"]', 617 | 'property_selector': './PROPERTY[@name="reserved-size-numeric"]', 618 | 'properties_as_label': POOL_PROPERTIES_AS_LABEL_MAPPING 619 | } 620 | }, 621 | 'pool_unallocated_reserved_size': { 622 | 'description': 'Unallocated Reserved Size', 623 | 'sources': { 624 | 'path': 'pools', 625 | 'object_selector': './OBJECT[@name="pools"]', 626 | 'property_selector': './PROPERTY[@name="reserved-unalloc-size-numeric"]', 627 | 'properties_as_label': POOL_PROPERTIES_AS_LABEL_MAPPING 628 | } 629 | }, 630 | 'tier_reads': { 631 | 'description': 'Reads', 632 | 'sources': { 633 | 'path': 'pool-statistics', 634 | 'object_selector': './/OBJECT[@name="tier-statistics"]', 635 | 'property_selector': './/PROPERTY[@name="number-of-reads"]', 636 | 'properties_as_label': TIER_PROPERTIES_AS_LABEL_MAPPING 637 | } 638 | }, 639 | 'tier_writes': { 640 | 'description': 'Writes', 641 | 'sources': { 642 | 'path': 'pool-statistics', 643 | 'object_selector': './/OBJECT[@name="tier-statistics"]', 644 | 'property_selector': './/PROPERTY[@name="number-of-writes"]', 645 | 'properties_as_label': TIER_PROPERTIES_AS_LABEL_MAPPING 646 | } 647 | }, 648 | 'tier_data_read': { 649 | 'description': 'Data Read', 650 | 'sources': { 651 | 'path': 'pool-statistics', 652 | 'object_selector': './/OBJECT[@name="tier-statistics"]', 653 | 'property_selector': './/PROPERTY[@name="data-read-numeric"]', 654 | 'properties_as_label': TIER_PROPERTIES_AS_LABEL_MAPPING 655 | } 656 | }, 657 | 'tier_data_written': { 658 | 'description': 'Data Written', 659 | 'sources': { 660 | 'path': 'pool-statistics', 661 | 'object_selector': './/OBJECT[@name="tier-statistics"]', 662 | 'property_selector': './/PROPERTY[@name="data-written-numeric"]', 663 | 'properties_as_label': TIER_PROPERTIES_AS_LABEL_MAPPING 664 | } 665 | }, 666 | 'tier_avg_resp_time': { 667 | 'description': 'I/O Response Time', 668 | 'sources': { 669 | 'path': 'pool-statistics', 670 | 'object_selector': './/OBJECT[@name="tier-statistics"]', 671 | 'property_selector': './/PROPERTY[@name="avg-rsp-time"]', 672 | 'properties_as_label': TIER_PROPERTIES_AS_LABEL_MAPPING 673 | } 674 | }, 675 | 'tier_avg_resp_time_read': { 676 | 'description': 'Read Response Time', 677 | 'sources': { 678 | 'path': 'pool-statistics', 679 | 'object_selector': './/OBJECT[@name="tier-statistics"]', 680 | 'property_selector': './/PROPERTY[@name="avg-read-rsp-time"]', 681 | 'properties_as_label': TIER_PROPERTIES_AS_LABEL_MAPPING 682 | } 683 | }, 684 | 'tier_avg_resp_time_write': { 685 | 'description': 'Write Response Time', 686 | 'sources': { 687 | 'path': 'pool-statistics', 688 | 'object_selector': './/OBJECT[@name="tier-statistics"]', 689 | 'property_selector': './/PROPERTY[@name="avg-write-rsp-time"]', 690 | 'properties_as_label': TIER_PROPERTIES_AS_LABEL_MAPPING 691 | } 692 | }, 693 | 'enclosure_power': { 694 | 'description': 'Power consumption in watts', 695 | 'sources': { 696 | 'path': 'enclosures', 697 | 'object_selector': './OBJECT[@name="enclosures"]', 698 | 'property_selector': './PROPERTY[@name="enclosure-power"]', 699 | 'properties_as_label': {'enclosure-id': 'id', 'enclosure-wwn': 'wwn'} 700 | } 701 | }, 702 | 'controller_cpu': { 703 | 'description': 'CPU Load', 704 | 'sources': { 705 | 'path': 'controller-statistics', 706 | 'object_selector': './OBJECT[@name="controller-statistics"]', 707 | 'property_selector': './PROPERTY[@name="cpu-load"]', 708 | 'properties_as_label': CONTROLLER_PROPERTIES_AS_LABEL_MAPPING 709 | } 710 | }, 711 | 'controller_iops': { 712 | 'description': 'IOPS', 713 | 'sources': { 714 | 'path': 'controller-statistics', 715 | 'object_selector': './OBJECT[@name="controller-statistics"]', 716 | 'property_selector': './PROPERTY[@name="iops"]', 717 | 'properties_as_label': CONTROLLER_PROPERTIES_AS_LABEL_MAPPING 718 | } 719 | }, 720 | 'controller_bps': { 721 | 'description': 'Bytes per second', 722 | 'sources': { 723 | 'path': 'controller-statistics', 724 | 'object_selector': './OBJECT[@name="controller-statistics"]', 725 | 'property_selector': './PROPERTY[@name="bytes-per-second-numeric"]', 726 | 'properties_as_label': CONTROLLER_PROPERTIES_AS_LABEL_MAPPING 727 | } 728 | }, 729 | 'controller_read_hits': { 730 | 'description': 'Read-Cache Hits', 731 | 'sources': { 732 | 'path': 'controller-statistics', 733 | 'object_selector': './OBJECT[@name="controller-statistics"]', 734 | 'property_selector': './PROPERTY[@name="read-cache-hits"]', 735 | 'properties_as_label': CONTROLLER_PROPERTIES_AS_LABEL_MAPPING 736 | } 737 | }, 738 | 'controller_read_misses': { 739 | 'description': 'Read-Cache Misses', 740 | 'sources': { 741 | 'path': 'controller-statistics', 742 | 'object_selector': './OBJECT[@name="controller-statistics"]', 743 | 'property_selector': './PROPERTY[@name="read-cache-misses"]', 744 | 'properties_as_label': CONTROLLER_PROPERTIES_AS_LABEL_MAPPING 745 | } 746 | }, 747 | 'controller_write_hits': { 748 | 'description': 'Write-Cache Hits', 749 | 'sources': { 750 | 'path': 'controller-statistics', 751 | 'object_selector': './OBJECT[@name="controller-statistics"]', 752 | 'property_selector': './PROPERTY[@name="write-cache-hits"]', 753 | 'properties_as_label': CONTROLLER_PROPERTIES_AS_LABEL_MAPPING 754 | } 755 | }, 756 | 'controller_write_misses': { 757 | 'description': 'Write-Cache Misses', 758 | 'sources': { 759 | 'path': 'controller-statistics', 760 | 'object_selector': './OBJECT[@name="controller-statistics"]', 761 | 'property_selector': './PROPERTY[@name="write-cache-misses"]', 762 | 'properties_as_label': CONTROLLER_PROPERTIES_AS_LABEL_MAPPING 763 | } 764 | }, 765 | 'psu_health': { 766 | 'description': 'Power-supply unit health', 767 | 'sources': { 768 | 'path': 'enclosure', 769 | 'object_selector': './OBJECT[@name="enclosures"]/OBJECT[@name="power-supplies"]', 770 | 'property_selector': './PROPERTY[@name="health-numeric"]', 771 | 'properties_as_label': PSU_PROPERTIES_AS_LABEL_MAPPING 772 | } 773 | }, 774 | 'psu_status': { 775 | 'description': 'Power-supply unit status', 776 | 'sources': { 777 | 'path': 'enclosure', 778 | 'object_selector': './OBJECT[@name="enclosures"]/OBJECT[@name="power-supplies"]', 779 | 'property_selector': './PROPERTY[@name="status-numeric"]', 780 | 'properties_as_label': PSU_PROPERTIES_AS_LABEL_MAPPING 781 | } 782 | }, 783 | 'system_health': { 784 | 'description': 'System health', 785 | 'sources': { 786 | 'path': 'system', 787 | 'object_selector': './OBJECT[@name="system-information"]', 788 | 'property_selector': './PROPERTY[@name="health-numeric"]', 789 | } 790 | }, 791 | } 792 | 793 | 794 | class MetricStore(object): 795 | def __init__(self): 796 | self.metrics = {} 797 | 798 | def get_or_create(self, metric_type, name, description, labels): 799 | metric_key = (name, tuple(labels.keys())) 800 | 801 | if metric_key not in self.metrics: 802 | if metric_type == 'gauge': 803 | self.metrics[metric_key] = prometheus_client.Gauge(name, description, tuple(labels.keys())) 804 | else: 805 | raise RuntimeError('Unknown metric type "%s"' % metric_type) 806 | 807 | metric = self.metrics[metric_key] 808 | 809 | if labels: 810 | return metric.labels(**labels) 811 | else: 812 | return metric 813 | 814 | 815 | def scrap_msa(metrics_store, host, login, password, timeout=10): 816 | session = requests.Session() 817 | session.verify = False 818 | 819 | creds = hashlib.sha256(b'%s_%s' % (login.encode('utf8'), password.encode('utf8'))).hexdigest() 820 | response = session.get('https://%s/api/login/%s' % (host, creds), timeout=timeout) 821 | response.raise_for_status() 822 | session_key = ET.fromstring(response.content)[0][2].text 823 | 824 | session.headers['sessionKey'] = session_key 825 | session.cookies['wbisessionkey'] = session_key 826 | session.cookies['wbiusername'] = login 827 | 828 | path_cache = {} 829 | 830 | # Firmware version 831 | response = session.get('https://%s/api/show/version' % (host), timeout=timeout) 832 | xml = lxml.etree.fromstring(response.content) 833 | 834 | for controller in ['controller-a-versions', 'controller-b-versions' ]: 835 | for obj in xml.xpath('./OBJECT[@name="%s"]'%controller): 836 | labels = { "controller": controller } 837 | for version in ["bundle-version", "bundle-base-version","sc-fw", "mc-fw", "pld-rev"]: 838 | value = obj.find('./PROPERTY[@name="%s"]'%version).text 839 | labels[version.replace("-", "_")] = value 840 | metrics_store.get_or_create('gauge', PREFIX + "version", "Firmware Versions", labels).set(1) 841 | 842 | for name, metric in METRICS.items(): 843 | name = PREFIX + name 844 | if isinstance(metric['sources'], dict): 845 | sources = [metric['sources']] 846 | else: 847 | sources = metric['sources'] 848 | 849 | for source in sources: 850 | if source['path'] not in path_cache: 851 | response = session.get('https://%s/api/show/%s' % (host, source['path']), timeout=timeout) 852 | response.raise_for_status() 853 | path_cache[source['path']] = lxml.etree.fromstring(response.content) 854 | 855 | xml = path_cache[source['path']] 856 | 857 | for obj in xml.xpath(source['object_selector']): 858 | labels = {source['properties_as_label'][elem.get('name')]: elem.text for elem in obj 859 | if elem.get('name') in source.get('properties_as_label', {})} 860 | labels.update(source.get('labels', {})) 861 | value = obj.find(source['property_selector']).text 862 | if value == 'N/A' : value = 'nan' 863 | metrics_store.get_or_create(metric.get('type', 'gauge'), name, metric['description'], labels).set(value) 864 | 865 | 866 | if __name__ == '__main__': 867 | parser = argparse.ArgumentParser() 868 | parser.add_argument('hostname') 869 | parser.add_argument('login') 870 | parser.add_argument('password') 871 | parser.add_argument('-p', '--port', type=int, default=8000) 872 | parser.add_argument('-i', '--interval', type=int, default=60) 873 | parser.add_argument('-t', '--timeout', type=int, default=60) 874 | 875 | args = parser.parse_args() 876 | 877 | print("Starting MSA exporter on port %d" % args.port) 878 | print("Connecting to %s as %s" % (args.hostname, args.login)) 879 | print("Scraping every %d seconds with timeout %d seconds" % (args.interval, args.timeout)) 880 | 881 | # disable urllib3 SSL warnings used by pyrequests 882 | urllib3.disable_warnings() 883 | prometheus_client.start_http_server(args.port) 884 | metrics_store = MetricStore() 885 | while True: 886 | try: 887 | scrap_msa(metrics_store, args.hostname, args.login, args.password, timeout=args.timeout) 888 | except: 889 | traceback.print_exc() 890 | time.sleep(args.interval) 891 | --------------------------------------------------------------------------------