#!/bin/python3 # # Copyright Red Hat, Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # # -*- coding: utf-8 -*- # fs-matrix.py automatically reads featureset configuration # files from config/general_config and builds a matrix w/ the corresponding # features. For new configuration files, just re-run the script and submit the # new generated doc/source/feature-configuration-generated.rst file. # You may need to change this script when adding new features that are # not mapped. Look for *features_map* below to see the featureset mapping. # This script should be automatically called by tox -e docs # The output generated by this script is a rst formatted file that is # included in doc/source/feature-configuration.rst. # You may look for the following when running tox -e docs: # 'python fs-matrix.py > doc/source/feature-configuration-generated.rst' # Once *feature-configuration-generated.rst* is updated, submit a review. import os from texttable import Texttable import yaml # featureset mapping to match fs configuration files # : [, , ] features_map = { 'overcloud_ipv6': ['true', 'IPv6', 'Overcloud IPv6'], 'ssl_overcloud': ['true', 'SSLoc', 'Overcloud SSL'], 'network_isolation': ['true', 'NIsol', 'Network Isolation'], 'network_isolation_type': ['single-nic-vlans|multiple-nics|bond', 'NItyp', 'Network Isolation Type'], 'step_introspect': ['true', 'Intro', 'Introspection'], 'undercloud_check_idempotency': ['true', 'Idemp', 'Undercloud Idempotency Check'], 'containerized_undercloud': ['true', 'ConUC', 'Containerized undecloud'], 'containerized_overcloud': ['true', 'ConOC', 'Containerized overcloud'], 'undercloud_upgrade': ['true', 'UPGuc', 'Undercloud Upgrade'], 'containerized_overcloud_upgrade': ['true', 'UPGoc', 'Overcloud Major Upgrade'], 'overcloud_update': ['true', 'UPDoc', 'Overcloud Update (Minor Upgrade)'], 'ffu_overcloud_upgrade': ['true', 'UPGff', 'Fast-forward Overcloud Upgrade'], 'standalone_role': ['Standalone.yaml', 'Stdln', 'Standalone Deploy'], 'test_ping': ['true', 'PingT', 'Ping and ssh tests'], 'run_tempest': ['true', 'Temps', 'run Tempest'], 'composable_scenario': ['', 'Scen#', 'Scenario ###'], 'extra_args': ['ceph', 'Cephd', 'Ceph deploy'], 'undercloud_heat_convergence': ['true', 'HConv', 'Undercloud Heat Convergence'], 'enable_minimal_browbeat': ['true', 'BrowB', 'Browbeat performance testing'], 'validate_ha_overcloud': ['true', 'HAval', 'HA Validation'], } symbol_map = { 'single-nic-vlans': [u'─', 'Network isolation single network interface' ' card'], 'multiple-nics': [u'☰', 'Network isolation multiple network interface' 'cards'], 'release': [u'◍', 'Feature enabled in certain releases only'], 'enabled': [u'◉', 'Feature enabled in all releases'], 'disabled': [u'❍', 'Feature explicitly disabled in all releases'], 'not-found': [u' ', 'Feature not found'], } def load_fs(): t = Texttable() # headers/columns columns = ['Fset#'] for k, h in sorted(features_map.items(), key=lambda kv: kv[1][1]): columns.append(h[1]) matrix_length = len(columns) t.set_cols_width([5] * matrix_length) t.set_cols_align(['c'] * matrix_length) t.set_cols_valign(['m'] * matrix_length) t.set_cols_dtype(['t'] * matrix_length) root_path = os.path.dirname(os.path.realpath(__file__)) fs_dir = os.path.join(root_path, 'config/general_config/') for fs_filename in sorted(os.listdir(fs_dir)): fs_dict = {} if fs_filename.startswith('featureset0') and \ fs_filename.endswith('.yml'): with open(os.path.join(fs_dir, fs_filename)) as fs_file: fs_dict = yaml.load(fs_file, yaml.SafeLoader) datarow = get_data_from_yaml(fs_dict, fs_filename) t.add_rows([columns, datarow]) fs_list.append(fs_filename[10:13]) print(t.draw()) print('\n') def get_data_from_yaml(fs_dict, fs_filename): """Get data from fs yaml file :param ds_dict: featureset dictonary read from yaml file :param fs_filename: featureset yaml config file :returns list -- list of features read from yaml file """ # Add XXX_ link to first column e.g. 001_ datarow = [fs_filename[10:13] + '_'] for k, v in sorted(features_map.items(), key=lambda kv: kv[1][1]): if k in fs_dict: # value = what the fs file has value = str.lower(str(fs_dict[k])) # enabled = what it should have to be active enabled = str.lower(str(v[0])) # get digits only from scenarioXXX in composable_scenario setting if k == 'composable_scenario': datarow.append(''.join([n for n in value if n.isdigit()])) # expects substr in extra_args e.g. 'ceph' elif k == 'extra_args' and enabled in value: datarow.append(symbol_map['enabled'][0]) # fields that expects exact value e.g. 'true' elif value == enabled: datarow.append(symbol_map['enabled'][0]) # expects a substr, transform it into a symbol elif value in enabled and value in symbol_map: datarow.append(symbol_map[value][0]) # enabled in certain releases elif value.startswith('{%') and 'release' in value: datarow.append(symbol_map['release'][0]) else: # feature is present but disabled e.g. 'false' datarow.append(symbol_map['disabled'][0]) # feature not found in fs file else: datarow.append(symbol_map['not-found'][0]) return datarow def acronyms_and_symbols(): at = Texttable() columns = ['Acronym', 'Definition'] for k, acr in sorted(features_map.items(), key=lambda kv: kv[1][1]): at.add_rows([columns, [acr[1], acr[2]]]) print(at.draw()) print('\n') st = Texttable() columns = ['Symbol', 'Description'] for k, symdef in sorted(symbol_map.items(), key=lambda kv: kv[1][1]): st.add_rows([columns, [symdef[0], symdef[1]]]) print(st.draw()) print('\n') baseurl = 'https://opendev.org/openstack/tripleo-quickstart' path = 'src/branch/master/config/general_config/' for f in fs_list: print(".. _{0}: {1}/{2}/featureset{0}.yml".format(f, baseurl, path)) ### if __name__ == '__main__': fs_list = [] load_fs() acronyms_and_symbols()