def process(self, device, results, log): # call self.relMap() helper method that initializes relname and compname for me # rm = self.relMap() lines = results.split('\n') if lines[0] != "yes": # we are not in a container or on a host return [] pos = 1 try: page_size = int(lines[pos]) except ValueError: page_size = 4096 pos += 1 arch = lines[pos] pos += 1 hw_map = ObjectMap({"page_size" : page_size, "arch" : arch }, compname="hw") infolines = [] while lines[pos] != "#veinfo-stop": infolines.append(lines[pos]) pos += 1 vzinfo = VZInfoParser.parse(infolines) # if we find VE 0, we are on a host... foundZero = False # blank line: pos += 2 while pos < len(lines): # helper method - will set compname, modname, and classname for me: # it gets these settings from relname, modname, and classname = modname om = self.objectMap() if lines[pos] == "0": foundZero = True om.title = "CT0" om.id = "0" om.description = "Hardware Node" om.onboot = False om.ve_root = "N/A" om.ve_private = "N/A" om.container_status = "running" om.ostemplate = "N/A" om.ipaddrs=[] om.macaddrs=[] else: om.id = self.prepId(lines[pos]) # NAME if lines[pos+1]: om.title = lines[pos+1] om.hostname = lines[pos+2] om.ostemplate = lines[pos+3] # veth macaddr info on lines[pos+5] om.description = lines[pos+6] om.ve_root = lines[pos+7] om.ve_private = lines[pos+8] om.onboot = False if lines[pos] in vzinfo: om.container_status = vzinfo[lines[pos]] if om.container_status == "running": om.ipaddrs = [] # only update IPs if running so the IPs stick around if the container is stopped during remodel, # so we still have IPs for container component <-> managed device correlation :) for ip in lines[pos+4].split(): om.ipaddrs.append(ip) # again, only update MAC addresses from veth when we are in a running state, so we cache old # ones for correlation if a container happens to be stopped... om.macaddrs = [] for netif in lines[pos+5].split(";"): keypairs = netif.split(",") for kp in keypairs: kv = kp.split("=") if len(kv) != 2: continue if kv[0] == "mac": om.macaddrs.append(kv[1].lower()) if lines[pos+9] == "yes": om.onboot = True pos += 11 rm.append(om) if not foundZero: return [] # a relMap() is just a container to store objectMaps # in relmap and objectmap, there is a compname and modname # any # # # objectmaps and relmaps are temporary objects that the modeler plugin sends to zenhub, which then determines # if the model needs to be updated. # device/containers/106 # om ^ relmap ^ om^ # we are allowd to return: # a relmap - will be filled with object maps that are related to "device" # an objectmap - # a list of relmaps, objectmaps # If we get here, we've identified this as an OpenVZ host. Create a new # ObjectMap that will be applied to the device. Use it to call our # setOpenVZHostTemplate method on the device to bind the host-level # monitoring template. device_map = ObjectMap() device_map.setOpenVZHostTemplate = True return [device_map, hw_map, rm]
def processResults(self, cmd, result): # We have defined an openvz datasource for our container. It has a # datapoint called "container_status" that really isn't used for # recording RRD data. But having this datapoint allows us to create a # data pipeline for throwing events related to container status # changes. We just don't write any RRD data into the point at the very # end. for p in cmd.points: if p.id == "container_status": # grab container status info we provided in dataForParser(): existing_veids = p.data break else: return lines = cmd.result.output.split('\n') current_veids = VZInfoParser.parse(lines) event_count = 0 for veid in current_veids: if veid == "0": # do not generate any events for VEID 0 continue if veid not in existing_veids: event_count += 1 # We are not explicitly setting an event class here, so it will default to # /Unknown. This means that the event will not be immutably locked into an # event class and we can then use a mapping to control everything about it. # This allows us to place it in the event class that we want and and attach # a transform to this specific type of event, based on eventClassKey. The # transform allows us to execute python code to perform actions based on # information in the event. # We create event mappings in the UI, by selecting the Event and clicking on # the little "tree" icon, or this can be done without selecting an Event by # going to "Event Classes" , "Status" (for example), and at bottom of screen # "Event Class Mappings", you can add one here. Make sure "eventClassKey" # matches the "eventClassKey" set below in the code. This will place that # event into the /Status event class. # Also make sure to add the Event Mapping to the ZenPack by selecting its # link and going to "Add to ZenPack". # We can map Events based on eventClassKey. Then, there is a rule and regex # that can be used to make our event mapping even more specific. # The "rule" is a python expression. True = match; False = no match # The "regex" will be matched against the event's message field, which is # usually a copy of "summary" that hasn't been truncated. Match = match. # The "transform" is literal python code. # globals in the context of the code that executes in "transform" are: # # evt (Event Object) # device & dev (Device Object - may be None) # txnCommit (method to commit changes to the model) # log (logger that will output into zeneventd.log) # dmd (DataRoot Object) # component (Component Object - may be None) # getFacade (method to gain access to API facades) # IInfo (Info adapter interface - for convenience) # # Example code: # # if component: # # modify properties of the object directly... # component.container_status = evt.new_status # txnCommit() # # This will update the status of the component with which the event is # associated, and commit the new status information to the model. # # In this code, we are making direct changes to the model, which give us # the ability to update the model direct without using DeviceProxy(). # # To test: zensendevent -d 10.0.1.2 -p 106 -s Info -k openvz_container_status_change -o "new_status=weird" "container status change" # # An overview of event severity: # # 0 = clear (green) - can clear existing events - # a clear will happen if the following match in the method: fingerprint device|component|eventClass|eventKey # (optional) (optional) # 1 = debug (grey) # 2 = info (blue) # 3 = warning (yellow) # 4 = error (orange) # 5 = critical (red) result.events.append( dict(summary="OpenVZ container created", severity="2", eventClassKey="openvz_container_created", component=veid, old_status=None, new_status=current_veids[veid])) elif existing_veids[veid] != current_veids[veid]: event_count += 1 if current_veids[veid] == "running": summary = "OpenVZ container started" else: summary = "OpenVZ container " + current_veids[veid] result.events.append( dict( # limited to 128 characters: summary=summary, severity="2", eventClassKey="openvz_container_status_change", component=veid, old_status=existing_veids[veid], new_status=current_veids[veid])) e_set = set(existing_veids.keys()) e_set.discard("0") c_set = set(current_veids.keys()) c_set.discard("0") for veid in e_set - c_set: # in existing set, not in current - VEID disappeared event_count += 1 result.events.append( dict(summary="OpenVZ container destroyed", severity="2", eventClassKey="openvz_container_destroyed", component=veid, old_status=existing_veids[veid], new_status="destroyed"))
def processResults(self, cmd, result): # We have defined an openvz datasource for our container. It has a # datapoint called "container_status" that really isn't used for # recording RRD data. But having this datapoint allows us to create a # data pipeline for throwing events related to container status # changes. We just don't write any RRD data into the point at the very # end. for p in cmd.points: if p.id == "container_status": # grab container status info we provided in dataForParser(): existing_veids = p.data break else: return lines = cmd.result.output.split("\n") current_veids = VZInfoParser.parse(lines) event_count = 0 for veid in current_veids: if veid == "0": # do not generate any events for VEID 0 continue if veid not in existing_veids: event_count += 1 # We are not explicitly setting an event class here, so it will default to # /Unknown. This means that the event will not be immutably locked into an # event class and we can then use a mapping to control everything about it. # This allows us to place it in the event class that we want and and attach # a transform to this specific type of event, based on eventClassKey. The # transform allows us to execute python code to perform actions based on # information in the event. # We create event mappings in the UI, by selecting the Event and clicking on # the little "tree" icon, or this can be done without selecting an Event by # going to "Event Classes" , "Status" (for example), and at bottom of screen # "Event Class Mappings", you can add one here. Make sure "eventClassKey" # matches the "eventClassKey" set below in the code. This will place that # event into the /Status event class. # Also make sure to add the Event Mapping to the ZenPack by selecting its # link and going to "Add to ZenPack". # We can map Events based on eventClassKey. Then, there is a rule and regex # that can be used to make our event mapping even more specific. # The "rule" is a python expression. True = match; False = no match # The "regex" will be matched against the event's message field, which is # usually a copy of "summary" that hasn't been truncated. Match = match. # The "transform" is literal python code. # globals in the context of the code that executes in "transform" are: # # evt (Event Object) # device & dev (Device Object - may be None) # txnCommit (method to commit changes to the model) # log (logger that will output into zeneventd.log) # dmd (DataRoot Object) # component (Component Object - may be None) # getFacade (method to gain access to API facades) # IInfo (Info adapter interface - for convenience) # # Example code: # # if component: # # modify properties of the object directly... # component.container_status = evt.new_status # txnCommit() # # This will update the status of the component with which the event is # associated, and commit the new status information to the model. # # In this code, we are making direct changes to the model, which give us # the ability to update the model direct without using DeviceProxy(). # # To test: zensendevent -d 10.0.1.2 -p 106 -s Info -k openvz_container_status_change -o "new_status=weird" "container status change" # # An overview of event severity: # # 0 = clear (green) - can clear existing events - # a clear will happen if the following match in the method: fingerprint device|component|eventClass|eventKey # (optional) (optional) # 1 = debug (grey) # 2 = info (blue) # 3 = warning (yellow) # 4 = error (orange) # 5 = critical (red) result.events.append( dict( summary="OpenVZ container created", severity="2", eventClassKey="openvz_container_created", component=veid, old_status=None, new_status=current_veids[veid], ) ) elif existing_veids[veid] != current_veids[veid]: event_count += 1 if current_veids[veid] == "running": summary = "OpenVZ container started" else: summary = "OpenVZ container " + current_veids[veid] result.events.append( dict( # limited to 128 characters: summary=summary, severity="2", eventClassKey="openvz_container_status_change", component=veid, old_status=existing_veids[veid], new_status=current_veids[veid], ) ) e_set = set(existing_veids.keys()) e_set.discard("0") c_set = set(current_veids.keys()) c_set.discard("0") for veid in e_set - c_set: # in existing set, not in current - VEID disappeared event_count += 1 result.events.append( dict( summary="OpenVZ container destroyed", severity="2", eventClassKey="openvz_container_destroyed", component=veid, old_status=existing_veids[veid], new_status="destroyed", ) )