-
Notifications
You must be signed in to change notification settings - Fork 4
/
st2.py
150 lines (123 loc) · 5.57 KB
/
st2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# coding:utf-8
import logging
import threading
from errbot import BotPlugin, re_botcmd, botcmd, arg_botcmd, webhook
from lib.st2pluginapi import St2PluginAPI
from lib.st2adapters import ChatAdapterFactory
LOG = logging.getLogger(__name__)
# A plugin prefix for stackstorm action aliases to avoid name collisions between
# them and native errbot plugins. Defined here so it's available to errbot's facade decorator.
PLUGIN_PREFIX = r"st2"
class St2Config(object):
def __init__(self, bot_conf):
self._configure_prefixes(bot_conf)
self._configure_stackstorm(bot_conf)
self.timer_update = bot_conf.STACKSTORM.get('timer_update', 60)
self.verify_cert = bot_conf.STACKSTORM.get('verify_cert', True)
def _configure_prefixes(self, bot_conf):
self.bot_prefix = bot_conf.BOT_PREFIX
self.plugin_prefix = PLUGIN_PREFIX
self.full_prefix = "{}{} ".format(bot_conf.BOT_PREFIX, self.plugin_prefix)
def _configure_stackstorm(self, bot_conf):
self.api_auth = bot_conf.STACKSTORM.get('api_auth', {})
self.api_url = bot_conf.STACKSTORM.get('api_url', 'http://localhost:9101/v1')
self.auth_url = bot_conf.STACKSTORM.get('auth_url', 'http://localhost:9100/v1')
self.stream_url = bot_conf.STACKSTORM.get('stream_url', 'http://localhost:9102/v1')
class St2(BotPlugin):
"""
Stackstorm plugin for authentication and Action Alias execution.
Try !st2help for action alias help.
"""
def __init__(self, bot, name):
super(St2, self).__init__(bot, name)
self.st2config = St2Config(self.bot_config)
self.st2api = St2PluginAPI(self.st2config)
# The chat backend adapter mediates data format and api calls between
# stackstorm, errbot and the chat backend.
self.chatbackend = {
"slack": ChatAdapterFactory.slack_adapter
}.get(self._bot.mode, ChatAdapterFactory.generic_adapter)(self)
# Run the stream listener loop in a separate thread.
if not self.st2api.validate_credentials():
LOG.critical("Invalid credentials when communicating with StackStorm API.")
th1 = threading.Thread(
target=self.st2api.st2stream_listener,
args=[self.chatbackend.post_message]
)
th1.setDaemon(True)
th1.start()
def activate(self):
"""
Activate Errbot's poller to validate credentials periodically. For user/password auth.
"""
super(St2, self).activate()
LOG.info("Poller activated")
self.start_poller(self.st2config.timer_update, self.st2api.validate_credentials)
@re_botcmd(pattern='^{} .*'.format(PLUGIN_PREFIX))
def st2_execute_actionalias(self, msg, match):
"""
Run an arbitrary stackstorm command.
Available commands can be listed using !st2help
"""
def remove_bot_prefix(msg):
"""
Drop plugin prefix and any trailing white space from user supplied st2 command.
"""
return msg.replace(self.st2config.plugin_prefix, "", 1).strip()
msg.body = remove_bot_prefix(match.group())
msg_debug = ""
for attr, value in msg.__dict__.items():
msg_debug += "\t\t{} [{}] {}\n".format(attr, type(value), value)
LOG.debug("Message received from chat backend.\n{}\n".format(msg_debug))
matched_result = self.st2api.match(msg.body)
if matched_result is not None:
action_alias, representation = matched_result
del matched_result
if action_alias.enabled is True:
res = self.st2api.execute_actionalias(
action_alias,
representation,
msg,
self.chatbackend
)
LOG.debug('action alias execution result: type={} {}'.format(type(res), res))
result = r"{}".format(res)
else:
result = "st2 command '{}' is disabled.".format(msg.body)
else:
result = "st2 command '{}' not found. View available commands with {}st2help."
result = result.format(msg.body, self.st2config.bot_prefix)
return result
@arg_botcmd("--pack", dest="pack", type=str)
@arg_botcmd("--filter", dest="filter", type=str)
@arg_botcmd("--limit", dest="limit", type=int)
@arg_botcmd("--offset", dest="offset", type=int)
def st2help(self, msg, pack=None, filter=None, limit=None, offset=None):
"""
Provide help for StackStorm action aliases.
"""
help_result = self.st2api.actionalias_help(pack, filter, limit, offset)
if isinstance(help_result, list) and len(help_result) == 0:
return "No help found for the search."
else:
return self.chatbackend.format_help(help_result)
@webhook('/chatops/message')
def chatops_message(self, request):
"""
Webhook entry point for stackstorm to post messages into
errbot which will relay them into the chat backend.
"""
LOG.debug("Webhook request: {}".format(request))
channel = request.get('channel')
message = request.get('message')
user = request.get('user')
whisper = request.get('whisper')
extra = request.get('extra', {})
self.chatbackend.post_message(whisper, message, user, channel, extra)
return "Delivered to chat backend."
@webhook('/login/challenge/<uuid>')
def login_uuid(self, request, uuid):
return None
@webhook('/login/authenticate/<uuid>')
def login_auth(self, request, uuid):
return None