Move argument parsing for dynamic_inventory to generate

At the moment osa_toolkit is installable as a package. With recent
changes to PBR for python3.12 console_scripts are no longer
installed "as is", but only a simple import is created. This change
results in broken `openstack-ansible-inventory` binary, as `inventory`
can not be imported.

To avoid the issue and follow our existing logic for rest of tooling,
we move argument parsing logic to generate.py itself, allowing it to
be self-sufficient and be leaving a dynamic_inventory.py as a simple
pointer which needs to stay in inventory folder for gropup_vars to
load properly.

Change-Id: Ie6d68f9c7b91d88736c5fc67c997cffd812afc61
This commit is contained in:
Dmitriy Rabotyagov 2025-03-19 17:48:16 +01:00
parent 173442c994
commit 7319bc994d
4 changed files with 77 additions and 64 deletions

View File

@ -15,7 +15,6 @@
#
# (c) 2014, Kevin Carter <kevin.carter@rackspace.com>
import argparse
import os
import sys
@ -28,57 +27,8 @@ except ImportError:
from osa_toolkit import generate
# Function kept in order to use relative pathing for the env.d directory
def args(arg_list):
"""Setup argument Parsing."""
parser = argparse.ArgumentParser(
usage='%(prog)s',
description='OpenStack Inventory Generator',
epilog='Inventory Generator Licensed "Apache 2.0"')
parser.add_argument(
'--config',
help='Path containing the user defined configuration files',
required=False,
default=os.getenv('OSA_CONFIG_DIR', None)
)
parser.add_argument(
'--list',
help='List all entries',
action='store_true'
)
parser.add_argument(
'--check',
help="Configuration check only, don't generate inventory",
action='store_true',
)
parser.add_argument(
'-d',
'--debug',
help=('Output debug messages to log file. '
'File is appended to, not overwritten'),
action='store_true',
default=False,
)
parser.add_argument(
'-e',
'--environment',
help=('Directory that contains the base env.d directory.\n'
'Defaults to <OSA_ROOT>/inventory/.'),
required=False,
default=os.path.dirname(__file__),
)
return vars(parser.parse_args(arg_list))
def main():
all_args = args(sys.argv[1:])
output = generate.main(**all_args)
print(output)
generate.main()
if __name__ == '__main__':

74
osa_toolkit/generate.py Executable file → Normal file
View File

@ -15,17 +15,23 @@
#
# (c) 2014, Kevin Carter <kevin.carter@rackspace.com>
import argparse
import copy
import json
import logging
import netaddr
from osa_toolkit import dictutils as du
from osa_toolkit import filesystem as filesys
from osa_toolkit import ip
from os import getenv as os_env
from os import path as os_path
import re
import sys
import uuid
import warnings
import netaddr
from osa_toolkit import __path__ as repo_path
from osa_toolkit import dictutils as du
from osa_toolkit import filesystem as filesys
from osa_toolkit import ip
logger = logging.getLogger('osa-inventory')
@ -50,6 +56,53 @@ REQUIRED_HOSTVARS = [
]
def args(argv):
"""Setup argument Parsing."""
parser = argparse.ArgumentParser(
usage='%(prog)s',
description='OpenStack Inventory Generator',
epilog='Inventory Generator Licensed "Apache 2.0"')
parser.add_argument(
'--config',
help='Path containing the user defined configuration files',
required=False,
default=os_env('OSA_CONFIG_DIR', None)
)
parser.add_argument(
'--list',
help='List all entries',
action='store_true'
)
parser.add_argument(
'--check',
help="Configuration check only, don't generate inventory",
action='store_true',
)
parser.add_argument(
'-d',
'--debug',
help=('Output debug messages to log file. '
'File is appended to, not overwritten'),
action='store_true',
default=False,
)
parser.add_argument(
'-e',
'--environment',
help=('Directory that contains the base env.d directory.\n'
'Defaults to <OSA_ROOT>/inventory/.'),
required=False,
default=f'{os_path.dirname(repo_path[0])}/inventory',
)
return vars(parser.parse_args(argv))
class MultipleHostsWithOneIPError(Exception):
def __init__(self, ip, assigned_host, new_host):
self.ip = ip
@ -1139,7 +1192,11 @@ def _prepare_debug_logger():
logger.info("Beginning new inventory run")
def main(config=None, check=False, debug=False, environment=None, **kwargs):
def generate(config=None,
check=False,
debug=False,
environment=None,
**kwargs):
"""Run the main application.
:param config: ``str`` Directory from which to pull configs and overrides
@ -1263,3 +1320,10 @@ def main(config=None, check=False, debug=False, environment=None, **kwargs):
filesys.save_inventory(inventory_json, inv_path)
return inventory_json
def main(argv=sys.argv[1:]):
all_args = args(argv)
data = generate(**all_args)
print(data)

View File

@ -28,4 +28,4 @@ packages = osa_toolkit
[entry_points]
console_scripts =
openstack-ansible-inventory = inventory.dynamic_inventory:main
openstack-ansible-inventory = osa_toolkit.generate:main

View File

@ -29,7 +29,6 @@ INV_DIR = 'inventory'
sys.path.append(path.join(os.getcwd(), INV_DIR))
import dynamic_inventory # noqa: E402
from osa_toolkit import dictutils # noqa: E402
from osa_toolkit import filesystem as fs # noqa: E402
from osa_toolkit import generate as di # noqa: E402
@ -102,7 +101,7 @@ def get_inventory(clean=True, extra_args=None):
if extra_args:
args.update(extra_args)
try:
inventory_string = di.main(**args)
inventory_string = di.generate(**args)
inventory = json.loads(inventory_string)
return inventory
finally:
@ -114,16 +113,16 @@ def get_inventory(clean=True, extra_args=None):
class TestArgParser(unittest.TestCase):
def test_no_args(self):
arg_dict = dynamic_inventory.args([])
arg_dict = di.args([])
self.assertIsNone(arg_dict['config'])
self.assertEqual(arg_dict['list'], False)
def test_list_arg(self):
arg_dict = dynamic_inventory.args(['--list'])
arg_dict = di.args(['--list'])
self.assertEqual(arg_dict['list'], True)
def test_config_arg(self):
arg_dict = dynamic_inventory.args(['--config',
arg_dict = di.args(['--config',
'/etc/openstack_deploy'])
self.assertEqual(arg_dict['config'], '/etc/openstack_deploy')
@ -1263,7 +1262,7 @@ class TestConfigCheckFunctional(TestConfigCheckBase):
self.user_defined_config['dashboard_hosts']['bogus'] = ip
def test_checking_good_config(self):
output = di.main(config=TARGET_DIR, check=True,
output = di.generate(config=TARGET_DIR, check=True,
environment=BASE_ENV_DIR)
self.assertEqual(output, 'Configuration ok!')
@ -1271,7 +1270,7 @@ class TestConfigCheckFunctional(TestConfigCheckBase):
self.duplicate_ip()
self.write_config()
with self.assertRaises(di.MultipleHostsWithOneIPError) as context:
di.main(config=TARGET_DIR, check=True, environment=BASE_ENV_DIR)
di.generate(config=TARGET_DIR, check=True, environment=BASE_ENV_DIR)
self.assertEqual(context.exception.ip, '172.29.236.100')