def command(self, opts, template_name, *params): """Add a single graph based on a template Arguments: template_name -- the name of the template file params -- other parameters (see below) The templates are in json, and is in the same format as the output of the dump_graph command. Other parameters are specified as "param_name=value" and will be substituted in the template. Use {param_name} in the template. """ try: template = util.GraphTemplate(template_name) except IOError: log.error("Unable to open template %s" % template_name) sys.exit(1) template_params = template.parse_nv_params(params) graph_data = template.sub(template_params) log.msgnb("Adding graph: %s..." % graph_data["title"]) try: rv = self.api.add_graph(graph_data=json.dumps(graph_data)) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error(e.error)
def add_checks(self): for name, idx in sorted(self.ports.items()): log.msgnb("Adding port %s..." % name) metric_names = [] params = { 'account': self.account, 'agent_id': self.agent, 'target': self.target, 'module': "snmp", 'display_name_%s' % self.target: "%s port %s interface stats" % ( self.friendly_name, name), 'community': self.community} for k in self.metrics: metric_names.append(k) params["oid_%s" % k] = "%s.%s" % (self.metrics[k], idx) params['metric_name'] = metric_names for k in sorted(params): log.debug("%20s = %s" % (k, params[k])) try: rv = self.api.add_check_bundle(**params) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error(e.error)
def command(self, opts, duration, pattern, notes=""): """Schedule maintenance for rules matching the pattern Arguments: duration -- how long should the maintenance window last? pattern -- pattern to match the check name with notes -- optional notes for the maintenance window Duration should be of the form <integer>[m|h|d]. Examples: 10m == 10 minutes 4h == 4 hours 2d == 2 days """ if duration[-1] not in 'mhd': log.error("Duration needs to be of the form <integer>[m|h|d]") sys.exit(1) rules = self.api.list_rules() checks = self.api.list_checks(active='true') filtered_checks = {} for c in checks: if re.search(pattern, c['name'], flags=re.IGNORECASE): filtered_checks[c['check_id']] = c filtered_rules = [r for r in rules if r['check_id'] in filtered_checks] # Remove duplicates dedup_rules = {} for r in filtered_rules: dedup_rules[(r['check_id'], r['metric_name'], r['severity'])] = r filtered_rules = dedup_rules.values() log.msg("Scheduling maintenance for:") for r in sorted(filtered_rules): print " Sev %s : %s : %s (from %s)" % ( r['severity'], filtered_checks[r['check_id']]['name'], r['metric_name'], filtered_checks[r['check_id']]['agent']) if util.confirm(): log.msg("Setting maintenance:") for r in filtered_rules: log.msgnb("Sev %s : %s : %s..." % ( r['severity'], filtered_checks[r['check_id']]['name'], r['metric_name'])) try: self.api.add_maintenance( check_id=r['check_id'], start='now', stop=duration, metric_name=r['metric_name'], severity=r['severity'], notes=notes) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error(e.error)
def get_agent(api, agent_name): rv = api.list_agents() agents = dict([(i['name'], i['agent_id']) for i in rv]) try: return agents[agent_name] except KeyError: log.error("Invalid/Unknown Agent: %s" % agent_name) log.msg("Valid Agents:") for a in agents: log.msgnf(" %s" % a) sys.exit(1)
def command(self, opts, pattern, *metrics_to_enable): """Activate metrics for checks Arguments: pattern -- Pattern for checks metrics_to_enable -- List of metrics to enable """ checks, groups = util.find_checks(self.api, pattern) already_enabled = {} # Pick only one check per check bundle bundles = {} for c in checks: if c['bundle_id'] in bundles: continue bundles[c['bundle_id']] = c log.msg("Retrieving metrics for checks") count = 0 for c in bundles.values(): count += 1 print "\r%s/%s" % (count, len(bundles)), sys.stdout.flush() rv = self.api.list_metrics(check_id=c['check_id']) already_enabled[c['check_id']] = [] for metric in sorted(rv): if metric['enabled']: already_enabled[c['check_id']].append(metric['name']) log.msg("Metrics to enable: %s" % (', '.join(metrics_to_enable))) log.msg("About to enable metrics for the following checks") for c in bundles.values(): log.msg(" %s (%s)" % (c['name'], ', '.join(already_enabled[c['check_id']]))) if util.confirm(): for c in bundles.values(): # Enable metrics here log.msgnb("%s..." % c['name']) all_metrics = set(already_enabled[c['check_id']]) \ | set(metrics_to_enable) if all_metrics != set(already_enabled[c['check_id']]): # The set of metrics has changed, apply the edit self.api.edit_check_bundle( bundle_id=c['bundle_id'], metric_name=list(all_metrics)) log.msgnf("Done") else: log.msgnf("No changes")
def command(self, opts, pattern, *metrics_to_enable): """Set the active metrics for a check based on regular expression This command will set the enabled metrics to exactly what matches the pattern(s) given. Any other metrics will be disabled, regardless of what their original setting was. Arguments: pattern -- Pattern for checks metrics_to_enable -- One or more regexes for enabled metrics """ checks, groups = util.find_checks(self.api, pattern) to_enable = {} # Pick only one check per check bundle bundles = {} for c in checks: if c['bundle_id'] in bundles: continue bundles[c['bundle_id']] = c log.msg("Retrieving metrics for checks") count = 0 for c in bundles.values(): count += 1 print "\r%s/%s" % (count, len(bundles)), sys.stdout.flush() rv = self.api.list_available_metrics(check_id=c['check_id']) to_enable[c['check_id']] = [] for mtype in rv['metrics']: for metric in rv['metrics'][mtype]: for pattern in metrics_to_enable: if re.match(pattern, metric): to_enable[c['check_id']].append(metric) log.msg("About to set enabled metrics for the following checks") for c in bundles.values(): log.msg(" %s (%s)" % (c['name'], ', '.join(sorted(to_enable[c['check_id']])))) if util.confirm(): for c in bundles.values(): # Enable metrics here log.msgnb("%s..." % c['name']) # The set of metrics has changed, apply the edit self.api.edit_check_bundle( bundle_id=c['bundle_id'], metric_name=to_enable[c['check_id']]) log.msgnf("Done")
def command(self, opts, pattern, replacement): """Rename multiple graphs at once Arguments: pattern -- a regex to select the graphs to rename replacement -- what to replace the graph name with The replacement can contain \1, \2 etc. to refer to groups in the pattern. """ rv = self.api.list_graphs() filtered_graphs = [] for g in sorted(rv, lambda a, b: cmp(a['title'], b['title'])): if re.search(pattern, g['title']): filtered_graphs.append(g) renames = {} log.msg("Going to perform the following renames:") for g in filtered_graphs: renames[g['title']] = re.sub(pattern, replacement, g['title']) log.msg(" %s => %s" % (g['title'], renames[g['title']])) if util.confirm(): for g in filtered_graphs: log.msgnb("Renaming %s..." % g['title']) try: rv = self.api.get_graph( graph_id=g['graph_id']) except circonusapi.CirconusAPIError, e: log.msgnf("Failed to fetch current graph") log.error(e.error) continue try: graph_data = json.loads(rv['graph_data']) except KeyError: log.msgnf("Failed to fetch current graph") log.error("No graph data returned") continue except ValueError: log.msgnf("Failed to fetch current graph") log.error("Unable to parse the graph data") continue graph_data['title'] = renames[g['title']] try: rv = self.api.edit_graph(graph_id=g['graph_id'], graph_data=json.dumps(graph_data)) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed to edit graph") log.error(e.error)
def add_graphs(self, template, checks, groups): for c in checks: params = { "check_name": c['name'], "check_id": c['check_id'], "check_target": c['target'], "check_agent": c['agent']} params.update(groups[c['check_id']]) graph_data = template.sub(params) log.msgnb("Adding graph: %s..." % graph_data['title']) try: rv = self.api.add_graph(graph_data=json.dumps(graph_data)) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error(e.error)
def command(self, opts, pattern, replacement): """Rename multiple checks at once Options: -a - Include inactive and deleted checks also Arguments: pattern -- a regex to select the checks to rename replacement -- what to replace the check name with The replacement can contain \1, \2 etc. to refer to groups in the pattern. """ active = 'true' if ('-a', '') in opts: active = '' rv = self.api.list_checks(active=active) filtered_checks = [] # We rename bundles, not checks, so only do each bundle once bundles = {} for check in sorted(rv): if re.search(pattern, check['name']): if not check['bundle_id'] in bundles: filtered_checks.append(check) bundles[check['bundle_id']] = True renames = {} log.msg("Going to perform the following renames:") for c in filtered_checks: renames[c['name']] = re.sub(pattern, replacement, c['name']) log.msg("%s => %s" % (c['name'], renames[c['name']])) if util.confirm(): for c in filtered_checks: log.msgnb("Renaming %s... " % c['name']) metrics = [m['name'] for m in self.api.list_metrics(check_id=c['check_id'])] params = { 'bundle_id': c['bundle_id'], 'metric_name': metrics, 'display_name_%s' % c['target']: renames[c['name']]} try: rv = self.api.edit_check_bundle(**params) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error(e.error)
def command(self, opts, check_pattern, metric_pattern=None): """Removes rules for checks that match the given pattern Arguments: check_pattern -- regex to match check names on (optional) metric_pattern -- regex to match metric names on (optional) At least one of check_pattern or metric_pattern must be provided. If you want to leave out the check_pattern, then specify it as an empty string. """ rules = self.api.list_rules() if check_pattern and check_pattern != '.': checks, groups = util.find_checks(self.api, check_pattern) check_ids = dict([(c['check_id'], c['name']) for c in checks]) matching = [r for r in rules if r['check_id'] in check_ids] else: checks = self.api.list_checks() check_ids = dict([(c['check_id'], c['name']) for c in checks]) matching = rules if metric_pattern: matching = [r for r in matching if re.search(metric_pattern, r['metric_name'])] matching = sorted(matching, reverse=True, key=lambda x: (x['check_id'], x['metric_name'], x['order'])) log.msg("About to delete the following rules:") for r in matching: log.msg("%s`%s (%s - %s %s)" % (check_ids[r['check_id']], r['metric_name'], r['order'], r['criteria'], r['value'])) if util.confirm(): for r in matching: log.msgnb("Deleting %s`%s (%s)..." % ( check_ids[r['check_id']], r['metric_name'], r['order'])) try: rv = self.api.remove_metric_rule(check_id=r['check_id'], metric_name=r['metric_name'], order=r['order']) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error(e.error)
def command(self, opts, pattern): """Delete multiple graphs at once Arguments: pattern -- a regex to select the graphs to delete """ rv = self.api.list_graphs() filtered_graphs = [] for g in sorted(rv, lambda a, b: cmp(a['title'], b['title'])): if re.search(pattern, g['title']): filtered_graphs.append(g) log.msg("Going to DELETE the following graphs:") for g in filtered_graphs: log.msg(" %s" % g['title']) if util.confirm(): for g in filtered_graphs: log.msgnb("Deleting %s..." % g['title']) try: rv = self.api.remove_graph(graph_id=g['graph_id']) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error(e.error)
def command(self, opts, old_check_id, old_metric_name, new_check_id, new_metric_name): """Clone rulesets from one check to another Arguments: old_check_id -- the check_id to copy the ruleset from old_metric_name -- the metric_name to copy the ruleset from new_check_id -- the check_id to copy the ruleset to new_metric_name -- the metric_name to copy the ruleset to """ rules = self.api.list_rules(check_id=old_check_id, metric_name=old_metric_name) for r in rules: r['check_id'] = new_check_id r['metric_name'] = new_metric_name for r in rules: log.msgnb("Adding rule %s... " % r['order']) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error(e.error) return
def command(self, opts, title, pattern): """Add a worksheet containing matching graphs Arguments: pattern -- a regex to match on graph names Options: -f/--favorite -- mark the worksheet as a favorite """ rv = self.api.list_graphs() filtered_graphs = [] for g in sorted(rv, lambda a, b: cmp(a['title'], b['title'])): if re.search(pattern, g['title']): filtered_graphs.append(g) favorite = False if ('-f', '') in opts or ('--favorite', '') in opts: favorite = True worksheet_data = { 'title': title, 'favorite': favorite, 'graphs': filtered_graphs} log.msg("Adding a worksheet with the following graphs:") for i in filtered_graphs: log.msg(" %s" % i['title']) if favorite: log.msg("Worksheet will be marked as a favorite") if not util.confirm(): log.msg("Not adding worksheet") sys.exit(1) log.msgnb("Adding worksheet... ") try: self.api.add_worksheet(worksheet_data=json.dumps(worksheet_data)) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error("Unable to add worksheet: %s" % e)
def command(self, opts, template_name, pattern, *params): """Adds rules for checks that match the given pattern Arguments: template_name -- the name of the template file pattern -- regex to match check names on params -- other parameters (see below) Other parameters are specified as "param_name=value" and will be substituted in the template. Use {param_name} in the template. Some predefined parameters: {check_id} - The check ID {check_name} - The check name {check_target} - The target of the check (IP address) {check_agent} - The agent the check is run from {groupN} - Matching groups (the parts in parentheses) in the pattern given on the command line. (replace N with a group number) """ template = util.RuleTemplate(template_name) template_params = template.parse_nv_params(params) checks, groups = util.find_checks(self.api, pattern) util.verify_metrics(self.api, template, checks) log.msg("About to add %s rules for the following checks:" % (template_name)) for c in checks: log.msg(" %s (%s)" % (c["name"], c["agent"])) if not util.confirm(): log.msg("Not adding rules.") sys.exit() for c in checks: p = { "check_name": c["name"], "check_id": c["check_id"], "check_target": c["target"], "check_agent": c["agent"], } p.update(template_params) p.update(groups[c["check_id"]]) substituted = template.sub(p) # Get mapping from contact group name to ID rv = self.api.list_contact_groups() contact_group_ids = {} for i in rv: contact_group_ids[i["name"]] = i["contact_group_id"] for rule in substituted: # Extract the contact groups and get the IDs for severity in rule["contact_groups"]: contact_group_names = rule["contact_groups"][severity] del rule["contact_groups"][severity] rule["contact_groups"][severity] = [] for cg in contact_group_names: rule["contact_groups"][severity].append({"id": contact_group_ids[cg], "name": cg}) log.msgnb("Adding rule for %s... " % c["name"]) try: rv = self.api.set_ruleset(ruleset=json.dumps(rule)) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error(e.error)
def command(self, opts, graph_id, new_title, *params): """Copy a graph, changing some parameters Options: -v -- Show the new graph data before adding the graph Arguments: graph_id -- The UUID of the graph you want to copy new_title -- The title of the new graph params -- Search/replace on datapoint values The search/replace parameters will replace any datapoint values, including the check_id, metric_name, colors, and datapoint names. Parameters should be of the form: search_term=replacement For example, to modify the check id, you can do 1234=2345 You can also specify a single number without an equals sign. In this case, all check ids that aren't replaced with another pattern will be set to this value. If you have a graph that is only for a single check, then specifying the check id mapping as a single number is what you want. """ try: uuid.UUID(graph_id) except ValueError: log.error("Invalid graph ID specified. It should look like a UUID") sys.exit(1) rv = self.api.get_graph(graph_id=graph_id) graph_data = json.loads(rv["graph_data"]) # Set the new title graph_data["title"] = new_title subs = {} default_check_id = None for p in params: try: # First try to parse as a single check id default_check_id = int(p) continue except ValueError: pass parts = [i for i in p.split("=", 1)] try: subs[parts[0]] = parts[1] except IndexError: log.error("Invalid substitution: %s" % p) sys.exit(1) for d in graph_data["datapoints"]: for k in d: if type(d[k]) == str or type(d[k]) == unicode: # String search/replace for s in subs: d[k] = d[k].replace(s, subs[s]) print d[k], s, subs[s] elif type(d[k]) == int: # Integer replacement (matches only on the whole number) # Used for check_ids if str(d[k]) in subs: d[k] = int(subs[str(d[k])]) elif k == "check_id" and default_check_id: # If we didn't do a substitution previously, and we're # considering a check_id, replace the check_id with # the default d[k] = default_check_id if ("-v", "") in opts: print json.dumps(graph_data, indent=4) if not util.confirm(): log.msg("Not adding graph.") sys.exit(0) log.msgnb("Adding copied graph: %s..." % graph_data["title"]) try: rv = self.api.add_graph(graph_data=json.dumps(graph_data)) log.msgnf("Success") except circonusapi.CirconusAPIError, e: log.msgnf("Failed") log.error(e.error)