Merge pull request #51949 from mchugh19/remove_hipchat

Remove hipchat engine due to service retirement
This commit is contained in:
Gareth J. Greenaway 2019-03-05 08:03:35 -08:00 committed by Christian McHugh
parent 8ce2511010
commit 5958b7e973
3 changed files with 0 additions and 436 deletions

View File

@ -11,7 +11,6 @@ engine modules
:template: autosummary.rst.tmpl
docker_events
hipchat
http_logstash
ircbot
junos_syslog

View File

@ -1,6 +0,0 @@
salt.engines.hipchat module
===========================
.. automodule:: salt.engines.hipchat
:members:
:undoc-members:

View File

@ -1,429 +0,0 @@
# -*- coding: utf-8 -*-
'''
An engine that reads messages from Hipchat and sends them to the Salt
event bus. Alternatively Salt commands can be sent to the Salt master
via Hipchat by setting the control parameter to ``True`` and using command
prefaced with a ``!``. Only token key is required, but room and control
keys make the engine interactive.
.. versionadded: 2016.11.0
:depends: hypchat
:configuration: Example configuration
.. code-block:: yaml
engines:
- hipchat:
api_url: http://api.hipchat.myteam.com
token: 'XXXXXX'
room: 'salt'
control: True
valid_users:
- SomeUser
valid_commands:
- test.ping
- cmd.run
- list_jobs
- list_commands
aliases:
list_jobs:
cmd: jobs.list_jobs
list_commands:
cmd: pillar.get salt:engines:hipchat:valid_commands target=saltmaster
max_rooms: 0
wait_time: 1
'''
from __future__ import absolute_import, print_function, unicode_literals
import logging
import time
import os
try:
import hypchat
except ImportError:
hypchat = None
import salt.utils.args
import salt.utils.event
import salt.utils.files
import salt.utils.http
import salt.utils.json
import salt.utils.stringutils
import salt.runner
import salt.client
import salt.loader
import salt.output
from salt.ext import six
log = logging.getLogger(__name__)
_DEFAULT_API_URL = 'https://api.hipchat.com'
_DEFAULT_SLEEP = 5
_DEFAULT_MAX_ROOMS = 1000
__virtualname__ = 'hipchat'
def __virtual__():
return __virtualname__ if hypchat is not None \
else (False, 'hypchat is not installed')
def _publish_file(token, room, filepath, message='', outputter=None, api_url=None):
'''
Send file to a HipChat room via API version 2
Parameters
----------
token : str
HipChat API version 2 compatible token - must be token for active user
room: str
Name or API ID of the room to notify
filepath: str
Full path of file to be sent
message: str, optional
Message to send to room
api_url: str, optional
Hipchat API URL to use, defaults to http://api.hipchat.com
'''
if not os.path.isfile(filepath):
raise ValueError("File '{0}' does not exist".format(filepath))
if len(message) > 1000:
raise ValueError('Message too long')
url = "{0}/v2/room/{1}/share/file".format(api_url, room)
headers = {'Content-type': 'multipart/related; boundary=boundary123456'}
headers['Authorization'] = "Bearer " + token
msg = salt.utils.json.dumps({'message': message})
# future lint: disable=blacklisted-function
with salt.utils.files.fopen(filepath, 'rb') as rfh:
payload = str('''\
--boundary123456
Content-Type: application/json; charset=UTF-8
Content-Disposition: attachment; name="metadata"
{0}
--boundary123456
Content-Disposition: attachment; name="file"; filename="{1}"
{2}
--boundary123456--\
''').format(msg,
os.path.basename(salt.utils.stringutils.to_str(filepath)),
salt.utils.stringutils.to_str(rfh.read()))
# future lint: enable=blacklisted-function
salt.utils.http.query(url, method='POST', header_dict=headers, data=payload)
def _publish_html_message(token, room, data, message='', outputter='nested', api_url=None):
'''
Publishes the HTML-formatted message.
'''
url = "{0}/v2/room/{1}/notification".format(api_url, room)
headers = {
'Content-type': 'text/plain'
}
headers['Authorization'] = 'Bearer ' + token
salt.utils.http.query(
url,
'POST',
data=message,
decode=True,
status=True,
header_dict=headers,
opts=__opts__,
)
headers['Content-type'] = 'text/html'
message = salt.output.html_format(data, outputter, opts=__opts__)
salt.utils.http.query(
url,
'POST',
data=message,
decode=True,
status=True,
header_dict=headers,
opts=__opts__,
)
def _publish_code_message(token, room, data, message='', outputter='nested', api_url=None):
'''
Publishes the output format as code.
'''
url = "{0}/v2/room/{1}/notification".format(api_url, room)
headers = {
'Content-type': 'text/plain'
}
headers['Authorization'] = 'Bearer ' + token
salt.utils.http.query(
url,
'POST',
data=message,
decode=True,
status=True,
header_dict=headers,
opts=__opts__,
)
message = '/code '
message += salt.output.string_format(data, outputter, opts=__opts__)
salt.utils.http.query(
url,
'POST',
data=message,
decode=True,
status=True,
header_dict=headers,
opts=__opts__,
)
def start(token,
room='salt',
aliases=None,
valid_users=None,
valid_commands=None,
control=False,
trigger="!",
tag='salt/engines/hipchat/incoming',
api_key=None,
api_url=None,
max_rooms=None,
wait_time=None,
output_type='file',
outputter='nested'):
'''
Listen to Hipchat messages and forward them to Salt.
token
The HipChat API key. It requires a key for global usgae,
assigned per user, rather than room.
room
The HipChat room name.
aliases
Define custom aliases.
valid_users
Restrict access only to certain users.
valid_commands
Restrict the execution to a limited set of commands.
control
Send commands to the master.
trigger: ``!``
Special character that triggers the execution of salt commands.
tag: ``salt/engines/hipchat/incoming``
The event tag on the Salt bus.
api_url: ``https://api.hipchat.com``
The URL to the HipChat API.
.. versionadded:: 2017.7.0
max_rooms: ``1000``
Maximum number of rooms allowed to fetch. If set to 0,
it is able to retrieve the entire list of rooms.
wait_time: ``5``
Maximum wait time, in seconds.
output_type: ``file``
The type of the output. Choose bewteen:
- ``file``: save the output into a temporary file and upload
- ``html``: send the output as HTML
- ``code``: send the output as code
This can be overridden when executing a command, using the ``--out-type`` argument.
.. versionadded:: 2017.7.0
outputter: ``nested``
The format to display the data, using the outputters available on the CLI.
This argument can also be overridden when executing a command, using the ``--out`` option.
.. versionadded:: 2017.7.0
HipChat Example:
.. code-block:: text
! test.ping
! test.ping target=minion1
! test.ping --out=nested
! test.ping --out-type=code --out=table
'''
target_room = None
if __opts__.get('__role') == 'master':
fire_master = salt.utils.event.get_master_event(
__opts__,
__opts__['sock_dir']).fire_event
else:
fire_master = None
def fire(tag, msg):
'''
fire event to salt bus
'''
if fire_master:
fire_master(msg, tag)
else:
__salt__['event.send'](tag, msg)
def _eval_bot_mentions(all_messages, trigger):
''' yield partner message '''
for message in all_messages:
message_text = message['message']
if message_text.startswith(trigger):
fire(tag, message)
text = message_text.replace(trigger, '').strip()
yield message['from']['mention_name'], text
token = token or api_key
if not token:
raise UserWarning("Hipchat token not found")
runner_functions = sorted(salt.runner.Runner(__opts__).functions)
if not api_url:
api_url = _DEFAULT_API_URL
hipc = hypchat.HypChat(token, endpoint=api_url)
if not hipc:
raise UserWarning("Unable to connect to hipchat")
log.debug('Connected to Hipchat')
rooms_kwargs = {}
if max_rooms is None:
max_rooms = _DEFAULT_MAX_ROOMS
rooms_kwargs['max_results'] = max_rooms
elif max_rooms > 0:
rooms_kwargs['max_results'] = max_rooms
# if max_rooms is 0 => retrieve all (rooms_kwargs is empty dict)
all_rooms = hipc.rooms(**rooms_kwargs)['items']
for a_room in all_rooms:
if a_room['name'] == room:
target_room = a_room
if not target_room:
log.debug("Unable to connect to room %s", room)
# wait for a bit as to not burn through api calls
time.sleep(30)
raise UserWarning("Unable to connect to room {0}".format(room))
after_message_id = target_room.latest(maxResults=1)['items'][0]['id']
while True:
try:
new_messages = target_room.latest(
not_before=after_message_id)['items']
except hypchat.requests.HttpServiceUnavailable:
time.sleep(15)
continue
after_message_id = new_messages[-1]['id']
for partner, text in _eval_bot_mentions(new_messages[1:], trigger):
# bot summoned by partner
if not control:
log.debug("Engine not configured for control")
return
# Ensure the user is allowed to run commands
if valid_users:
if partner not in valid_users:
target_room.message('{0} not authorized to run Salt commands'.format(partner))
return
args = []
kwargs = {}
cmdline = salt.utils.args.shlex_split(text)
cmd = cmdline[0]
# Evaluate aliases
if aliases and isinstance(aliases, dict) and cmd in aliases.keys():
cmdline = aliases[cmd].get('cmd')
cmdline = salt.utils.args.shlex_split(cmdline)
cmd = cmdline[0]
# Parse args and kwargs
if len(cmdline) > 1:
for item in cmdline[1:]:
if '=' in item:
(key, value) = item.split('=', 1)
kwargs[key] = value
else:
args.append(item)
# Check for target. Otherwise assume *
if 'target' not in kwargs:
target = '*'
else:
target = kwargs['target']
del kwargs['target']
# Check for tgt_type. Otherwise assume glob
if 'tgt_type' not in kwargs:
tgt_type = 'glob'
else:
tgt_type = kwargs['tgt_type']
del kwargs['tgt_type']
# Check for outputter. Otherwise assume nested
if '--out' in kwargs:
outputter = kwargs['--out']
del kwargs['--out']
# Check for outputter. Otherwise assume nested
if '--out-type' in kwargs:
output_type = kwargs['--out-type']
del kwargs['--out-type']
# Ensure the command is allowed
if valid_commands:
if cmd not in valid_commands:
target_room.message('Using {0} is not allowed.'.format(cmd))
return
ret = {}
if cmd in runner_functions:
runner = salt.runner.RunnerClient(__opts__)
ret = runner.cmd(cmd, arg=args, kwarg=kwargs)
# Default to trying to run as a client module.
else:
local = salt.client.LocalClient()
ret = local.cmd('{0}'.format(target), cmd, args, kwargs, tgt_type='{0}'.format(tgt_type))
nice_args = (' ' + ' '.join(args)) if args else ''
nice_kwargs = (' ' + ' '.join('{0}={1}'.format(key, value) for (key, value) in six.iteritems(kwargs))) \
if kwargs else ''
message_string = '@{0} Results for: {1}{2}{3} on {4}'.format(partner,
cmd,
nice_args,
nice_kwargs,
target)
if output_type == 'html':
_publish_html_message(token, room, ret, message=message_string, outputter=outputter, api_url=api_url)
elif output_type == 'code':
_publish_code_message(token, room, ret, message=message_string, outputter=outputter, api_url=api_url)
else:
tmp_path_fn = salt.utils.files.mkstemp()
with salt.utils.files.fopen(tmp_path_fn, 'w+') as fp_:
salt.utils.json.dump(ret, fp_, sort_keys=True, indent=4)
_publish_file(token, room, tmp_path_fn, message=message_string, api_url=api_url)
salt.utils.files.safe_rm(tmp_path_fn)
time.sleep(wait_time or _DEFAULT_SLEEP)