def test_greater_operator(self): assert str(GreaterOperator("uptime", 150))\ == '[">", "uptime", 150]' assert str(GreaterOperator("end_time", '2016-05-11T23:22:48.709Z'))\ == '[">", "end_time", "2016-05-11T23:22:48.709Z"]' assert str(GreaterOperator(['parameter', 'version'], 4.0))\ == '[">", ["parameter", "version"], 4.0]' assert str(GreaterOperator("report_timestamp", datetime.datetime(2016, 6, 11)))\ == '[">", "report_timestamp", "2016-06-11 00:00:00"]'
def test_not_operator(self): op = NotOperator() op.add(EqualsOperator("operatingsystem", "CentOS")) assert str(op) == '["not", ["=", "operatingsystem", "CentOS"]]' assert repr(op) == 'Query: ["not", ["=", "operatingsystem", "CentOS"]]' assert str(op) == '["not", ["=", "operatingsystem", "CentOS"]]' with pytest.raises(APIError): op.add(GreaterOperator("operatingsystemmajrelease", 6)) with pytest.raises(APIError): op.add([EqualsOperator("architecture", "x86_64"), GreaterOperator("operatingsystemmajrelease", 6)])
def _puppetdb_nodes(rules, master_id, master_address): if "facts" not in rules or not rules["facts"]: return set() if rules["match_type"] == "ALL": operator = AndOperator() else: operator = OrOperator() for fact_rule in rules["facts"]: rule_op = fact_rule["operator"] lhs = ["fact", fact_rule["fact"]] rhs = fact_rule["value"] if rule_op == "=": operator.add(EqualsOperator(lhs, rhs)) elif rule_op == "!=": notop = NotOperator() notop.add(EqualsOperator(lhs, rhs)) operator.add(notop) elif rule_op == "~": operator.add(RegexOperator(lhs, rhs)) elif rule_op == "!~": notop = NotOperator() notop.add(RegexOperator(lhs, rhs)) operator.add(notop) elif rule_op == ">": operator.add(GreaterOperator(lhs, rhs)) elif rule_op == ">=": operator.add(GreaterEqualOperator(lhs, rhs)) elif rule_op == "<": operator.add(LessOperator(lhs, rhs)) elif rule_op == "<=": operator.add(LessEqualOperator(lhs, rhs)) query_str = str(operator).replace("'", '"') cert_instance = CertsClass(master_id) cert_path = cert_instance.get_cert() private_key_path = cert_instance.get_key() req = requests.get( f"https://{master_address}:8081/pdb/meta/v1/version", verify=False, cert=(cert_path, private_key_path), ) if req.status_code == 404: # PuppetDB <= 2.x nodes_uri = f"https://{master_address}:8081/v4/nodes?query={query_str}" else: # PuppetDB >= 3.x nodes_uri = ( f"https://{master_address}:8081/pdb/query/v4/nodes?query={query_str}" ) # Fetch the matching nodes req = requests.get(nodes_uri, verify=False, cert=(cert_path, private_key_path)) return {node["certname"] for node in req.json()}
def main(): """main entry point""" args = get_args() logging.basicConfig(level=get_log_level(args.verbose)) failed_nodes = [] pdb = connect() nodes = defaultdict(dict) max_age = datetime.utcnow() - timedelta(hours=args.max_age) extract = ExtractOperator() extract.add_field(['certname', FunctionOperator('count'), 'status']) extract.add_group_by(['certname', 'status']) extract.add_query(GreaterOperator('receive_time', max_age.isoformat())) # pypuppetdb does have a `reports` method which wraps `_query`. however it yields # results of type pypuppetdb.Report which expects a number of parameters e.g. hash # to be present in the result payload. however we don't extract theses values and # therefore have to resort to the more powerful private method reports = pdb._query('reports', query=extract) # pylint: disable=protected-access for report in reports: nodes[report['certname']][report['status']] = report['count'] if args.dev: failed_nodes = [hostname for hostname, node in nodes.items() if not node.get('unchanged', 0)] else: for fqdn, node in nodes.items(): # skip hosts with no unchanged reports: if node.get('unchanged', 0): continue # skip staging servers: # - hostname starting labstest* # - hostname ending dev or dev\d{4} # - hostname ending test or test\d{4} if (fqdn.startswith('labtest') or search(r'(:?dev|test)(:?\d{4})?$', fqdn.split('.')[0]) is not None): logger.debug('%s: Skipping staging host', fqdn) continue failed_nodes.append(fqdn) if len(failed_nodes) >= args.critical: print('CRITICAL: the following ({}) node(s) change every puppet run: {}'.format( len(failed_nodes), ', '.join(failed_nodes))) return 2 if len(failed_nodes) >= args.warning: print('WARNING: the following ({}) node(s) change every puppet run: {}'.format( len(failed_nodes), ', '.join(failed_nodes))) return 1 print('OK: all nodes running as expected') return 0
def test_or_operator(self): op = OrOperator() op.add(EqualsOperator("operatingsystem", "CentOS")) op.add([EqualsOperator("architecture", "x86_64"), GreaterOperator("operatingsystemmajrelease", 6)]) assert str(op) == '["or", ["=", "operatingsystem", "CentOS"], '\ '["=", "architecture", "x86_64"], '\ '[">", "operatingsystemmajrelease", 6]]' assert repr(op) == 'Query: ["or", '\ '["=", "operatingsystem", "CentOS"], '\ '["=", "architecture", "x86_64"], '\ '[">", "operatingsystemmajrelease", 6]]' assert str(op) == '["or", ["=", "operatingsystem", "CentOS"], ' \ '["=", "architecture", "x86_64"], '\ '[">", "operatingsystemmajrelease", 6]]' with pytest.raises(APIError): op.add({"query1": '["=", "catalog_environment", "production"]'})
def main(): """main entry point""" args = get_args() logging.basicConfig(level=get_log_level(args.verbose)) pdb = connect() nodes = defaultdict(dict) max_age = datetime.utcnow() - timedelta(hours=args.max_age) extract = ExtractOperator() extract.add_field(['certname', FunctionOperator('count'), 'status']) extract.add_group_by(['certname', 'status']) extract.add_query(GreaterOperator('receive_time', max_age.isoformat())) # pypuppetdb does have a `reports` method which wraps `_query`. however it yields # results of type pypuppetdb.Report which expects a number of parameters e.g. hash # to be present in the result payload. however we don't extract theses values and # therefore have to resort to the more powerful private method reports = pdb._query('reports', query=extract) # pylint: disable=protected-access for report in reports: nodes[report['certname']][report['status']] = report['count'] failed_nodes = [ hostname for hostname, node in nodes.items() if not node.get('unchanged', 0) ] if len(failed_nodes) >= args.critical: print( 'CRITICAL: the following ({}) node(s) change every puppet run: {}'. format(len(failed_nodes), ', '.join(failed_nodes))) return 2 if len(failed_nodes) >= args.warning: print( 'WARNING: the following ({}) node(s) change every puppet run: {}'. format(len(failed_nodes), ', '.join(failed_nodes))) return 1 print('OK: all nodes running as expected') return 0
def test_with_add_query(self): op = ExtractOperator() op.add_field(['certname', 'fact_environment', 'catalog_environment']) with pytest.raises(APIError): op.add_query({'less': 42, 'greater': 50}) op.add_query(EqualsOperator('domain', 'example.com')) assert repr(op) == 'Query: ["extract", '\ '["certname", "fact_environment", "catalog_environment"], '\ '["=", "domain", "example.com"]]' assert str(op) == '["extract", '\ '["certname", "fact_environment", "catalog_environment"], '\ '["=", "domain", "example.com"]]' assert str(op) == '["extract", ' \ '["certname", "fact_environment", "catalog_environment"], '\ '["=", "domain", "example.com"]]' with pytest.raises(APIError): op.add_query(GreaterOperator("processorcount", 1))