如何解决无法在 Saltstack 中加载自定义返回器
我正在尝试为 custom returner
中的 custom modules
编写 sqlite3
之类的 Saltstack
。我在 _returners
内创建了一个 /srv/salt/base/
文件夹,在该文件夹内,我创建了名为 my_returner.py
的返回者。
当我尝试使用以下命令 ping 时,它在 salt-master 中显示 requested returner my_returner could not be loaded
错误。
salt * test.ping --return my_returner
错误:
2020-12-29 10:56:16,993 [salt.master :2405][ERROR ][89595] Failed to allocate a jid. The requested returner 'my_returner' could not be loaded.
2020-12-29 10:56:16,996 [salt.transport.zeromq :876 ][ERROR ][89595] Some exception handling a payload from minion
Traceback (most recent call last):
File "/home/sarosh/VIRT3/lib/python3.8/site-packages/salt/transport/zeromq.py",line 872,in handle_message
ret,req_opts = yield self.payload_handler(payload)
File "/home/sarosh/VIRT3/lib/python3.8/site-packages/salt/ext/tornado/gen.py",line 1056,in run
value = future.result()
File "/home/sarosh/VIRT3/lib/python3.8/site-packages/salt/ext/tornado/concurrent.py",line 249,in result
raise_exc_info(self._exc_info)
File "<string>",line 4,in raise_exc_info
File "/home/sarosh/VIRT3/lib/python3.8/site-packages/salt/ext/tornado/gen.py",line 294,in wrapper
result = func(*args,**kwargs)
File "/usr/lib/python3.8/types.py",line 278,in wrapped
coro = func(*args,**kwargs)
File "/home/sarosh/VIRT3/lib/python3.8/site-packages/salt/master.py",line 1132,in _handle_payload
ret = {"aes": self._handle_aes,"clear": self._handle_clear}[key](load)
File "/home/sarosh/VIRT3/lib/python3.8/site-packages/salt/master.py",line 1173,in _handle_clear
ret = method(load),{"fun": "send_clear"}
File "/home/sarosh/VIRT3/lib/python3.8/site-packages/salt/master.py",line 2356,in publish
payload = self._prep_pub(minions,jid,clear_load,extra,missing)
File "/home/sarosh/VIRT3/lib/python3.8/site-packages/salt/master.py",line 2444,in _prep_pub
self.event.fire_event({"minions": minions},clear_load["jid"])
File "/home/sarosh/VIRT3/lib/python3.8/site-packages/salt/utils/event.py",line 755,in fire_event
salt.utils.stringutils.to_bytes(tag),File "/home/sarosh/VIRT3/lib/python3.8/site-packages/salt/utils/stringutils.py",line 62,in to_bytes
raise TypeError("expected str,bytes,or bytearray not {}".format(type(s)))
TypeError: expected str,or bytearray not <class 'dict'>
2020-12-29 10:56:17,008 [tornado.general :473 ][ERROR ][89595] Uncaught exception in zmqstream callback
请任何人帮助我解决这个问题。请让我知道我们是否可以在 Saltstack 中编写像自定义模块一样的自定义返回器。
请在下面找到主配置、返回者和版本信息的详细信息。 提前致谢。
Setup:
master config file configuration:
file_roots:
base:
/root/srv/salt/
sqlite3.database: /root/salt.db
sqlite3.timeout: 5.0
master_job_cache: my_returner
minion configuration file
master: localhost
Steps to Reproduce the behavior
1) define the configuration file as given above.
2) define returner in /root/srv/salt/_returners/my_returner.py
my returner is a copy of sqlite3 returner.
Salt Version:
Salt: 3002.2
Dependency Versions:
cffi: Not Installed
cherrypy: Not Installed
dateutil: Not Installed
docker-py: Not Installed
gitdb: Not Installed
gitpython: Not Installed
Jinja2: 2.11.2
libgit2: Not Installed
M2Crypto: Not Installed
Mako: Not Installed
msgpack: 1.0.1
msgpack-pure: Not Installed
mysql-python: Not Installed
pycparser: Not Installed
pycrypto: Not Installed
pycryptodome: 3.9.9
pygit2: Not Installed
Python: 3.8.5 (default,Jul 28 2020,12:59:40)
python-gnupg: Not Installed
PyYAML: 5.3.1
PyZMQ: 20.0.0
smmap: Not Installed
timelib: Not Installed
Tornado: 4.5.3
ZMQ: 4.3.3
System Versions:
dist: ubuntu 20.04 focal
locale: utf-8
machine: x86_64
release: 5.4.0-56-generic
system: Linux
version: Ubuntu 20.04 focal
返回代码:
import datetime
# Import python libs
import logging
import salt.returners
# Import Salt libs
import salt.utils.jid
import salt.utils.json
# Import 3rd-party libs
from salt.ext import six
# Better safe than sorry here. Even though sqlite3 is included in python
try:
import sqlite3
HAS_SQLITE3 = True
except ImportError:
HAS_SQLITE3 = False
log = logging.getLogger(__name__)
# Define the module's virtual name
__virtualname__ = "test2"
def __virtual__():
if not HAS_SQLITE3:
return False,"Could not import sqlite3 returner; sqlite3 is not installed."
return __virtualname__
def _get_options(ret=None):
"""
Get the SQLite3 options from salt.
"""
attrs = {"database": "database","timeout": "timeout"}
_options = salt.returners.get_returner_options(
__virtualname__,ret,attrs,__salt__=__salt__,__opts__=__opts__
)
log.debug("dev>>>>>>>>>>>>>>>>>>>>>>>>>>")
return _options
def _get_conn(ret=None):
"""
Return a sqlite3 database connection
"""
# Possible todo: support detect_types,isolation_level,check_same_thread,# factory,cached_statements. Do we really need to though?
_options = _get_options(ret)
database = _options.get("database")
timeout = _options.get("timeout")
if not database:
raise Exception('sqlite3 config option "sqlite3.database" is missing')
if not timeout:
raise Exception('sqlite3 config option "sqlite3.timeout" is missing')
log.debug("Connecting the sqlite3 database: %s timeout: %s",database,timeout)
conn = sqlite3.connect(database,timeout=float(timeout))
return conn
def _close_conn(conn):
"""
Close the sqlite3 database connection
"""
log.debug("Closing the sqlite3 database connection")
conn.commit()
conn.close()
def returner(ret):
"""
Insert minion return data into the sqlite3 database
"""
log.debug("sqlite3 returner <returner> called with data: %s",ret)
log.debug("this is the point of focus")
conn = _get_conn(ret)
cur = conn.cursor()
sql = """INSERT INTO salt_returns
(fun,id,fun_args,date,full_ret,success)
VALUES (:fun,:jid,:id,:fun_args,:date,:full_ret,:success)"""
cur.execute(
sql,{
"fun": ret["fun"],"jid": ret["jid"],"id": ret["id"],"fun_args": six.text_type(ret["fun_args"]) if ret.get("fun_args") else None,"date": six.text_type(datetime.datetime.now()),"full_ret": salt.utils.json.dumps(ret["return"]),"success": ret.get("success",""),},)
_close_conn(conn)
def save_load(jid,load,minions=None):
"""
Save the load to the specified jid
"""
log.debug("sqlite3 returner <save_load> called jid: %s load: %s",load)
conn = _get_conn(ret=None)
cur = conn.cursor()
sql = """INSERT INTO jids (jid,load) VALUES (:jid,:load)"""
cur.execute(sql,{"jid": jid,"load": salt.utils.json.dumps(load)})
_close_conn(conn)
def save_minions(jid,minions,syndic_id=None): # pylint: disable=unused-argument
"""
Included for API consistency
"""
def get_load(jid):
"""
Return the load from a specified jid
"""
log.debug("sqlite3 returner <get_load> called jid: %s",jid)
conn = _get_conn(ret=None)
cur = conn.cursor()
sql = """SELECT load FROM jids WHERE jid = :jid"""
cur.execute(sql,{"jid": jid})
data = cur.fetchone()
if data:
return salt.utils.json.loads(data[0].encode())
_close_conn(conn)
return {}
def get_jid(jid):
"""
Return the information returned from a specified jid
"""
log.debug("sqlite3 returner <get_jid> called jid: %s",jid)
conn = _get_conn(ret=None)
cur = conn.cursor()
sql = """SELECT id,full_ret FROM salt_returns WHERE jid = :jid"""
cur.execute(sql,{"jid": jid})
data = cur.fetchone()
log.debug("query result: %s",data)
ret = {}
if data and len(data) > 1:
ret = {six.text_type(data[0]): {"return": salt.utils.json.loads(data[1])}}
log.debug("ret: %s",ret)
_close_conn(conn)
return ret
def get_fun(fun):
"""
Return a dict of the last function called for all minions
"""
log.debug("sqlite3 returner <get_fun> called fun: %s",fun)
conn = _get_conn(ret=None)
cur = conn.cursor()
sql = """SELECT s.id,s.full_ret,s.jid
FROM salt_returns s
JOIN ( SELECT MAX(jid) AS jid FROM salt_returns GROUP BY fun,id) max
ON s.jid = max.jid
WHERE s.fun = :fun
"""
cur.execute(sql,{"fun": fun})
data = cur.fetchall()
ret = {}
if data:
# Pop the jid off the list since it is not
# needed and I am trying to get a perfect
# pylint score :-)
data.pop()
for minion,ret in data:
ret[minion] = salt.utils.json.loads(ret)
_close_conn(conn)
return ret
def get_jids():
"""
Return a list of all job ids
"""
log.debug("sqlite3 returner <get_jids> called")
conn = _get_conn(ret=None)
cur = conn.cursor()
sql = """SELECT jid,load FROM jids"""
cur.execute(sql)
data = cur.fetchall()
ret = {}
for jid,load in data:
ret[jid] = salt.utils.jid.format_jid_instance(jid,salt.utils.json.loads(load))
_close_conn(conn)
return ret
def get_minions():
"""
Return a list of minions
"""
log.debug("sqlite3 returner <get_minions> called")
conn = _get_conn(ret=None)
cur = conn.cursor()
sql = """SELECT DISTINCT id FROM salt_returns"""
cur.execute(sql)
data = cur.fetchall()
ret = []
for minion in data:
ret.append(minion[0])
_close_conn(conn)
return ret
def prep_jid(nocache=False,passed_jid=None): # pylint: disable=unused-argument
"""
Do any work necessary to prepare a JID,including sending a custom id
"""
return passed_jid if passed_jid is not None else salt.utils.jid.gen_jid(__opts__)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。