1#!/usr/bin/env python3 2 3import os 4import sys 5import yaml 6from argparse import ArgumentParser 7from mako.template import Template 8 9""" 10This script generates the data structures for the 11phosphor-fan-monitor application. 12 13A future improvement is to get the fan inventory names 14from a separate file, so just that file could be generated 15from the MRW. 16""" 17 18 19tmpl = '''\ 20<%! 21def indent(str, depth): 22 return ''.join(4*' '*depth+line for line in str.splitlines(True)) 23%>\ 24<%def name="getCondParams(cond)" buffered="True"> 25%if (cond['name'] == 'propertiesMatch'): 26std::vector<PropertyState>{ 27 %for i in cond['properties']: 28 PropertyState{ 29 { 30 "${i['object']}", 31 "${i['interface']}", 32 "${i['property']['name']}" 33 }, 34 static_cast<${i['property']['type']}>(${str(i['property']['value']).lower()}) 35 }, 36 %endfor 37} 38%endif 39</%def>\ 40/* This is a generated file. */ 41#include "fan_defs.hpp" 42#include "types.hpp" 43#include "groups.hpp" 44#include "conditions.hpp" 45 46using namespace phosphor::fan::monitor; 47using namespace phosphor::fan::trust; 48 49const std::vector<FanDefinition> fanDefinitions 50{ 51%for fan_data in data.get('fans', {}): 52 FanDefinition{"${fan_data['inventory']}", 53 ${fan_data.get('functional_delay', 0)}, 54 ${fan_data['allowed_out_of_range_time']}, 55 ${fan_data['deviation']}, 56 ${fan_data['num_sensors_nonfunc_for_fan_nonfunc']}, 57 std::vector<SensorDefinition>{ 58 %for sensor in fan_data['sensors']: 59 <% 60 #has_target is a bool, and we need a true instead of True 61 has_target = str(sensor['has_target']).lower() 62 target_interface = sensor.get( 63 'target_interface', 64 'xyz.openbmc_project.Control.FanSpeed') 65 factor = sensor.get('factor', 1) 66 offset = sensor.get('offset', 0) 67 %> \ 68 SensorDefinition{"${sensor['name']}", 69 ${has_target}, 70 "${target_interface}", 71 ${factor}, 72 ${offset}}, 73 %endfor 74 }, 75 %if ('condition' in fan_data) and \ 76 (fan_data['condition'] is not None): 77 make_condition(condition::${fan_data['condition']['name']}(\ 78 ${indent(getCondParams(cond=fan_data['condition']), 5)}\ 79 )) 80 %else: 81 {} 82 %endif 83 }, 84%endfor 85}; 86 87##Function to generate the group creation lambda. 88##If a group were to ever need a different constructor, 89##it could be handled here. 90<%def name="get_lambda_contents(group)"> 91 std::vector<GroupDefinition> group{ 92 %for member in group['group']: 93 <% 94 in_trust = str(member.get('in_trust', "true")).lower() 95 %> 96 GroupDefinition{"${member['name']}", ${in_trust}}, 97 %endfor 98 }; 99 return std::make_unique<${group['class']}>(group); 100</%def> 101const std::vector<CreateGroupFunction> trustGroups 102{ 103%for group in data.get('sensor_trust_groups', {}): 104 { 105 []() 106 {\ 107${get_lambda_contents(group)}\ 108 } 109 }, 110%endfor 111}; 112''' 113 114 115if __name__ == '__main__': 116 parser = ArgumentParser( 117 description="Phosphor fan monitor definition parser") 118 119 parser.add_argument('-m', '--monitor_yaml', dest='monitor_yaml', 120 default="example/monitor.yaml", 121 help='fan monitor definitional yaml') 122 parser.add_argument('-o', '--output_dir', dest='output_dir', 123 default=".", 124 help='output directory') 125 args = parser.parse_args() 126 127 if not args.monitor_yaml: 128 parser.print_usage() 129 sys.exit(1) 130 131 with open(args.monitor_yaml, 'r') as monitor_input: 132 monitor_data = yaml.safe_load(monitor_input) or {} 133 134 #Do some minor input validation 135 for fan in monitor_data.get('fans', {}): 136 if ((fan['deviation'] < 0) or (fan['deviation'] > 100)): 137 sys.exit("Invalid deviation value " + str(fan['deviation'])) 138 139 output_file = os.path.join(args.output_dir, "fan_monitor_defs.cpp") 140 with open(output_file, 'w') as output: 141 output.write(Template(tmpl).render(data=monitor_data)) 142