1# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com> 2# 3# This file is part of Ansible 4# 5# Ansible is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# Ansible is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 17 18# Make coding more python3-ish 19from __future__ import (absolute_import, division, print_function) 20__metaclass__ = type 21 22from ansible.module_utils.common._collections_compat import MutableMapping 23from ansible.utils.vars import merge_hash 24 25 26class AggregateStats: 27 ''' holds stats about per-host activity during playbook runs ''' 28 29 def __init__(self): 30 31 self.processed = {} 32 self.failures = {} 33 self.ok = {} 34 self.dark = {} 35 self.changed = {} 36 self.skipped = {} 37 self.rescued = {} 38 self.ignored = {} 39 40 # user defined stats, which can be per host or global 41 self.custom = {} 42 43 def increment(self, what, host): 44 ''' helper function to bump a statistic ''' 45 46 self.processed[host] = 1 47 prev = (getattr(self, what)).get(host, 0) 48 getattr(self, what)[host] = prev + 1 49 50 def decrement(self, what, host): 51 _what = getattr(self, what) 52 try: 53 if _what[host] - 1 < 0: 54 # This should never happen, but let's be safe 55 raise KeyError("Don't be so negative") 56 _what[host] -= 1 57 except KeyError: 58 _what[host] = 0 59 60 def summarize(self, host): 61 ''' return information about a particular host ''' 62 63 return dict( 64 ok=self.ok.get(host, 0), 65 failures=self.failures.get(host, 0), 66 unreachable=self.dark.get(host, 0), 67 changed=self.changed.get(host, 0), 68 skipped=self.skipped.get(host, 0), 69 rescued=self.rescued.get(host, 0), 70 ignored=self.ignored.get(host, 0), 71 ) 72 73 def set_custom_stats(self, which, what, host=None): 74 ''' allow setting of a custom stat''' 75 76 if host is None: 77 host = '_run' 78 if host not in self.custom: 79 self.custom[host] = {which: what} 80 else: 81 self.custom[host][which] = what 82 83 def update_custom_stats(self, which, what, host=None): 84 ''' allow aggregation of a custom stat''' 85 86 if host is None: 87 host = '_run' 88 if host not in self.custom or which not in self.custom[host]: 89 return self.set_custom_stats(which, what, host) 90 91 # mismatching types 92 if not isinstance(what, type(self.custom[host][which])): 93 return None 94 95 if isinstance(what, MutableMapping): 96 self.custom[host][which] = merge_hash(self.custom[host][which], what) 97 else: 98 # let overloaded + take care of other types 99 self.custom[host][which] += what 100