| #!/usr/bin/env python3 |
| |
| import os |
| import sys |
| from argparse import ArgumentParser |
| |
| import yaml |
| from mako.template import Template |
| |
| """ |
| This script generates the data structures for the |
| phosphor-fan-monitor application. |
| |
| A future improvement is to get the fan inventory names |
| from a separate file, so just that file could be generated |
| from the MRW. |
| """ |
| |
| |
| tmpl = """\ |
| <%! |
| def indent(str, depth): |
| return ''.join(4*' '*depth+line for line in str.splitlines(True)) |
| %>\ |
| <%def name="getCondParams(cond)" buffered="True"> |
| %if (cond['name'] == 'propertiesMatch'): |
| std::vector<PropertyState>{ |
| %for i in cond['properties']: |
| PropertyState{ |
| { |
| "${i['object']}", |
| "${i['interface']}", |
| "${i['property']['name']}" |
| }, |
| static_cast<${i['property']['type']}>(${str(i['property']['value']).lower()}) |
| }, |
| %endfor |
| } |
| %endif |
| </%def>\ |
| /* This is a generated file. */ |
| #include "fan_defs.hpp" |
| #include "types.hpp" |
| #include "groups.hpp" |
| #include "conditions.hpp" |
| |
| using namespace phosphor::fan::monitor; |
| using namespace phosphor::fan::trust; |
| |
| const std::vector<FanDefinition> fanDefinitions |
| { |
| %for fan_data in data.get('fans', {}): |
| FanDefinition{"${fan_data['inventory']}", |
| ${fan_data.get('method', {})}, |
| ${fan_data.get('functional_delay', 0)}, |
| ${fan_data.get('allowed_out_of_range_time', {})}, |
| ${fan_data['deviation']}, |
| ${fan_data.get('upper_deviation', fan_data['deviation'])}, |
| ${fan_data['num_sensors_nonfunc_for_fan_nonfunc']}, |
| 0, // Monitor start delay - not used in YAML configs |
| 0, // Count interval - not used in YAML configs |
| std::nullopt, // nonfuncRotorErrorDelay - also not used here |
| std::nullopt, // fanMissingErrorDelay - also not used here |
| std::vector<SensorDefinition>{ |
| %for sensor in fan_data['sensors']: |
| <% |
| #has_target is a bool, and we need a true instead of True |
| has_target = str(sensor['has_target']).lower() |
| target_interface = sensor.get( |
| 'target_interface', |
| 'xyz.openbmc_project.Control.FanSpeed') |
| target_path = sensor.get( |
| 'target_path', |
| '') |
| factor = sensor.get('factor', 1) |
| offset = sensor.get('offset', 0) |
| threshold = sensor.get('threshold', 1) |
| ignore_above_max = str(sensor.get( |
| 'ignore_above_max', False)).lower() |
| %> \ |
| SensorDefinition{"${sensor['name']}", |
| ${has_target}, |
| "${target_interface}", |
| "${target_path}", |
| ${factor}, |
| ${offset}, |
| ${threshold}, |
| ${ignore_above_max}}, |
| %endfor |
| }, |
| %if ('condition' in fan_data) and \ |
| (fan_data['condition'] is not None): |
| make_condition(condition::${fan_data['condition']['name']}(\ |
| ${indent(getCondParams(cond=fan_data['condition']), 5)}\ |
| )), |
| %else: |
| {}, |
| %endif |
| false // set_func_on_present. Hardcoded to false. |
| }, |
| %endfor |
| }; |
| |
| ##Function to generate the group creation lambda. |
| ##If a group were to ever need a different constructor, |
| ##it could be handled here. |
| <%def name="get_lambda_contents(group)"> |
| std::vector<GroupDefinition> group{ |
| %for member in group['group']: |
| <% |
| in_trust = str(member.get('in_trust', "true")).lower() |
| %> |
| GroupDefinition{"${member['name']}", ${in_trust}}, |
| %endfor |
| }; |
| return std::make_unique<${group['class']}>(group); |
| </%def> |
| const std::vector<CreateGroupFunction> trustGroups |
| { |
| %for group in data.get('sensor_trust_groups', {}): |
| { |
| []() |
| {\ |
| ${get_lambda_contents(group)}\ |
| } |
| }, |
| %endfor |
| }; |
| """ |
| |
| |
| if __name__ == "__main__": |
| parser = ArgumentParser( |
| description="Phosphor fan monitor definition parser" |
| ) |
| |
| parser.add_argument( |
| "-m", |
| "--monitor_yaml", |
| dest="monitor_yaml", |
| default="example/monitor.yaml", |
| help="fan monitor definitional yaml", |
| ) |
| parser.add_argument( |
| "-o", |
| "--output_dir", |
| dest="output_dir", |
| default=".", |
| help="output directory", |
| ) |
| args = parser.parse_args() |
| |
| if not args.monitor_yaml: |
| parser.print_usage() |
| sys.exit(1) |
| |
| with open(args.monitor_yaml, "r") as monitor_input: |
| monitor_data = yaml.safe_load(monitor_input) or {} |
| |
| # Do some minor input validation |
| for fan in monitor_data.get("fans", {}): |
| if (fan["deviation"] < 0) or (fan["deviation"] > 100): |
| sys.exit("Invalid deviation value " + str(fan["deviation"])) |
| |
| output_file = os.path.join(args.output_dir, "fan_monitor_defs.cpp") |
| with open(output_file, "w") as output: |
| output.write(Template(tmpl).render(data=monitor_data)) |