summaryrefslogtreecommitdiffstats
path: root/src/mgr/PyModule.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mgr/PyModule.h')
-rw-r--r--src/mgr/PyModule.h193
1 files changed, 193 insertions, 0 deletions
diff --git a/src/mgr/PyModule.h b/src/mgr/PyModule.h
new file mode 100644
index 000000000..8d88ff94c
--- /dev/null
+++ b/src/mgr/PyModule.h
@@ -0,0 +1,193 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2017 John Spray <john.spray@redhat.com>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+#include <boost/optional.hpp>
+#include "common/ceph_mutex.h"
+#include "Python.h"
+#include "Gil.h"
+#include "mon/MgrMap.h"
+
+
+class MonClient;
+
+std::string handle_pyerror(bool generate_crash_dump = false,
+ std::string module = {},
+ std::string caller = {});
+
+std::string peek_pyerror();
+
+/**
+ * A Ceph CLI command description provided from a Python module
+ */
+class ModuleCommand {
+public:
+ std::string cmdstring;
+ std::string helpstring;
+ std::string perm;
+ bool polling;
+
+ // Call the ActivePyModule of this name to handle the command
+ std::string module_name;
+};
+
+class PyModule
+{
+ mutable ceph::mutex lock = ceph::make_mutex("PyModule::lock");
+private:
+ const std::string module_name;
+ std::string get_site_packages();
+ int load_subclass_of(const char* class_name, PyObject** py_class);
+
+ // Did the MgrMap identify this module as one that should run?
+ bool enabled = false;
+
+ // Did the MgrMap flag this module as always on?
+ bool always_on = false;
+
+ // Did we successfully import this python module and look up symbols?
+ // (i.e. is it possible to instantiate a MgrModule subclass instance?)
+ bool loaded = false;
+
+ // Did the module identify itself as being able to run?
+ // (i.e. should we expect instantiating and calling serve() to work?)
+ bool can_run = false;
+
+ // Did the module encounter an unexpected error while running?
+ // (e.g. throwing an exception from serve())
+ bool failed = false;
+
+ // Populated if loaded, can_run or failed indicates a problem
+ std::string error_string;
+
+ // Helper for loading MODULE_OPTIONS and COMMANDS members
+ int walk_dict_list(
+ const std::string &attr_name,
+ std::function<int(PyObject*)> fn);
+
+ int load_commands();
+ std::vector<ModuleCommand> commands;
+
+ int register_options(PyObject *cls);
+ int load_options();
+ std::map<std::string, MgrMap::ModuleOption> options;
+
+ int load_notify_types();
+ std::set<std::string> notify_types;
+
+public:
+ static std::string mgr_store_prefix;
+
+ SafeThreadState pMyThreadState;
+ PyObject *pClass = nullptr;
+ PyObject *pStandbyClass = nullptr;
+
+ explicit PyModule(const std::string &module_name_)
+ : module_name(module_name_)
+ {
+ }
+
+ ~PyModule();
+
+ bool is_option(const std::string &option_name);
+ const std::map<std::string,MgrMap::ModuleOption>& get_options() const {
+ return options;
+ }
+
+ PyObject *get_typed_option_value(
+ const std::string& option,
+ const std::string& value);
+
+ int load(PyThreadState *pMainThreadState);
+ static PyObject* init_ceph_logger();
+ static PyObject* init_ceph_module();
+
+ void set_enabled(const bool enabled_)
+ {
+ enabled = enabled_;
+ }
+
+ void set_always_on(const bool always_on_) {
+ always_on = always_on_;
+ }
+
+ /**
+ * Extend `out` with the contents of `this->commands`
+ */
+ void get_commands(std::vector<ModuleCommand> *out) const
+ {
+ std::lock_guard l(lock);
+ ceph_assert(out != nullptr);
+ out->insert(out->end(), commands.begin(), commands.end());
+ }
+
+
+ /**
+ * Mark the module as failed, recording the reason in the error
+ * string.
+ */
+ void fail(const std::string &reason)
+ {
+ std::lock_guard l(lock);
+ failed = true;
+ error_string = reason;
+ }
+
+ bool is_enabled() const {
+ std::lock_guard l(lock);
+ return enabled || always_on;
+ }
+
+ bool is_failed() const { std::lock_guard l(lock) ; return failed; }
+ bool is_loaded() const { std::lock_guard l(lock) ; return loaded; }
+ bool is_always_on() const { std::lock_guard l(lock) ; return always_on; }
+
+ bool should_notify(const std::string& notify_type) const {
+ return notify_types.count(notify_type);
+ }
+
+ const std::string &get_name() const {
+ std::lock_guard l(lock) ; return module_name;
+ }
+ const std::string &get_error_string() const {
+ std::lock_guard l(lock) ; return error_string;
+ }
+ bool get_can_run() const {
+ std::lock_guard l(lock) ; return can_run;
+ }
+};
+
+typedef std::shared_ptr<PyModule> PyModuleRef;
+
+class PyModuleConfig {
+public:
+ mutable ceph::mutex lock = ceph::make_mutex("PyModuleConfig::lock");
+ std::map<std::string, std::string> config;
+
+ PyModuleConfig();
+
+ PyModuleConfig(PyModuleConfig &mconfig);
+
+ ~PyModuleConfig();
+
+ std::pair<int, std::string> set_config(
+ MonClient *monc,
+ const std::string &module_name,
+ const std::string &key, const std::optional<std::string>& val);
+
+};