Source code for octavia.common.config

# Copyright 2011 VMware, Inc., 2014 A10 Networks
# All Rights Reserved.
#
#    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.

"""
Routines for configuring Octavia
"""

import os
import sys

from keystoneauth1 import loading as ks_loading
from octavia_lib.common import constants as lib_consts
from oslo_config import cfg
from oslo_db import options as db_options
from oslo_log import log as logging
import oslo_messaging as messaging
from oslo_middleware import cors

from octavia.certificates.common import local
from octavia.common import constants
from octavia.common import utils
from octavia.common import validate
from octavia.i18n import _
from octavia import version

LOG = logging.getLogger(__name__)

core_opts = [
    cfg.HostnameOpt('host', default=utils.get_hostname(),
                    sample_default='<server-hostname.example.com>',
                    help=_("The hostname Octavia is running on")),
    cfg.StrOpt('octavia_plugins', default='hot_plug_plugin',
               help=_("Name of the controller plugin to use")),
]

api_opts = [
    cfg.IPOpt('bind_host', default='127.0.0.1',
              help=_("The host IP to bind to")),
    cfg.PortOpt('bind_port', default=9876,
                help=_("The port to bind to")),
    cfg.StrOpt('auth_strategy', default=constants.KEYSTONE,
               choices=[constants.NOAUTH,
                        constants.KEYSTONE,
                        constants.TESTING],
               help=_("The auth strategy for API requests.")),
    cfg.BoolOpt('allow_pagination', default=True,
                help=_("Allow the usage of pagination")),
    cfg.BoolOpt('allow_sorting', default=True,
                help=_("Allow the usage of sorting")),
    cfg.BoolOpt('allow_filtering', default=True,
                help=_("Allow the usage of filtering")),
    cfg.BoolOpt('allow_field_selection', default=True,
                help=_("Allow the usage of field selection")),
    cfg.StrOpt('pagination_max_limit',
               default=str(constants.DEFAULT_PAGE_SIZE),
               help=_("The maximum number of items returned in a single "
                      "response. The string 'infinite' or a negative "
                      "integer value means 'no limit'")),
    cfg.StrOpt('api_base_uri',
               help=_("Base URI for the API for use in pagination links. "
                      "This will be autodetected from the request if not "
                      "overridden here.")),
    cfg.BoolOpt('allow_tls_terminated_listeners', default=True,
                help=_("Allow users to create TLS Terminated listeners?")),
    cfg.BoolOpt('allow_ping_health_monitors', default=True,
                help=_("Allow users to create PING type Health Monitors?")),
    cfg.BoolOpt('allow_prometheus_listeners', default=True,
                help=_("Allow users to create PROMETHEUS type listeners?")),
    cfg.DictOpt('enabled_provider_drivers',
                help=_('A comma separated list of dictionaries of the '
                       'enabled provider driver names and descriptions. '
                       'Must match the driver name in the '
                       'octavia.api.drivers entrypoint.'),
                default={'amphora': 'The Octavia Amphora driver.',
                         'octavia': 'Deprecated alias of the Octavia Amphora '
                                    'driver.',
                         }),
    cfg.StrOpt('default_provider_driver', default='amphora',
               help=_('Default provider driver.')),
    cfg.IntOpt('udp_connect_min_interval_health_monitor',
               default=3,
               help=_("The minimum health monitor delay interval for the "
                      "UDP-CONNECT Health Monitor type. A negative integer "
                      "value means 'no limit'.")),
    cfg.BoolOpt('healthcheck_enabled', default=False,
                help=_("When True, the oslo middleware healthcheck endpoint "
                       "is enabled in the Octavia API.")),
    cfg.IntOpt('healthcheck_refresh_interval', default=5,
               help=_("The interval healthcheck plugins should cache results, "
                      "in seconds.")),
    cfg.StrOpt('default_listener_ciphers',
               default=constants.CIPHERS_OWASP_SUITE_B,
               help=_("Default OpenSSL cipher string (colon-separated) for "
                      "new TLS-enabled listeners.")),
    cfg.StrOpt('default_pool_ciphers',
               default=constants.CIPHERS_OWASP_SUITE_B,
               help=_("Default OpenSSL cipher string (colon-separated) for "
                      "new TLS-enabled pools.")),
    cfg.StrOpt('tls_cipher_prohibit_list', default='',
               deprecated_name='tls_cipher_blacklist',
               help=_("Colon separated list of OpenSSL ciphers. "
                      "Usage of these ciphers will be blocked.")),
    cfg.ListOpt('default_listener_tls_versions',
                default=constants.TLS_VERSIONS_OWASP_SUITE_B,
                item_type=cfg.types.String(
                    choices=constants.TLS_ALL_VERSIONS),
                help=_('List of TLS versions to use for new TLS-enabled '
                       'listeners.')),
    cfg.ListOpt('default_pool_tls_versions',
                default=constants.TLS_VERSIONS_OWASP_SUITE_B,
                item_type=cfg.types.String(
                    choices=constants.TLS_ALL_VERSIONS),
                help=_('List of TLS versions to use for new TLS-enabled '
                       'pools.')),
    cfg.StrOpt('minimum_tls_version',
               default=None,
               choices=constants.TLS_ALL_VERSIONS + [None],
               help=_('Minimum allowed TLS version for listeners and pools.')),
    cfg.ListOpt('default_listener_alpn_protocols',
                default=[lib_consts.ALPN_PROTOCOL_HTTP_2,
                         lib_consts.ALPN_PROTOCOL_HTTP_1_1,
                         lib_consts.ALPN_PROTOCOL_HTTP_1_0],
                item_type=cfg.types.String(
                    choices=constants.SUPPORTED_ALPN_PROTOCOLS),
                help=_('List of ALPN protocols to use for new TLS-enabled '
                       'listeners.')),
    cfg.ListOpt('default_pool_alpn_protocols',
                default=[lib_consts.ALPN_PROTOCOL_HTTP_2,
                         lib_consts.ALPN_PROTOCOL_HTTP_1_1,
                         lib_consts.ALPN_PROTOCOL_HTTP_1_0],
                item_type=cfg.types.String(
                    choices=constants.SUPPORTED_ALPN_PROTOCOLS),
                help=_('List of ALPN protocols to use for new TLS-enabled '
                       'pools.')),
]

