From 9ec71694263804cff1a645207b01267691260d9c Mon Sep 17 00:00:00 2001 From: Praveen Chaudhary Date: Wed, 3 Oct 2018 16:19:07 -0700 Subject: [PATCH] [sensors_create_metadata.yml]: playbook to create sensors meta data for given hwsku. [sensors_meta_data.py]: Ansible module to create sensors meta data. Signed-off-by: Praveen Chaudhary This playbook and module generates a file with sensors meta data which can be used with sensors test suite. Without this module user has to go through tedious process for creating this Meta data manually. [Review Note]: As of now sensors_create_metadata.yml is placed in main ansible directory. Kindly suggest the best directory for it. --- ansible/library/sensors_meta_data.py | 237 +++++++++++++++++++++++++++ ansible/sensors_create_metadata.yml | 59 +++++++ 2 files changed, 296 insertions(+) create mode 100644 ansible/library/sensors_meta_data.py create mode 100644 ansible/sensors_create_metadata.yml diff --git a/ansible/library/sensors_meta_data.py b/ansible/library/sensors_meta_data.py new file mode 100644 index 00000000000..bea8343be10 --- /dev/null +++ b/ansible/library/sensors_meta_data.py @@ -0,0 +1,237 @@ +#!/usr/bin/python + +from __future__ import print_function +from ansible.module_utils.basic import * + +DOCUMENTATION = ''' +--- +module: sensors_meta_data +version_added: +author: Praveen Chaudhary (pchaudhary@linkedin.com) +short description: Generate file with sensors meta data which can be used with +sensors test suite. Without this module user has to go through tedious process +for creating this Meta data manually. + +description: + - sensors_raw input dictionary defines fields which will be part of sonic + meta data. + - create a predefined format similar to file sku-sensors-data.yml for result + dictionary. + - fill result dictionary with complete key string on basis of keys in + sensors_facts. + - write all non-classifiable strings in [others] keys. + - write output in file with same format as file sku-sensors-data.yml + +Post work items: + - Manually classify string listed in [others] + - paste the data in sku-sensors-data.yml to use it for sensors test suite +''' + +EXAMPLES = ''' + - name: create sensors meta data file + sensors_meta_data: sensors_raw={{ sensors['raw'] }} file={{ file }} hwsku={{ hwsku }} + connection: local + register: sensors_metadata +''' + +class SensorsMetaData(object): + def __init__(self): + self.module = AnsibleModule( + argument_spec=dict( + sensors_raw=dict(required=True, type='dict'), + file_name =dict(required=True, type='str'), + hwsku=dict(required=True, type='str'), + ), + supports_check_mode=True) + + self.rawDict = self.module.params['sensors_raw'] + self.file = self.module.params['file_name'] + self.hwsku = self.module.params['hwsku'] + self.sensorsMetaData = {self.hwsku: {}} + self.facts = {'sensors_meta_data': self.sensorsMetaData} + + return + + def run(self): + """ + Main method of the class + + """ + self.init() + + keyStr="" + for key in self.rawDict.keys(): + keyStr = (key+"/") + self.generateSensorsMetaData(self.rawDict[key], + self.sensorsMetaData[self.hwsku], keyStr) + + # print resultant dictionary in the file + with open(self.file,'w') as outputFile: + self.writeResultInFile(self.sensorsMetaData, " ", outputFile) + + self.module.exit_json(ansible_facts=self.facts) + + return + + def fillDictResultAlarms(self, keyStr, subResult): + """ + fill Alarms section of result + """ + + if "fan" in keyStr: + subResult["alarms"]["fan"].append(keyStr) + elif "cpu" in keyStr or "CPU" in keyStr or "Psu" in keyStr: + subResult["alarms"]["power"].append(keyStr) + elif "temp" in keyStr: + subResult["alarms"]["temp"].append(keyStr) + else: + subResult["alarms"]["power"].append(keyStr) + + return + + def findDictKeyFromStr(self, keyStr): + ''' + find key for compare section by string parsing + ''' + + if "fan" in keyStr: + dictKey = "fan" + elif "cpu" in keyStr or "CPU" in keyStr or "Psu" in keyStr: + dictKey = "power" + elif "temp" in keyStr: + dictKey = "temp" + else: + dictKey = "power" + + return dictKey + + def fillCompares(self, keyStr, compareStr, subResult, dictKey): + ''' + fill compares section of result + ''' + keyStr = "- " + keyStr + compareStr = " " + compareStr + subResult["compares"][dictKey].append(keyStr) + subResult["compares"][dictKey].append(compareStr) + + return + + def fillDictResultCompares(self, keyStr, subResult, rawDict): + ''' + find compare string and fill compares section + ''' + compareStr = "" + for keys in rawDict.keys(): + if "input" in keys: + idx = keyStr.rfind("/") + compareStr = keyStr[0:idx+1] + compareStr += keys + + if compareStr == "": + # no input item in this dict" + subResult["others"].append(keyStr) + return + + dictKey = self.findDictKeyFromStr(keyStr) + + if "min" in keyStr or "lcrit" in keyStr: + self.fillCompares(keyStr, compareStr, subResult, dictKey) + else: + self.fillCompares(compareStr, keyStr, subResult, dictKey) + + return + + def fillDictResult(self, keyStr, subResult, rawDict): + ''' + find relavent section of result to fill + ''' + + keyStr = "- " + keyStr + + if "alarm" in keyStr or "fault" in keyStr: + self.fillDictResultAlarms(keyStr, subResult) + + elif "crit" in keyStr or "max" in keyStr or "min" in keyStr: + self.fillDictResultCompares(keyStr, subResult, rawDict) + + elif "input" in keyStr: + dictKey = self.findDictKeyFromStr(keyStr) + subResult["non-zero"][dictKey].append(keyStr) + else: + subResult["others"].append(keyStr) + + return + + def generateSensorsMetaData(self, rawDict, subResult, keyStr): + ''' + generate key strings meta data from sensors_raw by parsing it + recursively + ''' + + for keys in rawDict.keys(): + + if type(rawDict[keys]) == type(rawDict): + newStr = keyStr + (keys+"/") + self.generateSensorsMetaData(rawDict[keys], subResult, newStr) + + else: + newStr = keyStr + keys + self.fillDictResult(newStr, subResult, rawDict) + return + + def writeResultInFile(self, result, tabStr, outputFile): + ''' + print result dictionary recursively in outputfile + ''' + for keys in result.keys(): + print(tabStr, end="", file=outputFile) + + if type(result[keys]) == type(result): + print("{}:".format(keys), file=outputFile) + self.writeResultInFile(result[keys], " " + tabStr, outputFile) + + else: # it is a list of string + if len(result[keys]) == 0: + print("{}:".format(keys), end="", file=outputFile) + print(" []", file=outputFile) + else: + print("{}:".format(keys), file=outputFile) + for item in result[keys]: + print(tabStr, end="", file=outputFile) + print(item, file=outputFile) + return + + def init(self): + ''' + create skelaton of result dictionary + ''' + sensorsDict = self.sensorsMetaData[self.hwsku] + + sensorsDict["alarms"] = dict() + sensorsDict["compares"] = dict() + sensorsDict["non-zero"] = dict() + sensorsDict["psu_skips"] = dict() + sensorsDict["others"] = list() + + sensorsDict["alarms"]["fan"] = list() + sensorsDict["alarms"]["power"] = list() + sensorsDict["alarms"]["temp"] = list() + + sensorsDict["compares"]["fan"] = list() + sensorsDict["compares"]["power"] = list() + sensorsDict["compares"]["temp"] = list() + + sensorsDict["non-zero"]["fan"] = list() + sensorsDict["non-zero"]["power"] = list() + sensorsDict["non-zero"]["temp"] = list() + + return + +def main(): + sensorsMetaData = SensorsMetaData() + sensorsMetaData.run() + + return + +if __name__ == "__main__": + main() diff --git a/ansible/sensors_create_metadata.yml b/ansible/sensors_create_metadata.yml new file mode 100644 index 00000000000..5ef5f34fd24 --- /dev/null +++ b/ansible/sensors_create_metadata.yml @@ -0,0 +1,59 @@ +# This Playbook is used to generate Sensors Meta Data for new platforms for SONIC. +# Sensors Meta Data can be appended in ansible/group_vars/sonic/sku-sensors-data.yml +# to use it for sensors test suite. +# +# Without this playbook user has to go through tedious process for creating this Meta +# data Manually. +# +# How it works: +# This playbook uses sensors_facts module to collect the data from sonic device. +# - Argument to sensors_facts module will be an empty dictionary. +# Then it uses sensors_meta_data module to generate a file with meta data. +# Meta data will be in same format as in file ansible/group_vars/sonic/sku-sensors-data.yml +# Caveat: file will also have a field [others] for non classified sensors. User has to +# classify this part manually. +# +# Usage: +# ansible-playbook -i lab -l falco-test-dut02 sensors_create_metadata.yml +# -e "file=/tmp/praveen/sensorsMetaData.txt hwsku=Seastone-DX010" +# +# args: +# -l sonic_dut Sonic device +# -e file output file +# -e hwsku platform hwsku such as Seastone-DX010 + +- hosts: sonic + remote_user: admin + + tasks: + - name: Get platform monitor docker name + shell: docker ps -a --format '{{'{{'}}.Image{{'}} {{'}}.Names{{'}}'}}' | grep 'platform' | awk '{print $2}' + register: pmon_ps + + - debug: + var: pmon_ps + + - set_fact: + ansible_python_interpreter: "docker exec -i {{ pmon_ps.stdout }} python" + + - set_fact: + checks: {'alarms': {}, 'compares': {}, 'non_zero': {}, 'psu_skips': {}} + + - name: Gather sensors + sensors_facts: checks={{ checks }} + vars: + ansible_shell_type: docker + + - set_fact: + ansible_python_interpreter: "/usr/bin/python" + + - name: print variables + debug: + msg: "sensors_raw: {{ sensors['raw'] }}; file: {{ file }}; hwsku: {{ hwsku }}" + + - name: create sensors meta data file + sensors_meta_data: sensors_raw={{ sensors['raw'] }} file_name={{ file }} hwsku={{ hwsku }} + connection: local + register: sensors_metadata + + - debug: msg="{{ sensors_metadata }}"