Merge "Inventory filesystem refactor load funcs moved"

This commit is contained in:
Jenkins 2016-11-28 21:18:55 +00:00 committed by Gerrit Code Review
commit 12182c186d
3 changed files with 90 additions and 114 deletions

View File

@ -22,6 +22,9 @@ import json
import logging import logging
import os import os
import tarfile import tarfile
import yaml
import dictutils as du
logger = logging.getLogger('osa-inventory') logger = logging.getLogger('osa-inventory')
@ -105,6 +108,23 @@ def dir_find(preferred_path=None, suffix=None, raise_if_missing=True):
return False return False
def _extra_config(user_defined_config, base_dir):
"""Discover new items in any extra directories and add the new values.
:param user_defined_config: ``dict``
:param base_dir: ``str``
"""
for root_dir, _, files in os.walk(base_dir):
for name in files:
if name.endswith(('.yml', '.yaml')):
with open(os.path.join(root_dir, name), 'rb') as f:
du.merge_dict(
user_defined_config,
yaml.safe_load(f.read()) or {}
)
logger.debug("Merged overrides from file {}".format(name))
def _make_backup(backup_path, source_file_path): def _make_backup(backup_path, source_file_path):
""" Create a backup of all previous inventory files as a tar archive """ Create a backup of all previous inventory files as a tar archive
@ -217,3 +237,49 @@ def save_inventory(inventory_json, save_path):
with open(inventory_file, 'wb') as f: with open(inventory_file, 'wb') as f:
f.write(inventory_json) f.write(inventory_json)
logger.info("Inventory written") logger.info("Inventory written")
def load_environment(config_path, environment):
"""Create an environment dictionary from config files
:param config_path: ``str`` path where the environment files are kept
:param environment: ``dict`` dictionary to populate with environment data
"""
# Load all YAML files found in the env.d directory
env_plugins = dir_find(config_path, 'env.d', raise_if_missing=False)
if env_plugins is not False:
_extra_config(user_defined_config=environment, base_dir=env_plugins)
logger.debug("Loaded environment from {}".format(config_path))
return environment
def load_user_configuration(config_path):
"""Create a user configuration dictionary from config files
:param config_path: ``str`` path where the configuration files are kept
"""
user_defined_config = dict()
# Load the user defined configuration file
user_config_file = os.path.join(config_path, 'openstack_user_config.yml')
if os.path.isfile(user_config_file):
with open(user_config_file, 'rb') as f:
user_defined_config.update(yaml.safe_load(f.read()) or {})
# Load anything in a conf.d directory if found
base_dir = dir_find(config_path, 'conf.d', raise_if_missing=False)
if base_dir is not False:
_extra_config(user_defined_config, base_dir)
# Exit if no user_config was found and loaded
if not user_defined_config:
raise SystemExit(
'No user config loaded\n'
'No openstack_user_config files are available in either \n{}'
'\nor \n{}/conf.d directory'.format(config_path, config_path)
)
logger.debug("User configuration loaded from: {}".format(user_config_file))
return user_defined_config

View File

