Add ability to remove any option from tempest.conf
A user will be able to specify which values should not be included in tempest configuration file through --remove argument. For ommiting value(s): --remove section.key=value[,value2[...]] For ommiting all values in section.key: --remove section.key Patch removes network.remove-extension option, because the patch is more generic solution of the same issue. Change-Id: I0375f2bbfa3bb7db4f9b81ea1518e86d725c30a3
This commit is contained in:
parent
c9b3c78c72
commit
3deb8061aa
@ -38,6 +38,7 @@ import ConfigParser
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import sys
|
||||||
import tempest.config
|
import tempest.config
|
||||||
import urllib2
|
import urllib2
|
||||||
|
|
||||||
@ -176,6 +177,11 @@ def main():
|
|||||||
configure_discovered_services(conf, services)
|
configure_discovered_services(conf, services)
|
||||||
configure_boto(conf, services)
|
configure_boto(conf, services)
|
||||||
configure_horizon(conf)
|
configure_horizon(conf)
|
||||||
|
|
||||||
|
# remove all unwanted values if were specified
|
||||||
|
if args.remove != {}:
|
||||||
|
LOG.info("Removing configuration: %s", str(args.remove))
|
||||||
|
conf.remove_values(args)
|
||||||
LOG.info("Creating configuration file %s", os.path.abspath(args.out))
|
LOG.info("Creating configuration file %s", os.path.abspath(args.out))
|
||||||
with open(args.out, 'w') as f:
|
with open(args.out, 'w') as f:
|
||||||
conf.write(f)
|
conf.write(f)
|
||||||
@ -221,6 +227,12 @@ def parse_arguments():
|
|||||||
parser.add_argument('--network-id',
|
parser.add_argument('--network-id',
|
||||||
help="""The ID of an existing network in our openstack
|
help="""The ID of an existing network in our openstack
|
||||||
instance with external connectivity""")
|
instance with external connectivity""")
|
||||||
|
parser.add_argument('--remove', action='append', default=[],
|
||||||
|
metavar="SECTION.KEY=VALUE[,VALUE]",
|
||||||
|
help="""key value pair to be removed from
|
||||||
|
configuration file.
|
||||||
|
For example: --remove identity.username=myname
|
||||||
|
--remove feature-enabled.api_ext=http,https""")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@ -229,9 +241,33 @@ def parse_arguments():
|
|||||||
" together, since creating" " resources requires"
|
" together, since creating" " resources requires"
|
||||||
" admin rights")
|
" admin rights")
|
||||||
args.overrides = parse_overrides(args.overrides)
|
args.overrides = parse_overrides(args.overrides)
|
||||||
|
args.remove = parse_values_to_remove(args.remove)
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def parse_values_to_remove(options):
|
||||||
|
"""Manual parsing of remove arguments.
|
||||||
|
|
||||||
|
:options list of arguments following --remove argument
|
||||||
|
:returns dict containing key paths with values to be removed
|
||||||
|
EXAMPLE: {'identity.username': [myname],
|
||||||
|
'identity-feature-enabled.api_extensions': [http, https]}
|
||||||
|
"""
|
||||||
|
parsed = {}
|
||||||
|
for argument in options:
|
||||||
|
if len(argument.split('=')) == 2:
|
||||||
|
section, values = argument.split('=')
|
||||||
|
if len(section.split('.')) != 2:
|
||||||
|
raise Exception("Missing dot. The option --remove has to"
|
||||||
|
"come in the format 'section.key=value,"
|
||||||
|
" but got '%s'." % (argument))
|
||||||
|
parsed[section] = values.split(',')
|
||||||
|
else:
|
||||||
|
# missing equal sign, all values in section.key will be deleted
|
||||||
|
parsed[argument] = []
|
||||||
|
return parsed
|
||||||
|
|
||||||
|
|
||||||
def parse_overrides(overrides):
|
def parse_overrides(overrides):
|
||||||
"""Manual parsing of positional arguments.
|
"""Manual parsing of positional arguments.
|
||||||
|
|
||||||
@ -464,6 +500,37 @@ class TempestConf(ConfigParser.SafeConfigParser):
|
|||||||
ConfigParser.SafeConfigParser.set(self, section, key, value)
|
ConfigParser.SafeConfigParser.set(self, section, key, value)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def remove_values(self, args):
|
||||||
|
"""Remove values from configuration file specified in arguments.
|
||||||
|
|
||||||
|
:args - arguments object
|
||||||
|
"""
|
||||||
|
for key_path in args.remove:
|
||||||
|
section, key = key_path.split('.')
|
||||||
|
try:
|
||||||
|
conf_values = self.get(section, key).split(',')
|
||||||
|
remove = args.remove[key_path]
|
||||||
|
if len(remove) == 0:
|
||||||
|
# delete all values in section.key
|
||||||
|
self.remove_option(section, key)
|
||||||
|
elif len(conf_values) == 1:
|
||||||
|
# make sure only the value specified by user
|
||||||
|
# will be deleted if in the key is other value
|
||||||
|
# than expected, ignore it
|
||||||
|
if conf_values[0] in args.remove[key_path]:
|
||||||
|
self.remove_option(section, key)
|
||||||
|
else:
|
||||||
|
# exclude all unwanted values from the list
|
||||||
|
# and preserve the original order of items
|
||||||
|
conf_values = [v for v in conf_values if v not in remove]
|
||||||
|
self.set(section, key, ",".join(conf_values))
|
||||||
|
except ConfigParser.NoOptionError:
|
||||||
|
# only inform a user, option specified by him doesn't exist
|
||||||
|
LOG.error(sys.exc_info()[1])
|
||||||
|
except ConfigParser.NoSectionError:
|
||||||
|
# only inform a user, section specified by him doesn't exist
|
||||||
|
LOG.error(sys.exc_info()[1])
|
||||||
|
|
||||||
|
|
||||||
def create_tempest_users(tenants_client, roles_client, users_client, conf,
|
def create_tempest_users(tenants_client, roles_client, users_client, conf,
|
||||||
services):
|
services):
|
||||||
@ -783,14 +850,6 @@ def configure_discovered_services(conf, services):
|
|||||||
|
|
||||||
# set service extensions
|
# set service extensions
|
||||||
keystone_v3_support = conf.get('identity-feature-enabled', 'api_v3')
|
keystone_v3_support = conf.get('identity-feature-enabled', 'api_v3')
|
||||||
# Currently neutron ext-list provides available api-extension but
|
|
||||||
# does not provide enabled extension due to bug in dvr.
|
|
||||||
# So we are removing dvr from neutron api-extension list.
|
|
||||||
# We can remove dvr from extension list using network.remove-extension dvr
|
|
||||||
# https://bugs.launchpad.net/neutron/+bug/1450067
|
|
||||||
if not conf.has_option('network', 'remove-extension'):
|
|
||||||
conf.set('network', 'remove-extension', '')
|
|
||||||
network_extension = conf.get('network', 'remove-extension')
|
|
||||||
for service, ext_key in SERVICE_EXTENSION_KEY.iteritems():
|
for service, ext_key in SERVICE_EXTENSION_KEY.iteritems():
|
||||||
if service in services:
|
if service in services:
|
||||||
extensions = ','.join(services[service].get('extensions', ""))
|
extensions = ','.join(services[service].get('extensions', ""))
|
||||||
@ -803,11 +862,6 @@ def configure_discovered_services(conf, services):
|
|||||||
conf.get("identity", "uri_v3"))
|
conf.get("identity", "uri_v3"))
|
||||||
extensions = list(set(extensions.split(',') + identity_v3_ext))
|
extensions = list(set(extensions.split(',') + identity_v3_ext))
|
||||||
extensions = ','.join(extensions)
|
extensions = ','.join(extensions)
|
||||||
elif service == 'network' and network_extension:
|
|
||||||
extensions = set(str(extensions).split(','))
|
|
||||||
remove_ext = set(network_extension.split(','))
|
|
||||||
extensions = list(extensions.difference(remove_ext))
|
|
||||||
extensions = ','.join(extensions)
|
|
||||||
conf.set(service + '-feature-enabled', ext_key, extensions)
|
conf.set(service + '-feature-enabled', ext_key, extensions)
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from argparse import Namespace
|
||||||
from config_tempest import config_tempest as tool
|
from config_tempest import config_tempest as tool
|
||||||
from config_tempest.tests.base import BaseConfigTempestTest
|
from config_tempest.tests.base import BaseConfigTempestTest
|
||||||
from fixtures import MonkeyPatch
|
from fixtures import MonkeyPatch
|
||||||
@ -151,6 +152,43 @@ class TestTempestConf(BaseConfigTempestTest):
|
|||||||
self.assertFalse(self.conf.get_bool_value("False"))
|
self.assertFalse(self.conf.get_bool_value("False"))
|
||||||
self.assertRaises(ValueError, self.conf.get_bool_value, "no")
|
self.assertRaises(ValueError, self.conf.get_bool_value, "no")
|
||||||
|
|
||||||
|
def test_remove_values(self):
|
||||||
|
api_exts = "router_availability_zone,rbac-policies,pagination,sorting,"
|
||||||
|
api_exts += "standard-attr-description,router,binding,metering,"
|
||||||
|
api_exts += "allowed-address-pairs,project-id,dvr,l3-flavors,tag-ext"
|
||||||
|
remove_exts = ["router", "project-id", "dvr"]
|
||||||
|
args = Namespace(
|
||||||
|
remove={
|
||||||
|
"identity.username": ["demo"],
|
||||||
|
"identity.tenant_name": ["tenant"],
|
||||||
|
"compute.image_ssh_user": ["rhel", "cirros"],
|
||||||
|
"network-feature-enabled.api_extensions": remove_exts
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.conf = self._get_conf("v2.0", "v3")
|
||||||
|
self.conf.set("compute", "image_ssh_user", "cirros")
|
||||||
|
self.conf.set("network-feature-enabled", "api_extensions", api_exts)
|
||||||
|
self.conf.remove_values(args)
|
||||||
|
self.assertFalse(self.conf.has_option("identity", "username"))
|
||||||
|
self.assertTrue(self.conf.has_option("identity", "tenant_name"))
|
||||||
|
self.assertFalse(self.conf.has_option("compute", "image_ssh_user"))
|
||||||
|
conf_exts = self.conf.get("network-feature-enabled", "api_extensions")
|
||||||
|
conf_exts = conf_exts.split(',')
|
||||||
|
for ext in api_exts.split(','):
|
||||||
|
if ext in remove_exts:
|
||||||
|
self.assertFalse(ext in conf_exts)
|
||||||
|
else:
|
||||||
|
self.assertTrue(ext in conf_exts)
|
||||||
|
|
||||||
|
@mock.patch('config_tempest.config_tempest.LOG')
|
||||||
|
def test_remove_not_defined_values(self, mock_logging):
|
||||||
|
self.conf.remove_values(Namespace(remove={"notExistSection.key": []}))
|
||||||
|
# check if LOG.error was called
|
||||||
|
self.assertTrue(mock_logging.error.called)
|
||||||
|
self.conf.remove_values(Namespace(remove={"section.notExistKey": []}))
|
||||||
|
# check if LOG.error was called
|
||||||
|
self.assertTrue(mock_logging.error.called)
|
||||||
|
|
||||||
|
|
||||||
class TestConfigTempest(BaseConfigTempestTest):
|
class TestConfigTempest(BaseConfigTempestTest):
|
||||||
|
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
Add a new ability to remove any configuration values from tempest.conf
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add a new parameter --remove to specify which configuration values should
|
||||||
|
not be included in tempest configuration file.
|
||||||
|
Parameter format for removing values:
|
||||||
|
[--remove SECTION.KEY=VALUE[,VALUE]]
|
||||||
|
|
||||||
|
Parameter format for removing all values in key.section:
|
||||||
|
[--remove SECTION.KEY]
|
||||||
|
|
||||||
|
If a section or an option specified in CLI does not exist, tempestconf will
|
||||||
|
inform a user about that in logging output.
|
Loading…
Reference in New Issue
Block a user