If you need to use a particular piece of code frequently, you can organize it into commands. These commands are executed by calling ./noc <command_name>.
For instance, to display the version, you can use the command ./noc about, which is located in the commands/about.py file.
The BaseCommand.print() function is used to print output to stdout when developing custom commands. It is recommended to always use this function instead of the built-in print() function within your commands.
In this case, we are using it to print the version information.
As an example, we will extract the code for checking configured metrics into a command. We will add the ability to pass a list of metrics as parameters. The code will be placed in the commands/check-metrics.py file.
We check if command line parameters are provided ( option["metrics"] ), and if not, we call the BaseCommand.die() function. The die() function prints an error message to stderr and terminates the command with a system error code.
We need to retrieve the object (database record) by its name. In NOC, to fetch a record by name, model methods like .get_by_name() are used. In addition to simplifying the code, .get_by_name() also provides caching, which can significantly enhance performance.
If the record is not found, .get_by_name() returns None. We use the check for None to ensure that the user has provided the correct metric name. If the user has provided an incorrect name, we print an error message and move on to processing the next metric.
At this point, we check if the metric scope is Interface. If it is, we add the metric to the iface_metrics list; otherwise, we add it to object_metrics.
If the user has provided at least one interface metric, we call the check_interface_metrics function and pass the interface_metrics list as a parameter.
check-metrics.py
3839404142434445464748495051
defcheck_object_metrics(self,metrics:List[MetricType]):mt_check:Dict[str,MetricType]={str(mt.id):mtformtinmetrics}formopinManagedObjectProfile.objects.filter(enable_periodic_discovery_metrics=True,enable_periodic_discovery=True):checks=set(mt_check)formcinmop.metrics:ifmc["metric_type"]inchecks:checks.remove(mc["metric_type"])ifchecks:self.print(f"[{mop.name}] Not configured metrics: ",",".join(mt_check[c].nameforcinchecks),)
Now, let's define the check_object_metrics function, which takes a list of object metrics as input.
check-metrics.py
3839404142434445464748495051
defcheck_object_metrics(self,metrics:List[MetricType]):mt_check:Dict[str,MetricType]={str(mt.id):mtformtinmetrics}formopinManagedObjectProfile.objects.filter(enable_periodic_discovery_metrics=True,enable_periodic_discovery=True):checks=set(mt_check)formcinmop.metrics:ifmc["metric_type"]inchecks:checks.remove(mc["metric_type"])ifchecks:self.print(f"[{mop.name}] Not configured metrics: ",",".join(mt_check[c].nameforcinchecks),)
We build a dictionary mt_check, where the metric ID is used as the key, and the metric object is stored as the value.
check-metrics.py
3839404142434445464748495051
defcheck_object_metrics(self,metrics:List[MetricType]):mt_check:Dict[str,MetricType]={str(mt.id):mtformtinmetrics}formopinManagedObjectProfile.objects.filter(enable_periodic_discovery_metrics=True,enable_periodic_discovery=True):checks=set(mt_check)formcinmop.metrics:ifmc["metric_type"]inchecks:checks.remove(mc["metric_type"])ifchecks:self.print(f"[{mop.name}] Not configured metrics: ",",".join(mt_check[c].nameforcinchecks),)
We retrieve all object profiles where periodic discovery is enabled and metrics are defined.
check-metrics.py
3839404142434445464748495051
defcheck_object_metrics(self,metrics:List[MetricType]):mt_check:Dict[str,MetricType]={str(mt.id):mtformtinmetrics}formopinManagedObjectProfile.objects.filter(enable_periodic_discovery_metrics=True,enable_periodic_discovery=True):checks=set(mt_check)formcinmop.metrics:ifmc["metric_type"]inchecks:checks.remove(mc["metric_type"])ifchecks:self.print(f"[{mop.name}] Not configured metrics: ",",".join(mt_check[c].nameforcinchecks),)
We create a set check based on the keys in mt_check. In the future, we will remove the discovered metrics from it.
check-metrics.py
3839404142434445464748495051
defcheck_object_metrics(self,metrics:List[MetricType]):mt_check:Dict[str,MetricType]={str(mt.id):mtformtinmetrics}formopinManagedObjectProfile.objects.filter(enable_periodic_discovery_metrics=True,enable_periodic_discovery=True):checks=set(mt_check)formcinmop.metrics:ifmc["metric_type"]inchecks:checks.remove(mc["metric_type"])ifchecks:self.print(f"[{mop.name}] Not configured metrics: ",",".join(mt_check[c].nameforcinchecks),)
We iterate through all the metrics defined in the profile and, if they are present in our check, we remove them from the check set.
check-metrics.py
3839404142434445464748495051
defcheck_object_metrics(self,metrics:List[MetricType]):mt_check:Dict[str,MetricType]={str(mt.id):mtformtinmetrics}formopinManagedObjectProfile.objects.filter(enable_periodic_discovery_metrics=True,enable_periodic_discovery=True):checks=set(mt_check)formcinmop.metrics:ifmc["metric_type"]inchecks:checks.remove(mc["metric_type"])ifchecks:self.print(f"[{mop.name}] Not configured metrics: ",",".join(mt_check[c].nameforcinchecks),)
If there are remaining metrics in our check set, we write a message stating that they are not configured for the profile.
check-metrics.py
53545556575859606162
defcheck_interface_metrics(self,metrics:List[MetricType]):foripinInterfaceProfile.objects.filter(metrics__exists=True):checks=set(metrics)formcinip.metrics:ifmc.metric_typeinchecks:checks.remove(mc.metric_type)ifchecks:self.print(f"[{ip.name}] Not configured metrics: ",",".join(c.nameforcinchecks))
Now, let's define the check_interface_metrics function, which takes a list of interface metrics as input.
check-metrics.py
54555657585960616263
defcheck_interface_metrics(self,metrics:List[MetricType]):foripinInterfaceProfile.objects.filter(metrics__exists=True):checks=set(metrics)formcinip.metrics:ifmc.metric_typeinchecks:checks.remove(mc.metric_type)ifchecks:self.print(f"[{ip.name}] Not configured metrics: ",",".join(c.nameforcinchecks))
Now, let's define the check_interface_metrics function, which takes a list of interface metrics as input.
check-metrics.py
54555657585960616263
defcheck_interface_metrics(self,metrics:List[MetricType]):foripinInterfaceProfile.objects.filter(metrics__exists=True):checks=set(metrics)formcinip.metrics:ifmc.metric_typeinchecks:checks.remove(mc.metric_type)ifchecks:self.print(f"[{ip.name}] Not configured metrics: ",",".join(c.nameforcinchecks))
We create a set check from all the input function parameters.
check-metrics.py
54555657585960616263
defcheck_interface_metrics(self,metrics:List[MetricType]):foripinInterfaceProfile.objects.filter(metrics__exists=True):checks=set(metrics)formcinip.metrics:ifmc.metric_typeinchecks:checks.remove(mc.metric_type)ifchecks:self.print(f"[{ip.name}] Not configured metrics: ",",".join(c.nameforcinchecks))
We iterate through the metrics defined in the profile, and if they are present in our check, we remove them from the check set.
check-metrics.py
54555657585960616263
defcheck_interface_metrics(self,metrics:List[MetricType]):foripinInterfaceProfile.objects.filter(metrics__exists=True):checks=set(metrics)formcinip.metrics:ifmc.metric_typeinchecks:checks.remove(mc.metric_type)ifchecks:self.print(f"[{ip.name}] Not configured metrics: ",",".join(c.nameforcinchecks))
If there are remaining metrics in our check set, we write a message stating that they are not configured for the profile.
check-metrics.py
6566
if__name__=="__main__":Command().run()
This part of the code is common to all commands and is responsible for running our command from the command line.