#!/usr/bin/env python3
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import yaml
import os
import urllib.parse
import logging
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ForkingMixIn
from prometheus_client import CONTENT_TYPE_LATEST
from osclient import OSClient
from oscache import OSCache
from check_os_api import CheckOSApi
from neutron_agents import NeutronAgentStats
from nova_services import NovaServiceStats
from cinder_services import CinderServiceStats
from hypervisor_stats import HypervisorStats
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s:%(levelname)s: %(message)s")
logger = logging.getLogger(__name__)
collectors = []
class ForkingHTTPServer(ForkingMixIn, HTTPServer):
pass
class OpenstackExporterHandler(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
def do_GET(self):
url = urllib.parse.urlparse(self.path)
if url.path == '/metrics':
output = b''
for collector in collectors:
try:
stats = collector.get_stats()
if stats is not None:
output = output + stats
except BaseException as inst:
logger.warning(
'Could not get stats for collector {}.'
'"{}" Exception "{}" occured.'
.format(
collector.get_cache_key(),
type(inst),
inst
))
self.send_response(200)
self.send_header('Content-Type', CONTENT_TYPE_LATEST)
self.end_headers()
self.wfile.write(output)
elif url.path == '/':
self.send_response(200)
self.end_headers()
self.wfile.write("""
OpenStack Exporter
OpenStack Exporter
Visit /metrics
to use.
""")
else:
self.send_response(404)
self.end_headers()
def handler(*args, **kwargs):
OpenstackExporterHandler(*args, **kwargs)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
usage=__doc__,
description='Prometheus OpenStack exporter',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('--config-file', nargs='?',
help='Configuration file path',
type=argparse.FileType('r'),
required=False)
args = parser.parse_args()
config = {}
if args.config_file:
config = yaml.safe_load(args.config_file.read())
os_keystone_url = config.get('OS_AUTH_URL', os.getenv('OS_AUTH_URL'))
os_password = config.get('OS_PASSWORD', os.getenv('OS_PASSWORD'))
os_tenant_name = config.get(
'OS_PROJECT_NAME',
os.getenv('OS_PROJECT_NAME'))
os_username = config.get('OS_USERNAME', os.getenv('OS_USERNAME'))
os_user_domain = config.get(
'OS_USER_DOMAIN_NAME',
os.getenv('OS_USER_DOMAIN_NAME'))
os_region = config.get('OS_REGION_NAME', os.getenv('OS_REGION_NAME'))
os_timeout = config.get(
'TIMEOUT_SECONDS', int(
os.getenv(
'TIMEOUT_SECONDS', 10)))
os_polling_interval = config.get(
'OS_POLLING_INTERVAL', int(
os.getenv(
'OS_POLLING_INTERVAL', 900)))
os_retries = config.get('OS_RETRIES', int(os.getenv('OS_RETRIES', 1)))
os_cpu_overcomit_ratio = config.get(
'OS_CPU_OC_RATIO', float(
os.getenv(
'OS_CPU_OC_RATIO', 1)))
os_ram_overcomit_ratio = config.get(
'OS_RAM_OC_RATIO', float(
os.getenv(
'OS_RAM_OC_RATIO', 1)))
osclient = OSClient(
os_keystone_url,
os_password,
os_tenant_name,
os_username,
os_user_domain,
os_region,
os_timeout,
os_retries)
oscache = OSCache(os_polling_interval, os_region)
collectors.append(oscache)
check_os_api = CheckOSApi(oscache, osclient)
collectors.append(check_os_api)
neutron_agent_stats = NeutronAgentStats(oscache, osclient)
collectors.append(neutron_agent_stats)
cinder_service_stats = CinderServiceStats(oscache, osclient)
collectors.append(cinder_service_stats)
nova_service_stats = NovaServiceStats(oscache, osclient)
collectors.append(nova_service_stats)
hypervisor_stats = HypervisorStats(
oscache,
osclient,
os_cpu_overcomit_ratio,
os_ram_overcomit_ratio)
collectors.append(hypervisor_stats)
oscache.start()
listen_port = config.get(
'LISTEN_PORT', int(
os.getenv(
'LISTEN_PORT', 9103)))
server = ForkingHTTPServer(('', listen_port), handler)
server.serve_forever()