"Fossies" - the Fresh Open Source Software Archive

Member "openstack-heat-13.0.0/heat/common/config.py" (16 Oct 2019, 27027 Bytes) of package /linux/misc/openstack/openstack-heat-13.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "config.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 12.0.0_vs_13.0.0.

    1 #
    2 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    3 #    not use this file except in compliance with the License. You may obtain
    4 #    a copy of the License at
    5 #
    6 #         http://www.apache.org/licenses/LICENSE-2.0
    7 #
    8 #    Unless required by applicable law or agreed to in writing, software
    9 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   10 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   11 #    License for the specific language governing permissions and limitations
   12 #    under the License.
   13 
   14 """Routines for configuring Heat."""
   15 import os
   16 
   17 from eventlet.green import socket
   18 from oslo_config import cfg
   19 from oslo_log import log as logging
   20 from oslo_middleware import cors
   21 from osprofiler import opts as profiler
   22 
   23 from heat.common import exception
   24 from heat.common.i18n import _
   25 from heat.common import wsgi
   26 
   27 
   28 LOG = logging.getLogger(__name__)
   29 paste_deploy_group = cfg.OptGroup('paste_deploy')
   30 paste_deploy_opts = [
   31     cfg.StrOpt('flavor',
   32                help=_("The flavor to use.")),
   33     cfg.StrOpt('api_paste_config', default="api-paste.ini",
   34                help=_("The API paste config file to use."))]
   35 
   36 
   37 service_opts = [
   38     cfg.IntOpt('periodic_interval',
   39                default=60,
   40                help=_('Seconds between running periodic tasks.')),
   41     cfg.StrOpt('heat_metadata_server_url',
   42                help=_('URL of the Heat metadata server. '
   43                       'NOTE: Setting this is only needed if you require '
   44                       'instances to use a different endpoint than in the '
   45                       'keystone catalog')),
   46     cfg.StrOpt('heat_waitcondition_server_url',
   47                help=_('URL of the Heat waitcondition server.')),
   48     cfg.StrOpt('heat_watch_server_url',
   49                default="",
   50                deprecated_for_removal=True,
   51                deprecated_reason='Heat CloudWatch Service has been removed.',
   52                deprecated_since='10.0.0',
   53                help=_('URL of the Heat CloudWatch server.')),
   54     cfg.StrOpt('instance_connection_is_secure',
   55                default="0",
   56                help=_('Instance connection to CFN/CW API via https.')),
   57     cfg.StrOpt('instance_connection_https_validate_certificates',
   58                default="1",
   59                help=_('Instance connection to CFN/CW API validate certs if '
   60                       'SSL is used.')),
   61     cfg.StrOpt('region_name_for_services',
   62                help=_('Default region name used to get services endpoints.')),
   63     cfg.StrOpt('heat_stack_user_role',
   64                default="heat_stack_user",
   65                help=_('Keystone role for heat template-defined users.')),
   66     cfg.StrOpt('stack_user_domain_id',
   67                deprecated_opts=[cfg.DeprecatedOpt('stack_user_domain',
   68                                                   group=None)],
   69                help=_('Keystone domain ID which contains heat '
   70                       'template-defined users. If this option is set, '
   71                       'stack_user_domain_name option will be ignored.')),
   72     cfg.StrOpt('stack_user_domain_name',
   73                help=_('Keystone domain name which contains heat '
   74                       'template-defined users. If `stack_user_domain_id` '
   75                       'option is set, this option is ignored.')),
   76     cfg.StrOpt('stack_domain_admin',
   77                help=_('Keystone username, a user with roles sufficient to '
   78                       'manage users and projects in the stack_user_domain.')),
   79     cfg.StrOpt('stack_domain_admin_password',
   80                secret=True,
   81                help=_('Keystone password for stack_domain_admin user.')),
   82     cfg.IntOpt('max_template_size',
   83                default=524288,
   84                help=_('Maximum raw byte size of any template.')),
   85     cfg.IntOpt('max_nested_stack_depth',
   86                default=5,
   87                help=_('Maximum depth allowed when using nested stacks.')),
   88     cfg.IntOpt('num_engine_workers',
   89                help=_('Number of heat-engine processes to fork and run. '
   90                       'Will default to either to 4 or number of CPUs on '
   91                       'the host, whichever is greater.')),
   92     cfg.StrOpt('server_keystone_endpoint_type',
   93                choices=['', 'public', 'internal', 'admin'],
   94                default='',
   95                help=_('If set, is used to control which authentication '
   96                       'endpoint is used by user-controlled servers to make '
   97                       'calls back to Heat. '
   98                       'If unset www_authenticate_uri is used.'))]
   99 
  100 engine_opts = [
  101     cfg.ListOpt('plugin_dirs',
  102                 default=['/usr/lib64/heat', '/usr/lib/heat',
  103                          '/usr/local/lib/heat', '/usr/local/lib64/heat'],
  104                 help=_('List of directories to search for plug-ins.')),
  105     cfg.StrOpt('environment_dir',
  106                default='/etc/heat/environment.d',
  107                help=_('The directory to search for environment files.')),
  108     cfg.StrOpt('template_dir',
  109                default='/etc/heat/templates',
  110                help=_('The directory to search for template files.')),
  111     cfg.StrOpt('deferred_auth_method',
  112                choices=['password', 'trusts'],
  113                default='trusts',
  114                deprecated_for_removal=True,
  115                deprecated_reason='Stored password based deferred auth is '
  116                                  'broken when used with keystone v3 and '
  117                                  'is not supported.',
  118                deprecated_since='9.0.0',
  119                help=_('Select deferred auth method, '
  120                       'stored password or trusts.')),
  121     cfg.StrOpt('reauthentication_auth_method',
  122                choices=['', 'trusts'],
  123                default='',
  124                help=_('Allow reauthentication on token expiry, such that'
  125                       ' long-running tasks may complete. Note this defeats'
  126                       ' the expiry of any provided user tokens.')),
  127     cfg.BoolOpt('allow_trusts_redelegation',
  128                 default=False,
  129                 help=_('Create trusts with redelegation enabled. '
  130                        'This option is only used when '
  131                        'reauthentication_auth_method is set to "trusts". '
  132                        'Note that enabling this option does have '
  133                        'security implications as all trusts created by Heat '
  134                        'will use both impersonation and redelegation enabled. '
  135                        'Enable it only when there are other services that '
  136                        'need to create trusts from tokens Heat uses to '
  137                        'access them, examples are Aodh and Heat in another '
  138                        'region when configured to use trusts too.')),
  139     cfg.ListOpt('trusts_delegated_roles',
  140                 default=[],
  141                 help=_('Subset of trustor roles to be delegated to heat.'
  142                        ' If left unset, all roles of a user will be'
  143                        ' delegated to heat when creating a stack.')),
  144     cfg.IntOpt('max_resources_per_stack',
  145                default=1000,
  146                help=_('Maximum resources allowed per top-level stack. '
  147                       '-1 stands for unlimited.')),
  148     cfg.IntOpt('max_stacks_per_tenant',
  149                default=100,
  150                help=_('Maximum number of stacks any one tenant may have'
  151                       ' active at one time.')),
  152     cfg.IntOpt('action_retry_limit',
  153                default=5,
  154                help=_('Number of times to retry to bring a '
  155                       'resource to a non-error state. Set to 0 to disable '
  156                       'retries.')),
  157     cfg.IntOpt('client_retry_limit',
  158                default=2,
  159                help=_('Number of times to retry when a client encounters an '
  160                       'expected intermittent error. Set to 0 to disable '
  161                       'retries.')),
  162     # Server host name limit to 53 characters by due to typical default
  163     # linux HOST_NAME_MAX of 64, minus the .novalocal appended to the name
  164     cfg.IntOpt('max_server_name_length',
  165                default=53,
  166                max=53,
  167                help=_('Maximum length of a server name to be used '
  168                       'in nova.')),
  169     cfg.IntOpt('max_interface_check_attempts',
  170                min=1,
  171                default=10,
  172                help=_('Number of times to check whether an interface has '
  173                       'been attached or detached.')),
  174     cfg.FloatOpt('max_nova_api_microversion',
  175                  help=_('Maximum nova API version for client plugin. With '
  176                         'this limitation, any nova feature supported with '
  177                         'microversion number above max_nova_api_microversion '
  178                         'will not be available.')),
  179     cfg.IntOpt('event_purge_batch_size',
  180                min=1,
  181                default=200,
  182                help=_("Controls how many events will be pruned whenever a "
  183                       "stack's events are purged. Set this "
  184                       "lower to keep more events at the expense of more "
  185                       "frequent purges.")),
  186     cfg.IntOpt('max_events_per_stack',
  187                default=1000,
  188                help=_('Rough number of maximum events that will be available '
  189                       'per stack. Actual number of events can be a bit '
  190                       'higher since purge checks take place randomly '
  191                       '200/event_purge_batch_size percent of the time. '
  192                       'Older events are deleted when events are purged. '
  193                       'Set to 0 for unlimited events per stack.')),
  194     cfg.IntOpt('stack_action_timeout',
  195                default=3600,
  196                help=_('Timeout in seconds for stack action (ie. create or'
  197                       ' update).')),
  198     cfg.IntOpt('error_wait_time',
  199                default=240,
  200                help=_('The amount of time in seconds after an error has'
  201                       ' occurred that tasks may continue to run before'
  202                       ' being cancelled.')),
  203     cfg.IntOpt('engine_life_check_timeout',
  204                default=2,
  205                help=_('RPC timeout for the engine liveness check that is used'
  206                       ' for stack locking.')),
  207     cfg.BoolOpt('enable_cloud_watch_lite',
  208                 default=False,
  209                 deprecated_for_removal=True,
  210                 deprecated_reason='Heat CloudWatch Service has been removed.',
  211                 deprecated_since='10.0.0',
  212                 help=_('Enable the legacy OS::Heat::CWLiteAlarm resource.')),
  213     cfg.BoolOpt('enable_stack_abandon',
  214                 default=False,
  215                 help=_('Enable the preview Stack Abandon feature.')),
  216     cfg.BoolOpt('enable_stack_adopt',
  217                 default=False,
  218                 help=_('Enable the preview Stack Adopt feature.')),
  219     cfg.BoolOpt('convergence_engine',
  220                 default=True,
  221                 help=_('Enables engine with convergence architecture. All '
  222                        'stacks with this option will be created using '
  223                        'convergence engine.')),
  224     cfg.BoolOpt('observe_on_update',
  225                 default=False,
  226                 help=_('On update, enables heat to collect existing resource '
  227                        'properties from reality and converge to '
  228                        'updated template.')),
  229     cfg.StrOpt('default_software_config_transport',
  230                choices=['POLL_SERVER_CFN',
  231                         'POLL_SERVER_HEAT',
  232                         'POLL_TEMP_URL',
  233                         'ZAQAR_MESSAGE'],
  234                default='POLL_SERVER_CFN',
  235                help=_('Template default for how the server should receive the '
  236                       'metadata required for software configuration. '
  237                       'POLL_SERVER_CFN will allow calls to the cfn API action '
  238                       'DescribeStackResource authenticated with the provided '
  239                       'keypair (requires enabled heat-api-cfn). '
  240                       'POLL_SERVER_HEAT will allow calls to the '
  241                       'Heat API resource-show using the provided keystone '
  242                       'credentials (requires keystone v3 API, and configured '
  243                       'stack_user_* config options). '
  244                       'POLL_TEMP_URL will create and populate a '
  245                       'Swift TempURL with metadata for polling (requires '
  246                       'object-store endpoint which supports TempURL).'
  247                       'ZAQAR_MESSAGE will create a dedicated zaqar queue and '
  248                       'post the metadata for polling.')),
  249     cfg.StrOpt('default_deployment_signal_transport',
  250                choices=['CFN_SIGNAL',
  251                         'TEMP_URL_SIGNAL',
  252                         'HEAT_SIGNAL',
  253                         'ZAQAR_SIGNAL'],
  254                default='CFN_SIGNAL',
  255                help=_('Template default for how the server should signal to '
  256                       'heat with the deployment output values. CFN_SIGNAL '
  257                       'will allow an HTTP POST to a CFN keypair signed URL '
  258                       '(requires enabled heat-api-cfn). '
  259                       'TEMP_URL_SIGNAL will create a Swift TempURL to be '
  260                       'signaled via HTTP PUT (requires object-store endpoint '
  261                       'which supports TempURL). '
  262                       'HEAT_SIGNAL will allow calls to the Heat API '
  263                       'resource-signal using the provided keystone '
  264                       'credentials. ZAQAR_SIGNAL will create a dedicated '
  265                       'zaqar queue to be signaled using the provided keystone '
  266                       'credentials.')),
  267     cfg.StrOpt('default_user_data_format',
  268                choices=['HEAT_CFNTOOLS',
  269                         'RAW',
  270                         'SOFTWARE_CONFIG'],
  271                default='HEAT_CFNTOOLS',
  272                help=_('Template default for how the user_data should be '
  273                       'formatted for the server. For HEAT_CFNTOOLS, the '
  274                       'user_data is bundled as part of the heat-cfntools '
  275                       'cloud-init boot configuration data. For RAW the '
  276                       'user_data is passed to Nova unmodified. For '
  277                       'SOFTWARE_CONFIG user_data is bundled as part of the '
  278                       'software config data, and metadata is derived from any '
  279                       'associated SoftwareDeployment resources.')),
  280     cfg.ListOpt('hidden_stack_tags',
  281                 default=['data-processing-cluster'],
  282                 help=_('Stacks containing these tag names will be hidden. '
  283                        'Multiple tags should be given in a comma-delimited '
  284                        'list (eg. hidden_stack_tags=hide_me,me_too).')),
  285     cfg.StrOpt('onready',
  286                help=_('Deprecated.')),
  287     cfg.BoolOpt('stack_scheduler_hints',
  288                 default=False,
  289                 help=_('When this feature is enabled, scheduler hints'
  290                        ' identifying the heat stack context of a server'
  291                        ' or volume resource are passed to the configured'
  292                        ' schedulers in nova and cinder, for creates done'
  293                        ' using heat resource types OS::Cinder::Volume,'
  294                        ' OS::Nova::Server, and AWS::EC2::Instance.'
  295                        ' heat_root_stack_id will be set to the id of the'
  296                        ' root stack of the resource, heat_stack_id will be'
  297                        ' set to the id of the resource\'s parent stack,'
  298                        ' heat_stack_name will be set to the name of the'
  299                        ' resource\'s parent stack, heat_path_in_stack will'
  300                        ' be set to a list of comma delimited strings of'
  301                        ' stackresourcename and stackname with list[0] being'
  302                        ' \'rootstackname\', heat_resource_name will be set to'
  303                        ' the resource\'s name, and heat_resource_uuid will be'
  304                        ' set to the resource\'s orchestration id.')),
  305     cfg.BoolOpt('encrypt_parameters_and_properties',
  306                 default=False,
  307                 help=_('Encrypt template parameters that were marked as'
  308                        ' hidden and also all the resource properties before'
  309                        ' storing them in database.'))]
  310 
  311 rpc_opts = [
  312     cfg.StrOpt('host',
  313                default=socket.gethostname(),
  314                sample_default='<Hostname>',
  315                help=_('Name of the engine node. '
  316                       'This can be an opaque identifier. '
  317                       'It is not necessarily a hostname, FQDN, '
  318                       'or IP address.'))]
  319 
  320 auth_password_group = cfg.OptGroup('auth_password')
  321 auth_password_opts = [
  322     cfg.BoolOpt('multi_cloud',
  323                 default=False,
  324                 help=_('Allow orchestration of multiple clouds.')),
  325     cfg.ListOpt('allowed_auth_uris',
  326                 default=[],
  327                 help=_('Allowed keystone endpoints for auth_uri when '
  328                        'multi_cloud is enabled. At least one endpoint needs '
  329                        'to be specified.'))]
  330 
  331 # these options define baseline defaults that apply to all clients
  332 default_clients_opts = [
  333     cfg.StrOpt('endpoint_type',
  334                default='publicURL',
  335                help=_(
  336                    'Type of endpoint in Identity service catalog to use '
  337                    'for communication with the OpenStack service.')),
  338     cfg.StrOpt('ca_file',
  339                help=_('Optional CA cert file to use in SSL connections.')),
  340     cfg.StrOpt('cert_file',
  341                help=_('Optional PEM-formatted certificate chain file.')),
  342     cfg.StrOpt('key_file',
  343                help=_('Optional PEM-formatted file that contains the '
  344                       'private key.')),
  345     cfg.BoolOpt('insecure',
  346                 default=False,
  347                 help=_("If set, then the server's certificate will not "
  348                        "be verified."))]
  349 
  350 # these options can be defined for each client
  351 # they must not specify defaults, since any options not defined in a client
  352 # specific group is looked up on the generic group above
  353 clients_opts = [
  354     cfg.StrOpt('endpoint_type',
  355                help=_(
  356                    'Type of endpoint in Identity service catalog to use '
  357                    'for communication with the OpenStack service.')),
  358     cfg.StrOpt('ca_file',
  359                help=_('Optional CA cert file to use in SSL connections.')),
  360     cfg.StrOpt('cert_file',
  361                help=_('Optional PEM-formatted certificate chain file.')),
  362     cfg.StrOpt('key_file',
  363                help=_('Optional PEM-formatted file that contains the '
  364                       'private key.')),
  365     cfg.BoolOpt('insecure',
  366                 help=_("If set, then the server's certificate will not "
  367                        "be verified."))]
  368 
  369 heat_client_opts = [
  370     cfg.StrOpt('url',
  371                default='',
  372                help=_('Optional heat url in format like'
  373                       ' http://0.0.0.0:8004/v1/%(tenant_id)s.'))]
  374 
  375 keystone_client_opts = [
  376     cfg.StrOpt('auth_uri',
  377                default='',
  378                help=_('Unversioned keystone url in format like'
  379                       ' http://0.0.0.0:5000.'))]
  380 
  381 client_http_log_debug_opts = [
  382     cfg.BoolOpt('http_log_debug',
  383                 default=False,
  384                 help=_("Allow client's debug log output."))]
  385 
  386 revision_group = cfg.OptGroup('revision')
  387 revision_opts = [
  388     cfg.StrOpt('heat_revision',
  389                default='unknown',
  390                help=_('Heat build revision. '
  391                       'If you would prefer to manage your build revision '
  392                       'separately, you can move this section to a different '
  393                       'file and add it as another config option.'))]
  394 
  395 volumes_group = cfg.OptGroup('volumes')
  396 volumes_opts = [
  397     cfg.BoolOpt('backups_enabled',
  398                 default=True,
  399                 help=_("Indicate if cinder-backup service is enabled. "
  400                        "This is a temporary workaround until cinder-backup "
  401                        "service becomes discoverable, see LP#1334856."))]
  402 
  403 noauth_group = cfg.OptGroup('noauth')
  404 noauth_opts = [
  405     cfg.StrOpt('token_response',
  406                default='',
  407                help=_("JSON file containing the content returned by the "
  408                       "noauth middleware."))]
  409 
  410 
  411 def startup_sanity_check():
  412     if (not cfg.CONF.stack_user_domain_id and
  413             not cfg.CONF.stack_user_domain_name):
  414         # FIXME(shardy): Legacy fallback for folks using old heat.conf
  415         # files which lack domain configuration
  416         LOG.warning('stack_user_domain_id or stack_user_domain_name not '
  417                     'set in heat.conf falling back to using default')
  418     else:
  419         domain_admin_user = cfg.CONF.stack_domain_admin
  420         domain_admin_password = cfg.CONF.stack_domain_admin_password
  421         if not (domain_admin_user and domain_admin_password):
  422             raise exception.Error(_('heat.conf misconfigured, cannot '
  423                                     'specify "stack_user_domain_id" or '
  424                                     '"stack_user_domain_name" without '
  425                                     '"stack_domain_admin" and '
  426                                     '"stack_domain_admin_password"'))
  427     auth_key_len = len(cfg.CONF.auth_encryption_key)
  428     if auth_key_len in (16, 24):
  429         LOG.warning(
  430             'Please update auth_encryption_key to be 32 characters.')
  431     elif auth_key_len != 32:
  432         raise exception.Error(_('heat.conf misconfigured, auth_encryption_key '
  433                                 'must be 32 characters'))
  434 
  435 
  436 def list_opts():
  437     yield None, rpc_opts
  438     yield None, engine_opts
  439     yield None, service_opts
  440     yield paste_deploy_group.name, paste_deploy_opts
  441     yield auth_password_group.name, auth_password_opts
  442     yield revision_group.name, revision_opts
  443     yield volumes_group.name, volumes_opts
  444     yield noauth_group.name, noauth_opts
  445     yield profiler.list_opts()[0]
  446     yield 'clients', default_clients_opts
  447 
  448     for client in ('aodh', 'barbican', 'cinder', 'designate',
  449                    'glance', 'heat', 'keystone', 'magnum', 'manila', 'mistral',
  450                    'monasca', 'neutron', 'nova', 'octavia', 'sahara', 'senlin',
  451                    'swift', 'trove', 'zaqar'
  452                    ):
  453         client_specific_group = 'clients_' + client
  454         yield client_specific_group, clients_opts
  455 
  456     yield 'clients_heat', heat_client_opts
  457     yield 'clients_keystone', keystone_client_opts
  458     yield 'clients_nova', client_http_log_debug_opts
  459     yield 'clients_cinder', client_http_log_debug_opts
  460 
  461 
  462 cfg.CONF.register_group(paste_deploy_group)
  463 cfg.CONF.register_group(auth_password_group)
  464 cfg.CONF.register_group(revision_group)
  465 profiler.set_defaults(cfg.CONF)
  466 
  467 for group, opts in list_opts():
  468     cfg.CONF.register_opts(opts, group=group)
  469 
  470 
  471 def _get_deployment_flavor():
  472     """Retrieves the paste_deploy.flavor config item.
  473 
  474     Item formatted appropriately for appending to the application name.
  475     """
  476     flavor = cfg.CONF.paste_deploy.flavor
  477     return '' if not flavor else ('-' + flavor)
  478 
  479 
  480 def _get_deployment_config_file():
  481     """Retrieves the deployment_config_file config item.
  482 
  483     Item formatted as an absolute pathname.
  484     """
  485     config_path = cfg.CONF.find_file(
  486         cfg.CONF.paste_deploy['api_paste_config'])
  487     if config_path is None:
  488         return None
  489 
  490     return os.path.abspath(config_path)
  491 
  492 
  493 def load_paste_app(app_name=None):
  494     """Builds and returns a WSGI app from a paste config file.
  495 
  496     We assume the last config file specified in the supplied ConfigOpts
  497     object is the paste config file.
  498 
  499     :param app_name: name of the application to load
  500 
  501     :raises RuntimeError: when config file cannot be located or application
  502             cannot be loaded from config file
  503     """
  504     if app_name is None:
  505         app_name = cfg.CONF.prog
  506 
  507     # append the deployment flavor to the application name,
  508     # in order to identify the appropriate paste pipeline
  509     app_name += _get_deployment_flavor()
  510 
  511     conf_file = _get_deployment_config_file()
  512     if conf_file is None:
  513         raise RuntimeError(_("Unable to locate config file [%s]") %
  514                            cfg.CONF.paste_deploy['api_paste_config'])
  515 
  516     try:
  517         app = wsgi.paste_deploy_app(conf_file, app_name, cfg.CONF)
  518 
  519         # Log the options used when starting if we're in debug mode...
  520         if cfg.CONF.debug:
  521             cfg.CONF.log_opt_values(logging.getLogger(app_name),
  522                                     logging.DEBUG)
  523 
  524         return app
  525     except (LookupError, ImportError) as e:
  526         raise RuntimeError(_("Unable to load %(app_name)s from "
  527                              "configuration file %(conf_file)s."
  528                              "\nGot: %(e)r") % {'app_name': app_name,
  529                                                 'conf_file': conf_file,
  530                                                 'e': e})
  531 
  532 
  533 def get_client_option(client, option):
  534     # look for the option in the [clients_${client}] section
  535     # unknown options raise cfg.NoSuchOptError
  536     try:
  537         group_name = 'clients_' + client
  538         cfg.CONF.import_opt(option, 'heat.common.config',
  539                             group=group_name)
  540         v = getattr(getattr(cfg.CONF, group_name), option)
  541         if v is not None:
  542             return v
  543     except cfg.NoSuchGroupError:
  544         pass  # do not error if the client is unknown
  545     # look for the option in the generic [clients] section
  546     cfg.CONF.import_opt(option, 'heat.common.config', group='clients')
  547     return getattr(cfg.CONF.clients, option)
  548 
  549 
  550 def get_ssl_options(client):
  551     # Look for the ssl options in the [clients_${client}] section
  552     cacert = get_client_option(client, 'ca_file')
  553     insecure = get_client_option(client, 'insecure')
  554     cert = get_client_option(client, 'cert_file')
  555     key = get_client_option(client, 'key_file')
  556     if insecure:
  557         verify = False
  558     else:
  559         verify = cacert or True
  560     if cert and key:
  561         cert = (cert, key)
  562     return {'verify': verify, 'cert': cert}
  563 
  564 
  565 def set_config_defaults():
  566     """This method updates all configuration default values."""
  567     cors.set_defaults(
  568         allow_headers=['X-Auth-Token',
  569                        'X-Identity-Status',
  570                        'X-Roles',
  571                        'X-Service-Catalog',
  572                        'X-User-Id',
  573                        'X-Tenant-Id',
  574                        'X-OpenStack-Request-ID'],
  575         expose_headers=['X-Auth-Token',
  576                         'X-Subject-Token',
  577                         'X-Service-Token',
  578                         'X-OpenStack-Request-ID'],
  579         allow_methods=['GET',
  580                        'PUT',
  581                        'POST',
  582                        'DELETE',
  583                        'PATCH']
  584     )