# Options only used by the amphora agent
amphora_agent_opts = [
    cfg.StrOpt('agent_server_ca', default='/etc/octavia/certs/client_ca.pem',
               help=_("The ca which signed the client certificates")),
    cfg.StrOpt('agent_server_cert', default='/etc/octavia/certs/server.pem',
               help=_("The server certificate for the agent server "
                      "to use")),
    cfg.StrOpt('agent_server_network_dir',
               help=_("The directory where new network interfaces "
                      "are located")),
    cfg.IntOpt('agent_request_read_timeout', default=180,
               help=_("The time in seconds to allow a request from the "
                      "controller to run before terminating the socket.")),
    cfg.StrOpt('agent_tls_protocol', default=lib_consts.TLS_VERSION_1_2,
               help=_("Minimum TLS protocol for communication with the "
                      "amphora agent."),
               choices=constants.TLS_ALL_VERSIONS),

    # Logging setup
    cfg.ListOpt('admin_log_targets',
                help=_('List of log server ip and port pairs for '
                       'Administrative logs. Additional hosts are backup to '
                       'the primary server. If none is '
                       'specified remote logging is disabled. Example '
                       '127.0.0.1:10514, 192.168.0.1:10514')),
    cfg.ListOpt('tenant_log_targets',
                help=_('List of log server ip and port pairs for '
                       'tenant traffic logs. Additional hosts are backup to '
                       'the primary server. If none is '
                       'specified remote logging is disabled. Example '
                       '127.0.0.1:10514, 192.168.0.1:10514')),
    cfg.IntOpt('user_log_facility', default=0, min=0, max=7,
               help=_('LOG_LOCAL facility number to use for user traffic '
                      'logs.')),
    cfg.IntOpt('administrative_log_facility', default=1, min=0, max=7,
               help=_('LOG_LOCAL facility number to use for amphora processes '
                      'logs.')),
    cfg.StrOpt('log_protocol', default=lib_consts.PROTOCOL_UDP,
               choices=[lib_consts.PROTOCOL_TCP, lib_consts.PROTOCOL_UDP],
               help=_("The log forwarding transport protocol. One of UDP or "
                      "TCP.")),
    cfg.IntOpt('log_retry_count', default=5,
               help=_('The maximum attempts to retry connecting to the '
                      'logging host.')),
    cfg.IntOpt('log_retry_interval', default=2,
               help=_('The time, in seconds, to wait between retries '
                      'connecting to the logging host.')),
    cfg.IntOpt('log_queue_size', default=10000,
               help=_('The queue size (messages) to buffer log messages.')),
    cfg.StrOpt('logging_template_override',
               help=_('Custom logging configuration template.')),
    cfg.BoolOpt('forward_all_logs', default=False,
                help=_('When True, the amphora will forward all of the '
                       'system logs (except tenant traffic logs) to the '
                       'admin log target(s). When False, '
                       'only amphora specific admin logs will be forwarded.')),
    cfg.BoolOpt('disable_local_log_storage', default=False,
                help=_('When True, no logs will be written to the amphora '
                       'filesystem. When False, log files will be written to '
                       'the local filesystem.')),

    # Do not specify in octavia.conf, loaded at runtime
    cfg.StrOpt('amphora_id', help=_("The amphora ID.")),
    cfg.StrOpt('amphora_udp_driver',
               default='keepalived_lvs',
               help='The UDP API backend for amphora agent.',
               deprecated_for_removal=True,
               deprecated_reason=_('amphora-agent will not support any other '
                                   'backend than keepalived_lvs.'),
               deprecated_since='Wallaby'),
]

