def fetch_callback(self, cluster: int, item: int, inst: int): """PMDA fetch callback""" if cluster == Consts.Control.Cluster: if item == Consts.Control.Register: json_val = ScriptEncoder(dump_state_data=False).encode( self.get_ctx_state(pmdaGetContext(), 'register', default={}, delete=True)) return [json_val, 1] elif item == Consts.Control.Deregister: json_val = json.dumps(self.get_ctx_state(pmdaGetContext(), 'deregister', default={}, delete=True)) return [json_val, 1] elif item == Consts.Control.Start: json_val = json.dumps(self.get_ctx_state(pmdaGetContext(), 'start', default={}, delete=True)) return [json_val, 1] elif item == Consts.Control.Stop: json_val = json.dumps(self.get_ctx_state(pmdaGetContext(), 'stop', default={}, delete=True)) return [json_val, 1] elif cluster == Consts.Info.Cluster: if item == Consts.Info.Scripts: id_or_name = self.script_indom.inst_name_lookup(inst) if id_or_name is None: return [c_api.PM_ERR_INST, 0] cluster = self.find_cluster_by_name(id_or_name) if cluster: return [cluster.script.code, 1] return [c_api.PM_ERR_INST, 0] elif item == Consts.Info.ScriptsJson: scripts = [cluster.script for cluster in self.clusters.values()] return [ScriptEncoder(dump_state_data=False).encode(scripts), 1] elif item == Consts.Info.Tracepoints: return [self.tracepoints_csv, 1] elif cluster in self.clusters: return self.clusters[cluster].fetch_callback(item, inst) return [c_api.PM_ERR_PMID, 0]
def set_ctx_state(self, key: str, value: Any, ctx=None): """set per-context state""" if ctx is None: ctx = pmdaGetContext() if ctx not in self.ctxtab: self.ctxtab[ctx] = {} self.ctxtab[ctx][key] = value
def store_callback(self, cluster: int, item: int, inst: int, val: str): """PMDA store callback""" if cluster == Consts.Control.Cluster: if not self.config.dynamic_scripts.enabled: self.logger.error("dynamic scripts are disabled in configuration") return c_api.PM_ERR_PERMISSION if self.config.dynamic_scripts.auth_enabled: username = self.get_ctx_state(pmdaGetContext(), 'username') if username is None: self.logger.info("permission denied for unauthenticated user") return c_api.PM_ERR_PERMISSION elif username not in self.config.dynamic_scripts.allowed_users: self.logger.info(f"permission denied for user {username}") return c_api.PM_ERR_PERMISSION if item == Consts.Control.Register: script = Script(val) script.username = self.get_ctx_state(pmdaGetContext(), 'username') return self.register_script(script) elif item == Consts.Control.Deregister: success = True for script_id in val.split(','): if not self.deregister_script(script_id): success = False if success: self.set_ctx_state(pmdaGetContext(), 'deregister', {"success": "true"}) return 0 else: self.set_ctx_state(pmdaGetContext(), 'deregister', {"error": "one or more scripts were not found"}) return c_api.PM_ERR_BADSTORE elif item == Consts.Control.Start: cluster = self.find_cluster_by_name(val) if not cluster: self.set_ctx_state(pmdaGetContext(), 'start', {"error": "script not found"}) return c_api.PM_ERR_BADSTORE self.bpftrace_service.start_script(cluster.script.script_id) self.set_ctx_state(pmdaGetContext(), 'start', {"success": "true"}) return 0 elif item == Consts.Control.Stop: cluster = self.find_cluster_by_name(val) if not cluster: self.set_ctx_state(pmdaGetContext(), 'stop', {"error": "script not found"}) return c_api.PM_ERR_BADSTORE self.bpftrace_service.stop_script(cluster.script.script_id) self.set_ctx_state(pmdaGetContext(), 'stop', {"success": "true"}) return 0 return c_api.PM_ERR_PMID
def register_script(self, script: Script, update_ctx=True): """register a new bpftrace script""" script = self.bpftrace_service.register_script(script) if update_ctx: self.set_ctx_state(pmdaGetContext(), 'register', script) if script.state.status == Status.Error: return c_api.PM_ERR_BADSTORE cluster = BPFtraceCluster(self, self.logger, self.bpftrace_service, script) cluster.register_metrics() self.clusters[cluster.cluster_id] = cluster self.refresh_script_indom() return 0
def get_ctx_state(self, key: str, ctx=None, default=None, delete=False) -> Any: """get per-context state""" if ctx is None: ctx = pmdaGetContext() if ctx not in self.ctxtab or key not in self.ctxtab[ctx]: return default value = self.ctxtab[ctx].get(key, default) if delete: del self.ctxtab[ctx][key] return value