@ -19,10 +19,8 @@ import ip
import json import json
import logging import logging
import netaddr import netaddr
import os
import uuid import uuid
import warnings import warnings
import yaml
import dictutils as du import dictutils as du
import filesystem as filesys import filesystem as filesys
@ -730,34 +728,6 @@ def container_skel_load(container_skel, inventory, config):
) )
def find_config_path(user_config_path=None):
# TODO(stevelle) REMOVE THIS FUNCTION: after other changes in chain
# prevents the clean removal right now
"""Return the path to the user configuration files.
If no directory is found the system will exit.
The lookup will be done in the following directories:
* user_config_path
* ``/etc/openstack_deploy/``
:param user_config_path: ``str`` Location to look in FIRST for a file
"""
path_check = [
os.path.join('/etc', 'openstack_deploy'),
]
if user_config_path is not None:
path_check.insert(0, os.path.expanduser(user_config_path))
for f in path_check:
if os.path.isdir(f):
return f
else:
raise SystemExit('No config found at: {}'.format(path_check))
def _ensure_inventory_uptodate(inventory, container_skel): def _ensure_inventory_uptodate(inventory, container_skel):
"""Update inventory if needed. """Update inventory if needed.
@ -823,23 +793,6 @@ def _parse_global_variables(user_cidr, inventory, user_defined_config):
del inventory['all']['vars'][key] del inventory['all']['vars'][key]
def _extra_config(user_defined_config, base_dir):
"""Discover new items in any extra directories and add the new values.
:param user_defined_config: ``dict``
:param base_dir: ``str``
"""
for root_dir, _, files in os.walk(base_dir):
for name in files:
if name.endswith(('.yml', '.yaml')):
with open(os.path.join(root_dir, name), 'rb') as f:
du.merge_dict(
user_defined_config,
yaml.safe_load(f.read()) or {}
)
logger.debug("Merged overrides from file %s", name)
def _check_same_ip_to_multiple_host(config): def _check_same_ip_to_multiple_host(config):
"""Check for IPs assigned to multiple hosts """Check for IPs assigned to multiple hosts
@ -988,51 +941,11 @@ def _collect_hostnames(dynamic_inventory):
return hostnames_ips return hostnames_ips
def load_environment(config_path, environment): def _prepare_debug_logger():
"""Create an environment dictionary from config files log_fmt = "%(lineno)d - %(funcName)s: %(message)s"
logging.basicConfig(format=log_fmt, filename='inventory.log')
:param config_path: ``str`` path where the environment files are kept logger.setLevel(logging.DEBUG)
:param environment: ``dict`` dictionary to populate with environment data logger.info("Beginning new inventory run")
"""
# Load all YAML files found in the env.d directory
env_plugins = filesys.dir_find(config_path, 'env.d',
raise_if_missing=False)
if env_plugins is not False:
_extra_config(user_defined_config=environment, base_dir=env_plugins)
logger.debug("Loaded environment from %s", config_path)
return environment
def load_user_configuration(config_path):
"""Create a user configuration dictionary from config files
:param config_path: ``str`` path where the configuration files are kept
"""
user_defined_config = dict()
# Load the user defined configuration file
user_config_file = os.path.join(config_path, 'openstack_user_config.yml')
if os.path.isfile(user_config_file):
with open(user_config_file, 'rb') as f:
user_defined_config.update(yaml.safe_load(f.read()) or {})
# Load anything in a conf.d directory if found
base_dir = filesys.dir_find(config_path, 'conf.d', raise_if_missing=False)
if base_dir is not False:
_extra_config(user_defined_config, base_dir)
# Exit if no user_config was found and loaded
if not user_defined_config:
raise SystemExit(
'No user config loaded\n'
'No openstack_user_config files are available in either \n{}'
'\nor \n{}/conf.d directory'.format(config_path, config_path)
)
logger.debug("User configuration loaded from: %s", user_config_file)
return user_defined_config
def main(config=None, check=False, debug=False, environment=None, **kwargs): def main(config=None, check=False, debug=False, environment=None, **kwargs):
@ -1047,18 +960,15 @@ def main(config=None, check=False, debug=False, environment=None, **kwargs):
:param environment: ``str`` Directory containing the base env.d :param environment: ``str`` Directory containing the base env.d
""" """
if debug: if debug:
log_fmt = "%(lineno)d - %(funcName)s: %(message)s" _prepare_debug_logger()
logging.basicConfig(format=log_fmt, filename='inventory.log')
logger.setLevel(logging.DEBUG)
logger.info("Beginning new inventory run")
# Get the path to the user configuration files # Get the path to the user configuration files
config_path = filesys.dir_find(preferred_path=config) config_path = filesys.dir_find(preferred_path=config)
user_defined_config = load_user_configuration(config_path) user_defined_config = filesys.load_user_configuration(config_path)
base_env_dir = environment base_env_dir = environment
base_env = load_environment(base_env_dir, {}) base_env = filesys.load_environment(base_env_dir, {})
environment = load_environment(config_path, base_env) environment = filesys.load_environment(config_path, base_env)
# Load existing inventory file if found # Load existing inventory file if found
dynamic_inventory = filesys.load_inventory(config_path, INVENTORY_SKEL) dynamic_inventory = filesys.load_inventory(config_path, INVENTORY_SKEL)
@ -1129,7 +1039,7 @@ def main(config=None, check=False, debug=False, environment=None, **kwargs):
if logger.isEnabledFor(logging.DEBUG): if logger.isEnabledFor(logging.DEBUG):
num_hosts = len(dynamic_inventory['_meta']['hostvars']) num_hosts = len(dynamic_inventory['_meta']['hostvars'])
logger.debug("%d hosts found." % num_hosts) logger.debug("%d hosts found.", num_hosts)
# Save new dynamic inventory # Save new dynamic inventory
filesys.save_inventory(dynamic_inventory_json, config_path) filesys.save_inventory(dynamic_inventory_json, config_path)