compute_opts = [
    cfg.IntOpt('max_retries', default=15,
               help=_('The maximum attempts to retry an action with the '
                      'compute service.')),
    cfg.IntOpt('retry_interval', default=1,
               help=_('Seconds to wait before retrying an action with the '
                      'compute service.')),
    cfg.IntOpt('retry_backoff', default=1,
               help=_('The seconds to backoff retry attempts.')),
    cfg.IntOpt('retry_max', default=10,
               help=_('The maximum interval in seconds between retry '
                      'attempts.')),
]

networking_opts = [
    cfg.IntOpt('max_retries', default=15,
               help=_('The maximum attempts to retry an action with the '
                      'networking service.')),
    cfg.IntOpt('retry_interval', default=1,
               help=_('Seconds to wait before retrying an action with the '
                      'networking service.')),
    cfg.IntOpt('retry_backoff', default=1,
               help=_('The seconds to backoff retry attempts.')),
    cfg.IntOpt('retry_max', default=10,
               help=_('The maximum interval in seconds between retry '
                      'attempts.')),
    cfg.IntOpt('port_detach_timeout', default=300,
               help=_('Seconds to wait for a port to detach from an '
                      'amphora.')),
    cfg.BoolOpt('allow_vip_network_id', default=True,
                help=_('Can users supply a network_id for their VIP?')),
    cfg.BoolOpt('allow_vip_subnet_id', default=True,
                help=_('Can users supply a subnet_id for their VIP?')),
    cfg.BoolOpt('allow_vip_port_id', default=True,
                help=_('Can users supply a port_id for their VIP?')),
    cfg.ListOpt('valid_vip_networks',
                help=_('List of network_ids that are valid for VIP '
                       'creation. If this field is empty, no validation '
                       'is performed.')),
    cfg.ListOpt('reserved_ips',
                default=['169.254.169.254'],
                item_type=cfg.types.IPAddress(),
                help=_('List of IP addresses reserved from being used for '
                       'member addresses. IPv6 addresses should be in '
                       'expanded, uppercase form.')),
    cfg.BoolOpt('allow_invisible_resource_usage', default=False,
                help=_("When True, users can use network resources they "
                       "cannot normally see as VIP or member subnets. Making "
                       "this True may allow users to access resources on "
                       "subnets they do not normally have access to via "
                       "neutron RBAC policies.")),
]

