"Fossies" - the Fresh Open Source Software Archive 
Member "salt-3002.2/salt/modules/slack_notify.py" (18 Nov 2020, 7967 Bytes) of package /linux/misc/salt-3002.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "slack_notify.py" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
3002.1_vs_3002.2.
1 """
2 Module for sending messages to Slack
3
4 .. versionadded:: 2015.5.0
5
6 :configuration: This module can be used by either passing an api key and version
7 directly or by specifying both in a configuration profile in the salt
8 master/minion config.
9
10 For example:
11
12 .. code-block:: yaml
13
14 slack:
15 api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15
16 """
17
18
19 import logging
20
21 import salt.ext.six.moves.http_client
22 import salt.utils.json
23 import salt.utils.slack
24 from salt.exceptions import SaltInvocationError
25 from salt.ext.six.moves import range
26
27 # pylint: disable=import-error,no-name-in-module,redefined-builtin
28 from salt.ext.six.moves.urllib.parse import urlencode as _urlencode
29 from salt.ext.six.moves.urllib.parse import urljoin as _urljoin
30
31 # pylint: enable=import-error,no-name-in-module
32
33 log = logging.getLogger(__name__)
34
35 __virtualname__ = "slack"
36
37
38 def __virtual__():
39 """
40 Return virtual name of the module.
41
42 :return: The virtual name of the module.
43 """
44 return __virtualname__
45
46
47 def _get_api_key():
48 api_key = __salt__["config.get"]("slack.api_key") or __salt__["config.get"](
49 "slack:api_key"
50 )
51
52 if not api_key:
53 raise SaltInvocationError("No Slack API key found.")
54
55 return api_key
56
57
58 def _get_hook_id():
59 url = __salt__["config.get"]("slack.hook") or __salt__["config.get"]("slack:hook")
60 if not url:
61 raise SaltInvocationError("No Slack WebHook url found")
62
63 return url
64
65
66 def list_rooms(api_key=None):
67 """
68 List all Slack rooms.
69
70 :param api_key: The Slack admin api key.
71 :return: The room list.
72
73 CLI Example:
74
75 .. code-block:: bash
76
77 salt '*' slack.list_rooms
78
79 salt '*' slack.list_rooms api_key=peWcBiMOS9HrZG15peWcBiMOS9HrZG15
80 """
81 if not api_key:
82 api_key = _get_api_key()
83 return salt.utils.slack.query(function="rooms", api_key=api_key, opts=__opts__)
84
85
86 def list_users(api_key=None):
87 """
88 List all Slack users.
89
90 :param api_key: The Slack admin api key.
91 :return: The user list.
92
93 CLI Example:
94
95 .. code-block:: bash
96
97 salt '*' slack.list_users
98
99 salt '*' slack.list_users api_key=peWcBiMOS9HrZG15peWcBiMOS9HrZG15
100 """
101 if not api_key:
102 api_key = _get_api_key()
103 return salt.utils.slack.query(function="users", api_key=api_key, opts=__opts__)
104
105
106 def find_room(name, api_key=None):
107 """
108 Find a room by name and return it.
109
110 :param name: The room name.
111 :param api_key: The Slack admin api key.
112 :return: The room object.
113
114 CLI Example:
115
116 .. code-block:: bash
117
118 salt '*' slack.find_room name="random"
119
120 salt '*' slack.find_room name="random" api_key=peWcBiMOS9HrZG15peWcBiMOS9HrZG15
121 """
122 if not api_key:
123 api_key = _get_api_key()
124
125 # search results don't include the name of the
126 # channel with a hash, if the passed channel name
127 # has a hash we remove it.
128 if name.startswith("#"):
129 name = name[1:]
130 ret = list_rooms(api_key)
131 if ret["res"]:
132 rooms = ret["message"]
133 if rooms:
134 for room in range(0, len(rooms)):
135 if rooms[room]["name"] == name:
136 return rooms[room]
137 return False
138
139
140 def find_user(name, api_key=None):
141 """
142 Find a user by name and return it.
143
144 :param name: The user name.
145 :param api_key: The Slack admin api key.
146 :return: The user object.
147
148 CLI Example:
149
150 .. code-block:: bash
151
152 salt '*' slack.find_user name="ThomasHatch"
153
154 salt '*' slack.find_user name="ThomasHatch" api_key=peWcBiMOS9HrZG15peWcBiMOS9HrZG15
155 """
156 if not api_key:
157 api_key = _get_api_key()
158
159 ret = list_users(api_key)
160 if ret["res"]:
161 users = ret["message"]
162 if users:
163 for user in range(0, len(users)):
164 if users[user]["name"] == name:
165 return users[user]
166 return False
167
168
169 def post_message(channel, message, from_name, api_key=None, icon=None):
170 """
171 Send a message to a Slack channel.
172
173 :param channel: The channel name, either will work.
174 :param message: The message to send to the Slack channel.
175 :param from_name: Specify who the message is from.
176 :param api_key: The Slack api key, if not specified in the configuration.
177 :param icon: URL to an image to use as the icon for this message
178 :return: Boolean if message was sent successfully.
179
180 CLI Example:
181
182 .. code-block:: bash
183
184 salt '*' slack.post_message channel="Development Room" message="Build is done" from_name="Build Server"
185
186 """
187 if not api_key:
188 api_key = _get_api_key()
189
190 if not channel:
191 log.error("channel is a required option.")
192
193 # channel must start with a hash or an @ (direct-message channels)
194 if not channel.startswith("#") and not channel.startswith("@"):
195 log.warning(
196 "Channel name must start with a hash or @. "
197 'Prepending a hash and using "#%s" as '
198 "channel name instead of %s",
199 channel,
200 channel,
201 )
202 channel = "#{}".format(channel)
203
204 if not from_name:
205 log.error("from_name is a required option.")
206
207 if not message:
208 log.error("message is a required option.")
209
210 if not from_name:
211 log.error("from_name is a required option.")
212
213 parameters = {"channel": channel, "username": from_name, "text": message}
214
215 if icon is not None:
216 parameters["icon_url"] = icon
217
218 # Slack wants the body on POST to be urlencoded.
219 result = salt.utils.slack.query(
220 function="message",
221 api_key=api_key,
222 method="POST",
223 header_dict={"Content-Type": "application/x-www-form-urlencoded"},
224 data=_urlencode(parameters),
225 opts=__opts__,
226 )
227
228 if result["res"]:
229 return True
230 else:
231 return result
232
233
234 def call_hook(
235 message,
236 attachment=None,
237 color="good",
238 short=False,
239 identifier=None,
240 channel=None,
241 username=None,
242 icon_emoji=None,
243 ):
244 """
245 Send message to Slack incoming webhook.
246
247 :param message: The topic of message.
248 :param attachment: The message to send to the Slack WebHook.
249 :param color: The color of border of left side
250 :param short: An optional flag indicating whether the value is short
251 enough to be displayed side-by-side with other values.
252 :param identifier: The identifier of WebHook.
253 :param channel: The channel to use instead of the WebHook default.
254 :param username: Username to use instead of WebHook default.
255 :param icon_emoji: Icon to use instead of WebHook default.
256 :return: Boolean if message was sent successfully.
257
258 CLI Example:
259
260 .. code-block:: bash
261
262 salt '*' slack.call_hook message='Hello, from SaltStack'
263
264 """
265 base_url = "https://hooks.slack.com/services/"
266 if not identifier:
267 identifier = _get_hook_id()
268
269 url = _urljoin(base_url, identifier)
270
271 if not message:
272 log.error("message is required option")
273
274 if attachment:
275 payload = {
276 "attachments": [
277 {
278 "fallback": message,
279 "color": color,
280 "pretext": message,
281 "fields": [{"value": attachment, "short": short}],
282 }
283 ]
284 }
285 else:
286 payload = {
287 "text": message,
288 }
289
290 if channel:
291 payload["channel"] = channel
292
293 if username:
294 payload["username"] = username
295
296 if icon_emoji:
297 payload["icon_emoji"] = icon_emoji
298
299 data = _urlencode({"payload": salt.utils.json.dumps(payload)})
300 result = salt.utils.http.query(url, method="POST", data=data, status=True)
301
302 if result["status"] <= 201:
303 return True
304 else:
305 return {"res": False, "message": result.get("body", result["status"])}