Setting up a ConfigView based on a --region CLI option and then passing that view to another RegionConfigurableMixin command caused the latter to overwrite the former's settings unless the former also passed the --region option along with it. The update_config_view now overwrites preexisting settings only when they are explicitly passed to that method. Example of this happening: https://eucalyptus.atlassian.net/browse/TOOLS-635
112 lines
4.5 KiB
Python
112 lines
4.5 KiB
Python
# Copyright (c) 2012-2016 Hewlett Packard Enterprise Development Company LP
|
|
#
|
|
# Permission to use, copy, modify, and/or distribute this software for
|
|
# any purpose with or without fee is hereby granted, provided that the
|
|
# above copyright notice and this permission notice appear in all copies.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
import os
|
|
|
|
import six
|
|
|
|
from requestbuilder import Arg
|
|
|
|
|
|
class RegionConfigurableMixin(object):
|
|
"""
|
|
A mixin that allows the user to specify which user/region names to use
|
|
for the configuration via a --region arg and, if a 'REGION_ENVVAR' class
|
|
variable is set, an environment variable as well. The included
|
|
update_config_view method actually reads these data and updates
|
|
self.config to point to them.
|
|
"""
|
|
|
|
ARGS = [Arg('--region', metavar='USER@REGION', route_to=None,
|
|
help=('region and/or user names to search when looking up '
|
|
'config file data'))]
|
|
|
|
def update_config_view(self, region=None, user=None):
|
|
# If the caller specified something directly we overwrite
|
|
# whatever may be there unconditionally.
|
|
if region:
|
|
self.config.region = region
|
|
if user:
|
|
self.config.user = user
|
|
|
|
# Otherwise, different sources of user/region info can override
|
|
# only one of the pair, so we only overwite them individually,
|
|
# and then only when no values are already set.
|
|
|
|
# self.args gets highest precedence
|
|
if self.args.get('region'):
|
|
self.__setdefault_view_attrs(
|
|
'--region CLI option "{0}"'.format(self.args['region']),
|
|
*self.__parse_region(self.args['region']))
|
|
# Environment comes next
|
|
region_envvar = getattr(self, 'REGION_ENVVAR', None)
|
|
if isinstance(region_envvar, (list, tuple)):
|
|
for var in region_envvar:
|
|
if os.getenv(var):
|
|
self.__setdefault_view_attrs(
|
|
'environment variable "{0}"'.format(var),
|
|
*self.__parse_region(os.getenv(var)))
|
|
break
|
|
elif isinstance(region_envvar, six.string_types):
|
|
if os.getenv(region_envvar):
|
|
self.__setdefault_view_attrs(
|
|
'environment variable "{0}"'.format(region_envvar),
|
|
*self.__parse_region(os.getenv(region_envvar)))
|
|
# Default region from the config file
|
|
self.__setdefault_view_attrs(
|
|
'"default-region" global config option',
|
|
region=self.config.get_global_option('default-region'))
|
|
# We've gone through all possible means of region selection, so
|
|
# if no user is yet selected look it up in the region's config.
|
|
user, section = self.config.get_region_option2('user')
|
|
self.__setdefault_view_attrs(
|
|
'"user" config option for region "{0}"'.format(section),
|
|
user=user)
|
|
|
|
def __setdefault_view_attrs(self, cause, user=None, region=None):
|
|
if region and not self.config.region:
|
|
self.log.info('selected region "%s" from %s', region, cause)
|
|
self.config.region = region
|
|
if user and not self.config.user:
|
|
self.log.info('selected user "%s" from %s', user, cause)
|
|
self.config.user = user
|
|
|
|
@staticmethod
|
|
def __parse_region(regionish):
|
|
"""
|
|
Given a string with pattern "[USER@][REGION]", return the user
|
|
and region names that that string represents, if any, and None
|
|
for the values it does not represent.
|
|
|
|
Examples:
|
|
- "" -> (None, None)
|
|
- "spam" -> (None, "spam")
|
|
- "eggs@" -> ("eggs", None)
|
|
- "eggs@spam" -> ("eggs", "spam")
|
|
"""
|
|
|
|
if not regionish:
|
|
return None, None
|
|
if regionish.endswith('@'):
|
|
return regionish.rstrip('@'), None
|
|
elif '@' in regionish:
|
|
return regionish.split('@', 1)
|
|
else:
|
|
return None, regionish
|
|
|
|
|
|
# Compatibility with requestbuilder < 0.3
|
|
from .formatting import TabifyingMixin
|
|
from .progress import FileTransferProgressBarMixin
|