health_manager_opts = [
    cfg.IPOpt('bind_ip', default='127.0.0.1',
              help=_('IP address the controller will listen on for '
                     'heart beats')),
    cfg.PortOpt('bind_port', default=5555,
                help=_('Port number the controller will listen on '
                       'for heart beats')),
    cfg.IntOpt('failover_threads',
               default=10,
               help=_('Number of threads performing amphora failovers.')),
    cfg.IntOpt('health_update_threads',
               default=None,
               help=_('Number of processes for amphora health update.')),
    cfg.IntOpt('stats_update_threads',
               default=None,
               help=_('Number of processes for amphora stats update.')),
    cfg.StrOpt('heartbeat_key',
               mutable=True,
               help=_('key used to validate amphora sending '
                      'the message'), secret=True),
    cfg.IntOpt('heartbeat_timeout',
               default=60,
               help=_('Interval, in seconds, to wait before failing over an '
                      'amphora.')),
    cfg.IntOpt('health_check_interval',
               default=3,
               help=_('Sleep time between health checks in seconds.')),
    cfg.IntOpt('sock_rlimit', default=0,
               help=_(' sets the value of the heartbeat recv buffer')),
    cfg.IntOpt('failover_threshold', default=None,
               help=_('Stop failovers if the count of simultaneously failed '
                      'amphora reaches this number. This may prevent large '
                      'scale accidental failover events, like in the case of '
                      'network failures or read-only database issues.')),

    # Used by the health manager on the amphora
    cfg.ListOpt('controller_ip_port_list',
                help=_('List of controller ip and port pairs for the '
                       'heartbeat receivers. Example 127.0.0.1:5555, '
                       '192.168.0.1:5555'),
                mutable=True,
                default=[]),
    cfg.IntOpt('heartbeat_interval',
               default=10,
               mutable=True,
               help=_('Sleep time between sending heartbeats.')),
]

oslo_messaging_opts = [
    cfg.StrOpt('topic', help=_('Topic (i.e. Queue) Name')),
]

haproxy_amphora_opts = [
    cfg.StrOpt('base_path',
               default='/var/lib/octavia',
               help=_('Base directory for amphora files.')),
    cfg.StrOpt('base_cert_dir',
               default='/var/lib/octavia/certs',
               help=_('Base directory for cert storage.')),
    cfg.StrOpt('haproxy_template', help=_('Custom haproxy template.')),
    cfg.BoolOpt('connection_logging', default=True,
                help=_('Set this to False to disable connection logging.')),
    cfg.IntOpt('connection_max_retries',
               default=120,
               help=_('Retry threshold for connecting to amphorae.')),
    cfg.IntOpt('connection_retry_interval',
               default=5,
               help=_('Retry timeout between connection attempts in '
                      'seconds.')),
    cfg.IntOpt('active_connection_max_retries',
               default=15,
               help=_('Retry threshold for connecting to active amphorae.')),
    cfg.IntOpt('active_connection_retry_interval',
               default=2,
               deprecated_name='active_connection_rety_interval',
               help=_('Retry timeout between connection attempts in '
                      'seconds for active amphora.')),
    cfg.IntOpt('failover_connection_max_retries',
               default=2,
               help=_('Retry threshold for connecting to an amphora in '
                      'failover.')),
    cfg.IntOpt('failover_connection_retry_interval',
               default=5,
               help=_('Retry timeout between connection attempts in '
                      'seconds for amphora in failover.')),
    cfg.IntOpt('build_rate_limit',
               default=-1,
               help=_('Number of amphorae that could be built per controller '
                      'worker, simultaneously.')),
    cfg.IntOpt('build_active_retries',
               default=120,
               help=_('Retry threshold for waiting for a build slot for '
                      'an amphorae.')),
    cfg.IntOpt('build_retry_interval',
               default=5,
               help=_('Retry timeout between build attempts in '
                      'seconds.')),
    cfg.StrOpt('haproxy_stick_size', default='10k',
               help=_(