View File

@ -426,7 +426,7 @@ class TestAnsibleInventoryFormatConstraints(unittest.TestCase):
class TestUserConfiguration(unittest.TestCase): class TestUserConfiguration(unittest.TestCase):
def setUp(self): def setUp(self):
self.longMessage = True self.longMessage = True
self.loaded_user_configuration = di.load_user_configuration(TARGET_DIR) self.loaded_user_configuration = fs.load_user_configuration(TARGET_DIR)
def test_loading_user_configuration(self): def test_loading_user_configuration(self):
"""Test that the user configuration can be loaded""" """Test that the user configuration can be loaded"""
@ -436,7 +436,7 @@ class TestUserConfiguration(unittest.TestCase):
class TestEnvironments(unittest.TestCase): class TestEnvironments(unittest.TestCase):
def setUp(self): def setUp(self):
self.longMessage = True self.longMessage = True
self.loaded_environment = di.load_environment(BASE_ENV_DIR, {}) self.loaded_environment = fs.load_environment(BASE_ENV_DIR, {})
def test_loading_environment(self): def test_loading_environment(self):
"""Test that the environment can be loaded""" """Test that the environment can be loaded"""
@ -458,14 +458,14 @@ class TestIps(unittest.TestCase):
# Allow custom assertion errors. # Allow custom assertion errors.
self.longMessage = True self.longMessage = True
@mock.patch('generate.load_environment') @mock.patch('filesystem.load_environment')
@mock.patch('generate.load_user_configuration') @mock.patch('filesystem.load_user_configuration')
def test_duplicates(self, mock_load_config, mock_load_env): def test_duplicates(self, mock_load_config, mock_load_env):
"""Test that no duplicate IPs are made on any network.""" """Test that no duplicate IPs are made on any network."""
# Grab our values read from the file system just once. # Grab our values read from the file system just once.
mock_load_config.return_value = get_config() mock_load_config.return_value = get_config()
mock_load_env.return_value = di.load_environment(BASE_ENV_DIR, {}) mock_load_env.return_value = fs.load_environment(BASE_ENV_DIR, {})
mock_open = mock.mock_open() mock_open = mock.mock_open()
@ -843,7 +843,7 @@ class TestGlobalOverridesConfigDeletion(TestConfigCheckBase):
class TestEnsureInventoryUptoDate(unittest.TestCase): class TestEnsureInventoryUptoDate(unittest.TestCase):
def setUp(self): def setUp(self):
self.env = di.load_environment(BASE_ENV_DIR, {}) self.env = fs.load_environment(BASE_ENV_DIR, {})
# Copy because we manipulate the structure in each test; # Copy because we manipulate the structure in each test;
# not copying would modify the global var in the target code # not copying would modify the global var in the target code
self.inv = copy.deepcopy(di.INVENTORY_SKEL) self.inv = copy.deepcopy(di.INVENTORY_SKEL)
@ -900,7 +900,7 @@ class TestEnsureInventoryUptoDate(unittest.TestCase):
class OverridingEnvBase(unittest.TestCase): class OverridingEnvBase(unittest.TestCase):
def setUp(self): def setUp(self):
self.base_env = di.load_environment(BASE_ENV_DIR, {}) self.base_env = fs.load_environment(BASE_ENV_DIR, {})
# Use the cinder configuration as our sample for override testing # Use the cinder configuration as our sample for override testing
with open(path.join(BASE_ENV_DIR, 'env.d', 'cinder.yml'), 'r') as f: with open(path.join(BASE_ENV_DIR, 'env.d', 'cinder.yml'), 'r') as f:
@ -926,7 +926,7 @@ class TestOverridingEnvVars(OverridingEnvBase):
self.write_override_env() self.write_override_env()
di.load_environment(TARGET_DIR, self.base_env) fs.load_environment(TARGET_DIR, self.base_env)
test_vol = self.base_env['container_skel']['cinder_volumes_container'] test_vol = self.base_env['container_skel']['cinder_volumes_container']
self.assertFalse(test_vol['properties']['is_metal']) self.assertFalse(test_vol['properties']['is_metal'])
@ -942,7 +942,7 @@ class TestOverridingEnvVars(OverridingEnvBase):
self.write_override_env() self.write_override_env()
di.load_environment(TARGET_DIR, self.base_env) fs.load_environment(TARGET_DIR, self.base_env)
test_vol = self.base_env['container_skel']['cinder_volumes_container'] test_vol = self.base_env['container_skel']['cinder_volumes_container']
@ -954,7 +954,7 @@ class TestOverridingEnvVars(OverridingEnvBase):
self.write_override_env() self.write_override_env()
di.load_environment(TARGET_DIR, self.base_env) fs.load_environment(TARGET_DIR, self.base_env)
test_vol = self.base_env['container_skel']['cinder_volumes_container'] test_vol = self.base_env['container_skel']['cinder_volumes_container']
@ -966,7 +966,7 @@ class TestOverridingEnvVars(OverridingEnvBase):
self.write_override_env() self.write_override_env()
di.load_environment(TARGET_DIR, self.base_env) fs.load_environment(TARGET_DIR, self.base_env)
test_vol = self.base_env['container_skel']['cinder_volumes_container'] test_vol = self.base_env['container_skel']['cinder_volumes_container']
@ -978,7 +978,7 @@ class TestOverridingEnvVars(OverridingEnvBase):
self.write_override_env() self.write_override_env()
di.load_environment(TARGET_DIR, self.base_env) fs.load_environment(TARGET_DIR, self.base_env)
test_vol = self.base_env['container_skel']['cinder_volumes_container'] test_vol = self.base_env['container_skel']['cinder_volumes_container']
@ -994,7 +994,7 @@ class TestOverridingEnvIntegration(OverridingEnvBase):
self.inv = fs.load_inventory(TARGET_DIR, di.INVENTORY_SKEL) self.inv = fs.load_inventory(TARGET_DIR, di.INVENTORY_SKEL)
def skel_setup(self): def skel_setup(self):
self.environment = di.load_environment(TARGET_DIR, self.base_env) self.environment = fs.load_environment(TARGET_DIR, self.base_env)
di.skel_setup(self.environment, self.inv) di.skel_setup(self.environment, self.inv)
@ -1173,7 +1173,7 @@ class TestLxcHosts(TestConfigCheckBase):
class TestConfigMatchesEnvironment(unittest.TestCase): class TestConfigMatchesEnvironment(unittest.TestCase):
def setUp(self): def setUp(self):
self.env = di.load_environment(BASE_ENV_DIR, {}) self.env = fs.load_environment(BASE_ENV_DIR, {})
def test_matching_keys(self): def test_matching_keys(self):
config = get_config() config = get_config()