# octavia.amphorae.backends.agent.api_server.amphora_info

# Source code for octavia.amphorae.backends.agent.api_server.amphora_info

    # Copyright 2015 Hewlett-Packard Development Company, L.P.
    #
    # 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 ipaddress
    import os
    import re
    import socket
    import subprocess

    import pyroute2
    import webob

    import netifaces
    from octavia.amphorae.backends.agent import api_server
    from octavia.amphorae.backends.agent.api_server import util
    from octavia.common import constants as consts

    class AmphoraInfo(object):
        def __init__(self, osutils):
            self._osutils = osutils

        def compile_amphora_info(self, extend_udp_driver=None):
            extend_body = {}
            if extend_udp_driver:
                extend_body = self._get_extend_body_from_udp_driver(
                    extend_udp_driver)
            body = {'hostname': socket.gethostname(),
                    'haproxy_version':
                        self._get_version_of_installed_package('haproxy'),
                    'api_version': api_server.VERSION}
            if extend_body:
                body.update(extend_body)
            return webob.Response(json=body)

        def compile_amphora_details(self, extend_udp_driver=None):
            haproxy_listener_list = sorted(util.get_listeners())
            extend_body = {}
            udp_listener_list = []
            if extend_udp_driver:
                udp_listener_list = util.get_udp_listeners()
                extend_data = self._get_extend_body_from_udp_driver(
                    extend_udp_driver)
                udp_count = self._count_udp_listener_processes(extend_udp_driver,
                                                               udp_listener_list)
                extend_body['udp_listener_process_count'] = udp_count
                extend_body.update(extend_data)
            meminfo = self._get_meminfo()
            cpu = self._cpu()
            st = os.statvfs('/')
            body = {'hostname': socket.gethostname(),
                    'haproxy_version':
                        self._get_version_of_installed_package('haproxy'),
                    'api_version': api_server.VERSION,
                    'networks': self._get_networks(),
                    'active': True,
                    'haproxy_count':
                        self._count_haproxy_processes(haproxy_listener_list),
                    'cpu': {
                        'total': cpu['total'],
                        'user': cpu['user'],
                        'system': cpu['system'],
                        'soft_irq': cpu['softirq'], },
                    'memory': {
                        'total': meminfo['MemTotal'],
                        'free': meminfo['MemFree'],
                        'buffers': meminfo['Buffers'],
                        'cached': meminfo['Cached'],
                        'swap_used': meminfo['SwapCached'],
                        'shared': meminfo['Shmem'],
                        'slab': meminfo['Slab'], },
                    'disk': {
                        'used': (st.f_blocks - st.f_bfree) * st.f_frsize,
                        'available': st.f_bavail * st.f_frsize},
                    'load': self._load(),
                    'topology': consts.TOPOLOGY_SINGLE,
                    'topology_status': consts.TOPOLOGY_STATUS_OK,
                    'listeners': sorted(list(
                        set(haproxy_listener_list + udp_listener_list)))
                    if udp_listener_list else haproxy_listener_list,
                    'packages': {}}
            if extend_body:
                body.update(extend_body)
            return webob.Response(json=body)

        def _get_version_of_installed_package(self, name):

            cmd = self._osutils.cmd_get_version_of_installed_package(name)
            version = subprocess.check_output(cmd.split())
            return version

        def _count_haproxy_processes(self, lb_list):
            num = 0
            for lb_id in lb_list:
                if util.is_lb_running(lb_id):
                    # optional check if it's still running
                    num += 1
            return num

        def _count_udp_listener_processes(self, udp_driver, listener_list):
            num = 0
            for listener_id in listener_list:
                if udp_driver.is_listener_running(listener_id):
                    # optional check if it's still running
                    num += 1
            return num

        def _get_extend_body_from_udp_driver(self, extend_udp_driver):
            extend_info = extend_udp_driver.get_subscribed_amp_compile_info()
            extend_data = {}
            for extend in extend_info:
                package_version = self._get_version_of_installed_package(extend)
                extend_data['%s_version' % extend] = package_version
            return extend_data

        def _get_meminfo(self):
            re_parser = re.compile(r'^(?P<key>\S*):\s*(?P<value>\d*)\s*kB')
            result = dict()
            with open('/proc/meminfo', 'r') as meminfo:
                for line in meminfo:
                    match = re_parser.match(line)
                    if not match:
                        continue  # skip lines that don't parse
                    key, value = match.groups(['key', 'value'])
                    result[key] = int(value)
            return result

        def _cpu(self):
            with open('/proc/stat') as f:
                cpu = f.readline()
                vals = cpu.split(' ')
                return {
                    'user': vals[2],
                    'nice': vals[3],
                    'system': vals[4],
                    'idle': vals[5],
                    'iowait': vals[6],
                    'irq': vals[7],
                    'softirq': vals[8],
                    'total': sum([int(i) for i in vals[2:]])
                }

        def _load(self):
            with open('/proc/loadavg') as f:
                load = f.readline()
                vals = load.split(' ')
                return vals[:3]

        def _get_networks(self):
            networks = dict()
            with pyroute2.NetNS(consts.AMPHORA_NAMESPACE) as netns:
                for interface in netns.get_links():
                    interface_name = None
                    for item in interface['attrs']:
                        if (item[0] == 'IFLA_IFNAME' and
                                not item[1].startswith('eth')):
                            break
                        if item[0] == 'IFLA_IFNAME':
                            interface_name = item[1]
                        if item[0] == 'IFLA_STATS64':
                            networks[interface_name] = dict(
                                network_tx=item[1]['tx_bytes'],
                                network_rx=item[1]['rx_bytes'])
            return networks

        def get_interface(self, ip_addr):

            try:
                ip_version = ipaddress.ip_address(ip_addr).version
            except Exception:
                return webob.Response(
                    json=dict(message="Invalid IP address"), status=400)

            if ip_version == 4:
                address_format = netifaces.AF_INET
            elif ip_version == 6:
                address_format = netifaces.AF_INET6
            else:
                return webob.Response(
                    json=dict(message="Bad IP address version"), status=400)

            # We need to normalize the address as IPv6 has multiple representations
            # fe80:0000:0000:0000:f816:3eff:fef2:2058 == fe80::f816:3eff:fef2:2058
            normalized_addr = socket.inet_ntop(address_format,
                                               socket.inet_pton(address_format,
                                                                ip_addr))

            with pyroute2.NetNS(consts.AMPHORA_NAMESPACE) as netns:
                for addr in netns.get_addr():
                    # Save the interface index as IPv6 records don't list a
                    # textual interface
                    interface_idx = addr['index']
                    # Save the address family (IPv4/IPv6) for use normalizing
                    # the IP address for comparison
                    interface_af = addr['family']
                    # Search through the attributes of each address record
                    for attr in addr['attrs']:
                        # Look for the attribute name/value pair for the address
                        if attr[0] == 'IFA_ADDRESS':
                            # Compare the normalized address with the address we
                            # we are looking for.  Since we have matched the name
                            # above, attr[1] is the address value
                            if normalized_addr == socket.inet_ntop(
                                    interface_af,
                                    socket.inet_pton(interface_af, attr[1])):

                                # Lookup the matching interface name by
                                # getting the interface with the index we found
                                # in the above address search
                                lookup_int = netns.get_links(interface_idx)
                                # Search through the attributes of the matching
                                # interface record
                                for int_attr in lookup_int[0]['attrs']:
                                    # Look for the attribute name/value pair
                                    # that includes the interface name
                                    if int_attr[0] == 'IFLA_IFNAME':
                                        # Return the response with the matching
                                        # interface name that is in int_attr[1]
                                        # for the matching interface attribute
                                        # name
                                        return webob.Response(
                                            json=dict(message='OK',
                                                      interface=int_attr[1]),
                                            status=200)

            return webob.Response(
                json=dict(message="Error interface not found for IP address"),
                status=404)

this page last updated: 2020-04-10 18:17:54

Except where otherwise noted, this document is licensed under Creative Commons Attribution 3.0 License. See all OpenStack Legal Documents.

found an error? report a bug questions?