1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-04-06 12:07:14 +00:00

Initial commit

This commit is contained in:
Ansible Core Team 2020-03-09 09:11:07 +00:00
commit aebc1b03fd
4861 changed files with 812621 additions and 0 deletions

View file

@ -0,0 +1,181 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2016, Jiangge Zhang <tonyseek@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}
DOCUMENTATION = '''
module: bearychat
short_description: Send BearyChat notifications
description:
- The M(bearychat) module sends notifications to U(https://bearychat.com)
via the Incoming Robot integration.
author: "Jiangge Zhang (@tonyseek)"
options:
url:
description:
- BearyChat WebHook URL. This authenticates you to the bearychat
service. It looks like
C(https://hook.bearychat.com/=ae2CF/incoming/e61bd5c57b164e04b11ac02e66f47f60).
required: true
text:
description:
- Message to send.
markdown:
description:
- If C(yes), text will be parsed as markdown.
default: 'yes'
type: bool
channel:
description:
- Channel to send the message to. If absent, the message goes to the
default channel selected by the I(url).
attachments:
description:
- Define a list of attachments. For more information, see
https://github.com/bearyinnovative/bearychat-tutorial/blob/master/robots/incoming.md#attachments
'''
EXAMPLES = """
- name: Send notification message via BearyChat
local_action:
module: bearychat
url: |
https://hook.bearychat.com/=ae2CF/incoming/e61bd5c57b164e04b11ac02e66f47f60
text: "{{ inventory_hostname }} completed"
- name: Send notification message via BearyChat all options
local_action:
module: bearychat
url: |
https://hook.bearychat.com/=ae2CF/incoming/e61bd5c57b164e04b11ac02e66f47f60
text: "{{ inventory_hostname }} completed"
markdown: no
channel: "#ansible"
attachments:
- title: "Ansible on {{ inventory_hostname }}"
text: "May the Force be with you."
color: "#ffffff"
images:
- http://example.com/index.png
"""
RETURN = """
msg:
description: execution result
returned: success
type: str
sample: "OK"
"""
try:
from ansible.module_utils.six.moves.urllib.parse import urlparse, urlunparse
HAS_URLPARSE = True
except Exception:
HAS_URLPARSE = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
def build_payload_for_bearychat(module, text, markdown, channel, attachments):
payload = {}
if text is not None:
payload['text'] = text
if markdown is not None:
payload['markdown'] = markdown
if channel is not None:
payload['channel'] = channel
if attachments is not None:
payload.setdefault('attachments', []).extend(
build_payload_for_bearychat_attachment(
module, item.get('title'), item.get('text'), item.get('color'),
item.get('images'))
for item in attachments)
payload = 'payload=%s' % module.jsonify(payload)
return payload
def build_payload_for_bearychat_attachment(module, title, text, color, images):
attachment = {}
if title is not None:
attachment['title'] = title
if text is not None:
attachment['text'] = text
if color is not None:
attachment['color'] = color
if images is not None:
target_images = attachment.setdefault('images', [])
if not isinstance(images, (list, tuple)):
images = [images]
for image in images:
if isinstance(image, dict) and 'url' in image:
image = {'url': image['url']}
elif hasattr(image, 'startswith') and image.startswith('http'):
image = {'url': image}
else:
module.fail_json(
msg="BearyChat doesn't have support for this kind of "
"attachment image")
target_images.append(image)
return attachment
def do_notify_bearychat(module, url, payload):
response, info = fetch_url(module, url, data=payload)
if info['status'] != 200:
url_info = urlparse(url)
obscured_incoming_webhook = urlunparse(
(url_info.scheme, url_info.netloc, '[obscured]', '', '', ''))
module.fail_json(
msg=" failed to send %s to %s: %s" % (
payload, obscured_incoming_webhook, info['msg']))
def main():
module = AnsibleModule(argument_spec={
'url': dict(type='str', required=True, no_log=True),
'text': dict(type='str'),
'markdown': dict(default='yes', type='bool'),
'channel': dict(type='str'),
'attachments': dict(type='list'),
})
if not HAS_URLPARSE:
module.fail_json(msg='urlparse is not installed')
url = module.params['url']
text = module.params['text']
markdown = module.params['markdown']
channel = module.params['channel']
attachments = module.params['attachments']
payload = build_payload_for_bearychat(
module, text, markdown, channel, attachments)
do_notify_bearychat(module, url, payload)
module.exit_json(msg="OK")
if __name__ == '__main__':
main()

View file

@ -0,0 +1,152 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: campfire
short_description: Send a message to Campfire
description:
- Send a message to Campfire.
- Messages with newlines will result in a "Paste" message being sent.
options:
subscription:
description:
- The subscription name to use.
required: true
token:
description:
- API token.
required: true
room:
description:
- Room number to which the message should be sent.
required: true
msg:
description:
- The message body.
required: true
notify:
description:
- Send a notification sound before the message.
required: false
choices: ["56k", "bell", "bezos", "bueller", "clowntown",
"cottoneyejoe", "crickets", "dadgummit", "dangerzone",
"danielsan", "deeper", "drama", "greatjob", "greyjoy",
"guarantee", "heygirl", "horn", "horror",
"inconceivable", "live", "loggins", "makeitso", "noooo",
"nyan", "ohmy", "ohyeah", "pushit", "rimshot",
"rollout", "rumble", "sax", "secret", "sexyback",
"story", "tada", "tmyk", "trololo", "trombone", "unix",
"vuvuzela", "what", "whoomp", "yeah", "yodel"]
# informational: requirements for nodes
requirements: [ ]
author: "Adam Garside (@fabulops)"
'''
EXAMPLES = '''
- campfire:
subscription: foo
token: 12345
room: 123
msg: Task completed.
- campfire:
subscription: foo
token: 12345
room: 123
notify: loggins
msg: Task completed ... with feeling.
'''
try:
from html import escape as html_escape
except ImportError:
# Python-3.2 or later
import cgi
def html_escape(text, quote=True):
return cgi.escape(text, quote)
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
def main():
module = AnsibleModule(
argument_spec=dict(
subscription=dict(required=True),
token=dict(required=True, no_log=True),
room=dict(required=True),
msg=dict(required=True),
notify=dict(required=False,
choices=["56k", "bell", "bezos", "bueller",
"clowntown", "cottoneyejoe",
"crickets", "dadgummit", "dangerzone",
"danielsan", "deeper", "drama",
"greatjob", "greyjoy", "guarantee",
"heygirl", "horn", "horror",
"inconceivable", "live", "loggins",
"makeitso", "noooo", "nyan", "ohmy",
"ohyeah", "pushit", "rimshot",
"rollout", "rumble", "sax", "secret",
"sexyback", "story", "tada", "tmyk",
"trololo", "trombone", "unix",
"vuvuzela", "what", "whoomp", "yeah",
"yodel"]),
),
supports_check_mode=False
)
subscription = module.params["subscription"]
token = module.params["token"]
room = module.params["room"]
msg = module.params["msg"]
notify = module.params["notify"]
URI = "https://%s.campfirenow.com" % subscription
NSTR = "<message><type>SoundMessage</type><body>%s</body></message>"
MSTR = "<message><body>%s</body></message>"
AGENT = "Ansible/1.2"
# Hack to add basic auth username and password the way fetch_url expects
module.params['url_username'] = token
module.params['url_password'] = 'X'
target_url = '%s/room/%s/speak.xml' % (URI, room)
headers = {'Content-Type': 'application/xml',
'User-agent': AGENT}
# Send some audible notification if requested
if notify:
response, info = fetch_url(module, target_url, data=NSTR % html_escape(notify), headers=headers)
if info['status'] not in [200, 201]:
module.fail_json(msg="unable to send msg: '%s', campfire api"
" returned error code: '%s'" %
(notify, info['status']))
# Send the message
response, info = fetch_url(module, target_url, data=MSTR % html_escape(msg), headers=headers)
if info['status'] not in [200, 201]:
module.fail_json(msg="unable to send msg: '%s', campfire api"
" returned error code: '%s'" %
(msg, info['status']))
module.exit_json(changed=True, room=room, msg=msg, notify=notify)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,151 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2016, Jonathan Mainguy <jon@soh.re>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# basis of code taken from the ansible twillio and nexmo modules
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: catapult
short_description: Send a sms / mms using the catapult bandwidth api
description:
- Allows notifications to be sent using sms / mms via the catapult bandwidth api.
options:
src:
description:
- One of your catapult telephone numbers the message should come from (must be in E.164 format, like C(+19195551212)).
required: true
dest:
description:
- The phone number or numbers the message should be sent to (must be in E.164 format, like C(+19195551212)).
required: true
msg:
description:
- The contents of the text message (must be 2048 characters or less).
required: true
media:
description:
- For MMS messages, a media url to the location of the media to be sent with the message.
user_id:
description:
- User Id from Api account page.
required: true
api_token:
description:
- Api Token from Api account page.
required: true
api_secret:
description:
- Api Secret from Api account page.
required: true
author: "Jonathan Mainguy (@Jmainguy)"
notes:
- Will return changed even if the media url is wrong.
- Will return changed if the destination number is invalid.
'''
EXAMPLES = '''
- name: Send a mms to multiple users
catapult:
src: "+15035555555"
dest:
- "+12525089000"
- "+12018994225"
media: "http://example.com/foobar.jpg"
msg: "Task is complete"
user_id: "{{ user_id }}"
api_token: "{{ api_token }}"
api_secret: "{{ api_secret }}"
- name: Send a sms to a single user
catapult:
src: "+15035555555"
dest: "+12018994225"
msg: "Consider yourself notified"
user_id: "{{ user_id }}"
api_token: "{{ api_token }}"
api_secret: "{{ api_secret }}"
'''
RETURN = '''
changed:
description: Whether the api accepted the message.
returned: always
type: bool
sample: True
'''
import json
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
def send(module, src, dest, msg, media, user_id, api_token, api_secret):
"""
Send the message
"""
AGENT = "Ansible"
URI = "https://api.catapult.inetwork.com/v1/users/%s/messages" % user_id
data = {'from': src, 'to': dest, 'text': msg}
if media:
data['media'] = media
headers = {'User-Agent': AGENT, 'Content-type': 'application/json'}
# Hack module params to have the Basic auth params that fetch_url expects
module.params['url_username'] = api_token.replace('\n', '')
module.params['url_password'] = api_secret.replace('\n', '')
return fetch_url(module, URI, data=json.dumps(data), headers=headers, method="post")
def main():
module = AnsibleModule(
argument_spec=dict(
src=dict(required=True),
dest=dict(required=True, type='list'),
msg=dict(required=True),
user_id=dict(required=True),
api_token=dict(required=True, no_log=True),
api_secret=dict(required=True, no_log=True),
media=dict(default=None, required=False),
),
)
src = module.params['src']
dest = module.params['dest']
msg = module.params['msg']
media = module.params['media']
user_id = module.params['user_id']
api_token = module.params['api_token']
api_secret = module.params['api_secret']
for number in dest:
rc, info = send(module, src, number, msg, media, user_id, api_token, api_secret)
if info["status"] != 201:
body = json.loads(info["body"])
fail_msg = body["message"]
module.fail_json(msg=fail_msg)
changed = True
module.exit_json(changed=changed)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,191 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: cisco_spark
short_description: Send a message to a Cisco Spark Room or Individual.
description:
- Send a message to a Cisco Spark Room or Individual with options to control the formatting.
author: Drew Rusell (@drew-russell)
notes:
- The C(recipient_id) type must be valid for the supplied C(recipient_id).
- Full API documentation can be found at U(https://developer.ciscospark.com/endpoint-messages-post.html).
options:
recipient_type:
description:
- The request parameter you would like to send the message to.
- Messages can be sent to either a room or individual (by ID or E-Mail).
required: True
choices: ['roomId', 'toPersonEmail', 'toPersonId']
recipient_id:
description:
- The unique identifier associated with the supplied C(recipient_type).
required: true
message_type:
description:
- Specifies how you would like the message formatted.
required: False
default: text
choices: ['text', 'markdown']
personal_token:
description:
- Your personal access token required to validate the Spark API.
required: true
aliases: ['token']
message:
description:
- The message you would like to send.
required: True
'''
EXAMPLES = """
# Note: The following examples assume a variable file has been imported
# that contains the appropriate information.
- name: Cisco Spark - Markdown Message to a Room
cisco_spark:
recipient_type: roomId
recipient_id: "{{ room_id }}"
message_type: markdown
personal_token: "{{ token }}"
message: "**Cisco Spark Ansible Module - Room Message in Markdown**"
- name: Cisco Spark - Text Message to a Room
cisco_spark:
recipient_type: roomId
recipient_id: "{{ room_id }}"
message_type: text
personal_token: "{{ token }}"
message: "Cisco Spark Ansible Module - Room Message in Text"
- name: Cisco Spark - Text Message by an Individuals ID
cisco_spark:
recipient_type: toPersonId
recipient_id: "{{ person_id}}"
message_type: text
personal_token: "{{ token }}"
message: "Cisco Spark Ansible Module - Text Message to Individual by ID"
- name: Cisco Spark - Text Message by an Individuals E-Mail Address
cisco_spark:
recipient_type: toPersonEmail
recipient_id: "{{ person_email }}"
message_type: text
personal_token: "{{ token }}"
message: "Cisco Spark Ansible Module - Text Message to Individual by E-Mail"
"""
RETURN = """
status_code:
description:
- The Response Code returned by the Spark API.
- Full Response Code explanations can be found at U(https://developer.ciscospark.com/endpoint-messages-post.html).
returned: always
type: int
sample: 200
message:
description:
- The Response Message returned by the Spark API.
- Full Response Code explanations can be found at U(https://developer.ciscospark.com/endpoint-messages-post.html).
returned: always
type: str
sample: OK (585 bytes)
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
def spark_message(module):
""" When check mode is specified, establish a read only connection, that does not return any user specific
data, to validate connectivity. In regular mode, send a message to a Cisco Spark Room or Individual"""
# Ansible Specific Variables
results = {}
ansible = module.params
headers = {
'Authorization': 'Bearer {0}'.format(ansible['personal_token']),
'content-type': 'application/json'
}
if module.check_mode:
url = "https://api.ciscospark.com/v1/people/me"
payload = None
else:
url = "https://api.ciscospark.com/v1/messages"
payload = {
ansible['recipient_type']: ansible['recipient_id'],
ansible['message_type']: ansible['message']
}
payload = module.jsonify(payload)
response, info = fetch_url(module, url, data=payload, headers=headers)
status_code = info['status']
message = info['msg']
# Module will fail if the response is not 200
if status_code != 200:
results['failed'] = True
results['status_code'] = status_code
results['message'] = message
else:
results['failed'] = False
results['status_code'] = status_code
if module.check_mode:
results['message'] = 'Authentication Successful.'
else:
results['message'] = message
return results
def main():
'''Ansible main. '''
module = AnsibleModule(
argument_spec=dict(
recipient_type=dict(required=True, choices=[
'roomId', 'toPersonEmail', 'toPersonId']),
recipient_id=dict(required=True, no_log=True),
message_type=dict(required=False, default=['text'], aliases=[
'type'], choices=['text', 'markdown']),
personal_token=dict(required=True, no_log=True, aliases=['token']),
message=dict(required=True)
),
supports_check_mode=True
)
results = spark_message(module)
module.exit_json(**results)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,188 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2013 Matt Coddington <coddington@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: flowdock
author: "Matt Coddington (@mcodd)"
short_description: Send a message to a flowdock
description:
- Send a message to a flowdock team inbox or chat using the push API (see https://www.flowdock.com/api/team-inbox and https://www.flowdock.com/api/chat)
options:
token:
description:
- API token.
required: true
type:
description:
- Whether to post to 'inbox' or 'chat'
required: true
choices: [ "inbox", "chat" ]
msg:
description:
- Content of the message
required: true
tags:
description:
- tags of the message, separated by commas
required: false
external_user_name:
description:
- (chat only - required) Name of the "user" sending the message
required: false
from_address:
description:
- (inbox only - required) Email address of the message sender
required: false
source:
description:
- (inbox only - required) Human readable identifier of the application that uses the Flowdock API
required: false
subject:
description:
- (inbox only - required) Subject line of the message
required: false
from_name:
description:
- (inbox only) Name of the message sender
required: false
reply_to:
description:
- (inbox only) Email address for replies
required: false
project:
description:
- (inbox only) Human readable identifier for more detailed message categorization
required: false
link:
description:
- (inbox only) Link associated with the message. This will be used to link the message subject in Team Inbox.
required: false
validate_certs:
description:
- If C(no), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
required: false
default: 'yes'
type: bool
requirements: [ ]
'''
EXAMPLES = '''
- flowdock:
type: inbox
token: AAAAAA
from_address: user@example.com
source: my cool app
msg: test from ansible
subject: test subject
- flowdock:
type: chat
token: AAAAAA
external_user_name: testuser
msg: test from ansible
tags: tag1,tag2,tag3
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.urls import fetch_url
# ===========================================
# Module execution.
#
def main():
module = AnsibleModule(
argument_spec=dict(
token=dict(required=True, no_log=True),
msg=dict(required=True),
type=dict(required=True, choices=["inbox", "chat"]),
external_user_name=dict(required=False),
from_address=dict(required=False),
source=dict(required=False),
subject=dict(required=False),
from_name=dict(required=False),
reply_to=dict(required=False),
project=dict(required=False),
tags=dict(required=False),
link=dict(required=False),
validate_certs=dict(default='yes', type='bool'),
),
supports_check_mode=True
)
type = module.params["type"]
token = module.params["token"]
if type == 'inbox':
url = "https://api.flowdock.com/v1/messages/team_inbox/%s" % (token)
else:
url = "https://api.flowdock.com/v1/messages/chat/%s" % (token)
params = {}
# required params
params['content'] = module.params["msg"]
# required params for the 'chat' type
if module.params['external_user_name']:
if type == 'inbox':
module.fail_json(msg="external_user_name is not valid for the 'inbox' type")
else:
params['external_user_name'] = module.params["external_user_name"]
elif type == 'chat':
module.fail_json(msg="external_user_name is required for the 'chat' type")
# required params for the 'inbox' type
for item in ['from_address', 'source', 'subject']:
if module.params[item]:
if type == 'chat':
module.fail_json(msg="%s is not valid for the 'chat' type" % item)
else:
params[item] = module.params[item]
elif type == 'inbox':
module.fail_json(msg="%s is required for the 'inbox' type" % item)
# optional params
if module.params["tags"]:
params['tags'] = module.params["tags"]
# optional params for the 'inbox' type
for item in ['from_name', 'reply_to', 'project', 'link']:
if module.params[item]:
if type == 'chat':
module.fail_json(msg="%s is not valid for the 'chat' type" % item)
else:
params[item] = module.params[item]
# If we're in check mode, just exit pretending like we succeeded
if module.check_mode:
module.exit_json(changed=False)
# Send the data to Flowdock
data = urlencode(params)
response, info = fetch_url(module, url, data=data)
if info['status'] != 200:
module.fail_json(msg="unable to send msg: %s" % info['msg'])
module.exit_json(changed=True, msg=module.params["msg"])
if __name__ == '__main__':
main()

View file

@ -0,0 +1,115 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: grove
short_description: Sends a notification to a grove.io channel
description:
- The C(grove) module sends a message for a service to a Grove.io
channel.
options:
channel_token:
description:
- Token of the channel to post to.
required: true
service:
description:
- Name of the service (displayed as the "user" in the message)
required: false
default: ansible
message:
description:
- Message content
required: true
url:
description:
- Service URL for the web client
required: false
icon_url:
description:
- Icon for the service
required: false
validate_certs:
description:
- If C(no), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
default: 'yes'
type: bool
author: "Jonas Pfenniger (@zimbatm)"
'''
EXAMPLES = '''
- grove: >
channel_token=6Ph62VBBJOccmtTPZbubiPzdrhipZXtg
service=my-app
message=deployed {{ target }}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.urls import fetch_url
BASE_URL = 'https://grove.io/api/notice/%s/'
# ==============================================================
# do_notify_grove
def do_notify_grove(module, channel_token, service, message, url=None, icon_url=None):
my_url = BASE_URL % (channel_token,)
my_data = dict(service=service, message=message)
if url is not None:
my_data['url'] = url
if icon_url is not None:
my_data['icon_url'] = icon_url
data = urlencode(my_data)
response, info = fetch_url(module, my_url, data=data)
if info['status'] != 200:
module.fail_json(msg="failed to send notification: %s" % info['msg'])
# ==============================================================
# main
def main():
module = AnsibleModule(
argument_spec=dict(
channel_token=dict(type='str', required=True, no_log=True),
message=dict(type='str', required=True),
service=dict(type='str', default='ansible'),
url=dict(type='str', default=None),
icon_url=dict(type='str', default=None),
validate_certs=dict(default='yes', type='bool'),
)
)
channel_token = module.params['channel_token']
service = module.params['service']
message = module.params['message']
url = module.params['url']
icon_url = module.params['icon_url']
do_notify_grove(module, channel_token, service, message, url, icon_url)
# Mission complete
module.exit_json(msg="OK")
if __name__ == '__main__':
main()

View file

@ -0,0 +1,208 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: hipchat
short_description: Send a message to Hipchat.
description:
- Send a message to a Hipchat room, with options to control the formatting.
options:
token:
description:
- API token.
required: true
room:
description:
- ID or name of the room.
required: true
from:
description:
- Name the message will appear to be sent from. Max length is 15
characters - above this it will be truncated.
default: Ansible
msg:
description:
- The message body.
required: true
color:
description:
- Background color for the message.
default: yellow
choices: [ "yellow", "red", "green", "purple", "gray", "random" ]
msg_format:
description:
- Message format.
default: text
choices: [ "text", "html" ]
notify:
description:
- If true, a notification will be triggered for users in the room.
type: bool
default: 'yes'
validate_certs:
description:
- If C(no), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: 'yes'
api:
description:
- API url if using a self-hosted hipchat server. For Hipchat API version
2 use the default URI with C(/v2) instead of C(/v1).
default: 'https://api.hipchat.com/v1'
author:
- Shirou Wakayama (@shirou)
- Paul Bourdel (@pb8226)
'''
EXAMPLES = '''
- hipchat:
room: notif
msg: Ansible task finished
# Use Hipchat API version 2
- hipchat:
api: https://api.hipchat.com/v2/
token: OAUTH2_TOKEN
room: notify
msg: Ansible task finished
'''
# ===========================================
# HipChat module specific support methods.
#
import json
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.six.moves.urllib.request import pathname2url
from ansible.module_utils._text import to_native
from ansible.module_utils.urls import fetch_url
DEFAULT_URI = "https://api.hipchat.com/v1"
MSG_URI_V1 = "/rooms/message"
NOTIFY_URI_V2 = "/room/{id_or_name}/notification"
def send_msg_v1(module, token, room, msg_from, msg, msg_format='text',
color='yellow', notify=False, api=MSG_URI_V1):
'''sending message to hipchat v1 server'''
params = {}
params['room_id'] = room
params['from'] = msg_from[:15] # max length is 15
params['message'] = msg
params['message_format'] = msg_format
params['color'] = color
params['api'] = api
params['notify'] = int(notify)
url = api + MSG_URI_V1 + "?auth_token=%s" % (token)
data = urlencode(params)
if module.check_mode:
# In check mode, exit before actually sending the message
module.exit_json(changed=False)
response, info = fetch_url(module, url, data=data)
if info['status'] == 200:
return response.read()
else:
module.fail_json(msg="failed to send message, return status=%s" % str(info['status']))
def send_msg_v2(module, token, room, msg_from, msg, msg_format='text',
color='yellow', notify=False, api=NOTIFY_URI_V2):
'''sending message to hipchat v2 server'''
headers = {'Authorization': 'Bearer %s' % token, 'Content-Type': 'application/json'}
body = dict()
body['message'] = msg
body['color'] = color
body['message_format'] = msg_format
body['notify'] = notify
POST_URL = api + NOTIFY_URI_V2
url = POST_URL.replace('{id_or_name}', pathname2url(room))
data = json.dumps(body)
if module.check_mode:
# In check mode, exit before actually sending the message
module.exit_json(changed=False)
response, info = fetch_url(module, url, data=data, headers=headers, method='POST')
# https://www.hipchat.com/docs/apiv2/method/send_room_notification shows
# 204 to be the expected result code.
if info['status'] in [200, 204]:
return response.read()
else:
module.fail_json(msg="failed to send message, return status=%s" % str(info['status']))
# ===========================================
# Module execution.
#
def main():
module = AnsibleModule(
argument_spec=dict(
token=dict(required=True, no_log=True),
room=dict(required=True),
msg=dict(required=True),
msg_from=dict(default="Ansible", aliases=['from']),
color=dict(default="yellow", choices=["yellow", "red", "green",
"purple", "gray", "random"]),
msg_format=dict(default="text", choices=["text", "html"]),
notify=dict(default=True, type='bool'),
validate_certs=dict(default='yes', type='bool'),
api=dict(default=DEFAULT_URI),
),
supports_check_mode=True
)
token = module.params["token"]
room = str(module.params["room"])
msg = module.params["msg"]
msg_from = module.params["msg_from"]
color = module.params["color"]
msg_format = module.params["msg_format"]
notify = module.params["notify"]
api = module.params["api"]
try:
if api.find('/v2') != -1:
send_msg_v2(module, token, room, msg_from, msg, msg_format, color, notify, api)
else:
send_msg_v1(module, token, room, msg_from, msg, msg_format, color, notify, api)
except Exception as e:
module.fail_json(msg="unable to send msg: %s" % to_native(e), exception=traceback.format_exc())
changed = True
module.exit_json(changed=changed, room=room, msg_from=msg_from, msg=msg)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,291 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2013, Jan-Piet Mens <jpmens () gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: irc
short_description: Send a message to an IRC channel or a nick
description:
- Send a message to an IRC channel or a nick. This is a very simplistic implementation.
options:
server:
description:
- IRC server name/address
default: localhost
port:
description:
- IRC server port number
default: 6667
nick:
description:
- Nickname to send the message from. May be shortened, depending on server's NICKLEN setting.
default: ansible
msg:
description:
- The message body.
required: true
topic:
description:
- Set the channel topic
color:
description:
- Text color for the message. ("none" is a valid option in 1.6 or later, in 1.6 and prior, the default color is black, not "none").
Added 11 more colors in version 2.0.
default: "none"
choices: [ "none", "white", "black", "blue", "green", "red", "brown", "purple", "orange", "yellow", "light_green", "teal", "light_cyan",
"light_blue", "pink", "gray", "light_gray"]
channel:
description:
- Channel name. One of nick_to or channel needs to be set. When both are set, the message will be sent to both of them.
required: true
nick_to:
description:
- A list of nicknames to send the message to. One of nick_to or channel needs to be set. When both are defined, the message will be sent to both of them.
key:
description:
- Channel key
passwd:
description:
- Server password
timeout:
description:
- Timeout to use while waiting for successful registration and join
messages, this is to prevent an endless loop
default: 30
use_ssl:
description:
- Designates whether TLS/SSL should be used when connecting to the IRC server
type: bool
default: 'no'
part:
description:
- Designates whether user should part from channel after sending message or not.
Useful for when using a faux bot and not wanting join/parts between messages.
type: bool
default: 'yes'
style:
description:
- Text style for the message. Note italic does not work on some clients
choices: [ "bold", "underline", "reverse", "italic" ]
# informational: requirements for nodes
requirements: [ socket ]
author:
- "Jan-Piet Mens (@jpmens)"
- "Matt Martz (@sivel)"
'''
EXAMPLES = '''
- irc:
server: irc.example.net
channel: #t1
msg: Hello world
- local_action:
module: irc
port: 6669
server: irc.example.net
channel: #t1
msg: 'All finished at {{ ansible_date_time.iso8601 }}'
color: red
nick: ansibleIRC
- local_action:
module: irc
port: 6669
server: irc.example.net
channel: #t1
nick_to:
- nick1
- nick2
msg: 'All finished at {{ ansible_date_time.iso8601 }}'
color: red
nick: ansibleIRC
'''
# ===========================================
# IRC module support methods.
#
import re
import socket
import ssl
import time
import traceback
from ansible.module_utils._text import to_native, to_bytes
from ansible.module_utils.basic import AnsibleModule
def send_msg(msg, server='localhost', port='6667', channel=None, nick_to=None, key=None, topic=None,
nick="ansible", color='none', passwd=False, timeout=30, use_ssl=False, part=True, style=None):
'''send message to IRC'''
nick_to = [] if nick_to is None else nick_to
colornumbers = {
'white': "00",
'black': "01",
'blue': "02",
'green': "03",
'red': "04",
'brown': "05",
'purple': "06",
'orange': "07",
'yellow': "08",
'light_green': "09",
'teal': "10",
'light_cyan': "11",
'light_blue': "12",
'pink': "13",
'gray': "14",
'light_gray': "15",
}
stylechoices = {
'bold': "\x02",
'underline': "\x1F",
'reverse': "\x16",
'italic': "\x1D",
}
try:
styletext = stylechoices[style]
except Exception:
styletext = ""
try:
colornumber = colornumbers[color]
colortext = "\x03" + colornumber
except Exception:
colortext = ""
message = styletext + colortext + msg
irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if use_ssl:
irc = ssl.wrap_socket(irc)
irc.connect((server, int(port)))
if passwd:
irc.send(to_bytes('PASS %s\r\n' % passwd))
irc.send(to_bytes('NICK %s\r\n' % nick))
irc.send(to_bytes('USER %s %s %s :ansible IRC\r\n' % (nick, nick, nick)))
motd = ''
start = time.time()
while 1:
motd += to_native(irc.recv(1024))
# The server might send back a shorter nick than we specified (due to NICKLEN),
# so grab that and use it from now on (assuming we find the 00[1-4] response).
match = re.search(r'^:\S+ 00[1-4] (?P<nick>\S+) :', motd, flags=re.M)
if match:
nick = match.group('nick')
break
elif time.time() - start > timeout:
raise Exception('Timeout waiting for IRC server welcome response')
time.sleep(0.5)
if channel:
if key:
irc.send(to_bytes('JOIN %s %s\r\n' % (channel, key)))
else:
irc.send(to_bytes('JOIN %s\r\n' % channel))
join = ''
start = time.time()
while 1:
join += to_native(irc.recv(1024))
if re.search(r'^:\S+ 366 %s %s :' % (nick, channel), join, flags=re.M | re.I):
break
elif time.time() - start > timeout:
raise Exception('Timeout waiting for IRC JOIN response')
time.sleep(0.5)
if topic is not None:
irc.send(to_bytes('TOPIC %s :%s\r\n' % (channel, topic)))
time.sleep(1)
if nick_to:
for nick in nick_to:
irc.send(to_bytes('PRIVMSG %s :%s\r\n' % (nick, message)))
if channel:
irc.send(to_bytes('PRIVMSG %s :%s\r\n' % (channel, message)))
time.sleep(1)
if part:
if channel:
irc.send(to_bytes('PART %s\r\n' % channel))
irc.send(to_bytes('QUIT\r\n'))
time.sleep(1)
irc.close()
# ===========================================
# Main
#
def main():
module = AnsibleModule(
argument_spec=dict(
server=dict(default='localhost'),
port=dict(type='int', default=6667),
nick=dict(default='ansible'),
nick_to=dict(required=False, type='list'),
msg=dict(required=True),
color=dict(default="none", aliases=['colour'], choices=["white", "black", "blue",
"green", "red", "brown",
"purple", "orange", "yellow",
"light_green", "teal", "light_cyan",
"light_blue", "pink", "gray",
"light_gray", "none"]),
style=dict(default="none", choices=["underline", "reverse", "bold", "italic", "none"]),
channel=dict(required=False),
key=dict(no_log=True),
topic=dict(),
passwd=dict(no_log=True),
timeout=dict(type='int', default=30),
part=dict(type='bool', default=True),
use_ssl=dict(type='bool', default=False)
),
supports_check_mode=True,
required_one_of=[['channel', 'nick_to']]
)
server = module.params["server"]
port = module.params["port"]
nick = module.params["nick"]
nick_to = module.params["nick_to"]
msg = module.params["msg"]
color = module.params["color"]
channel = module.params["channel"]
topic = module.params["topic"]
if topic and not channel:
module.fail_json(msg="When topic is specified, a channel is required.")
key = module.params["key"]
passwd = module.params["passwd"]
timeout = module.params["timeout"]
use_ssl = module.params["use_ssl"]
part = module.params["part"]
style = module.params["style"]
try:
send_msg(msg, server, port, channel, nick_to, key, topic, nick, color, passwd, timeout, use_ssl, part, style)
except Exception as e:
module.fail_json(msg="unable to send to IRC: %s" % to_native(e), exception=traceback.format_exc())
module.exit_json(changed=False, channel=channel, nick=nick,
msg=msg)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,164 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# (c) 2015, Brian Coca <bcoca@ansible.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: jabber
short_description: Send a message to jabber user or chat room
description:
- Send a message to jabber
options:
user:
description:
- User as which to connect
required: true
password:
description:
- password for user to connect
required: true
to:
description:
- user ID or name of the room, when using room use a slash to indicate your nick.
required: true
msg:
description:
- The message body.
required: true
host:
description:
- host to connect, overrides user info
port:
description:
- port to connect to, overrides default
default: 5222
encoding:
description:
- message encoding
# informational: requirements for nodes
requirements:
- python xmpp (xmpppy)
author: "Brian Coca (@bcoca)"
'''
EXAMPLES = '''
# send a message to a user
- jabber:
user: mybot@example.net
password: secret
to: friend@example.net
msg: Ansible task finished
# send a message to a room
- jabber:
user: mybot@example.net
password: secret
to: mychaps@conference.example.net/ansiblebot
msg: Ansible task finished
# send a message, specifying the host and port
- jabber:
user: mybot@example.net
host: talk.example.net
port: 5223
password: secret
to: mychaps@example.net
msg: Ansible task finished
'''
import time
import traceback
HAS_XMPP = True
XMPP_IMP_ERR = None
try:
import xmpp
except ImportError:
XMPP_IMP_ERR = traceback.format_exc()
HAS_XMPP = False
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils._text import to_native
def main():
module = AnsibleModule(
argument_spec=dict(
user=dict(required=True),
password=dict(required=True, no_log=True),
to=dict(required=True),
msg=dict(required=True),
host=dict(required=False),
port=dict(required=False, default=5222, type='int'),
encoding=dict(required=False),
),
supports_check_mode=True
)
if not HAS_XMPP:
module.fail_json(msg=missing_required_lib('xmpppy'), exception=XMPP_IMP_ERR)
jid = xmpp.JID(module.params['user'])
user = jid.getNode()
server = jid.getDomain()
port = module.params['port']
password = module.params['password']
try:
to, nick = module.params['to'].split('/', 1)
except ValueError:
to, nick = module.params['to'], None
if module.params['host']:
host = module.params['host']
else:
host = server
if module.params['encoding']:
xmpp.simplexml.ENCODING = module.params['encoding']
msg = xmpp.protocol.Message(body=module.params['msg'])
try:
conn = xmpp.Client(server, debug=[])
if not conn.connect(server=(host, port)):
module.fail_json(rc=1, msg='Failed to connect to server: %s' % (server))
if not conn.auth(user, password, 'Ansible'):
module.fail_json(rc=1, msg='Failed to authorize %s on: %s' % (user, server))
# some old servers require this, also the sleep following send
conn.sendInitPresence(requestRoster=0)
if nick: # sending to room instead of user, need to join
msg.setType('groupchat')
msg.setTag('x', namespace='http://jabber.org/protocol/muc#user')
join = xmpp.Presence(to=module.params['to'])
join.setTag('x', namespace='http://jabber.org/protocol/muc')
conn.send(join)
time.sleep(1)
else:
msg.setType('chat')
msg.setTo(to)
if not module.check_mode:
conn.send(msg)
time.sleep(1)
conn.disconnect()
except Exception as e:
module.fail_json(msg="unable to send msg: %s" % to_native(e), exception=traceback.format_exc())
module.exit_json(changed=False, to=to, user=user, msg=msg.getBody())
if __name__ == '__main__':
main()

View file

@ -0,0 +1,98 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'metadata_version': '1.1'}
DOCUMENTATION = '''
---
module: logentries_msg
short_description: Send a message to logentries.
description:
- Send a message to logentries
requirements:
- "python >= 2.6"
options:
token:
description:
- Log token.
required: true
msg:
description:
- The message body.
required: true
api:
description:
- API endpoint
default: data.logentries.com
port:
description:
- API endpoint port
default: 80
author: "Jimmy Tang (@jcftang) <jimmy_tang@rapid7.com>"
'''
RETURN = '''# '''
EXAMPLES = '''
- logentries_msg:
token=00000000-0000-0000-0000-000000000000
msg="{{ ansible_hostname }}"
'''
import socket
from ansible.module_utils.basic import AnsibleModule
def send_msg(module, token, msg, api, port):
message = "{0} {1}\n".format(token, msg)
api_ip = socket.gethostbyname(api)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((api_ip, port))
try:
if not module.check_mode:
s.send(message)
except Exception as e:
module.fail_json(msg="failed to send message, msg=%s" % e)
s.close()
def main():
module = AnsibleModule(
argument_spec=dict(
token=dict(type='str', required=True),
msg=dict(type='str', required=True),
api=dict(type='str', default="data.logentries.com"),
port=dict(type='int', default=80)),
supports_check_mode=True
)
token = module.params["token"]
msg = module.params["msg"]
api = module.params["api"]
port = module.params["port"]
changed = False
try:
send_msg(module, token, msg, api, port)
changed = True
except Exception as e:
module.fail_json(msg="unable to send msg: %s" % e)
module.exit_json(changed=changed, msg=msg)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,389 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2012, Dag Wieers (@dagwieers) <dag@wieers.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
author:
- Dag Wieers (@dagwieers)
module: mail
short_description: Send an email
description:
- This module is useful for sending emails from playbooks.
- One may wonder why automate sending emails? In complex environments
there are from time to time processes that cannot be automated, either
because you lack the authority to make it so, or because not everyone
agrees to a common approach.
- If you cannot automate a specific step, but the step is non-blocking,
sending out an email to the responsible party to make them perform their
part of the bargain is an elegant way to put the responsibility in
someone else's lap.
- Of course sending out a mail can be equally useful as a way to notify
one or more people in a team that a specific action has been
(successfully) taken.
options:
from:
description:
- The email-address the mail is sent from. May contain address and phrase.
type: str
default: root
to:
description:
- The email-address(es) the mail is being sent to.
- This is a list, which may contain address and phrase portions.
type: list
default: root
aliases: [ recipients ]
cc:
description:
- The email-address(es) the mail is being copied to.
- This is a list, which may contain address and phrase portions.
type: list
bcc:
description:
- The email-address(es) the mail is being 'blind' copied to.
- This is a list, which may contain address and phrase portions.
type: list
subject:
description:
- The subject of the email being sent.
required: yes
type: str
body:
description:
- The body of the email being sent.
type: str
default: $subject
username:
description:
- If SMTP requires username.
type: str
password:
description:
- If SMTP requires password.
type: str
host:
description:
- The mail server.
type: str
default: localhost
port:
description:
- The mail server port.
- This must be a valid integer between 1 and 65534
type: int
default: 25
attach:
description:
- A list of pathnames of files to attach to the message.
- Attached files will have their content-type set to C(application/octet-stream).
type: list
default: []
headers:
description:
- A list of headers which should be added to the message.
- Each individual header is specified as C(header=value) (see example below).
type: list
default: []
charset:
description:
- The character set of email being sent.
type: str
default: utf-8
subtype:
description:
- The minor mime type, can be either C(plain) or C(html).
- The major type is always C(text).
type: str
choices: [ html, plain ]
default: plain
secure:
description:
- If C(always), the connection will only send email if the connection is Encrypted.
If the server doesn't accept the encrypted connection it will fail.
- If C(try), the connection will attempt to setup a secure SSL/TLS session, before trying to send.
- If C(never), the connection will not attempt to setup a secure SSL/TLS session, before sending
- If C(starttls), the connection will try to upgrade to a secure SSL/TLS connection, before sending.
If it is unable to do so it will fail.
type: str
choices: [ always, never, starttls, try ]
default: try
timeout:
description:
- Sets the timeout in seconds for connection attempts.
type: int
default: 20
'''
EXAMPLES = r'''
- name: Example playbook sending mail to root
mail:
subject: System {{ ansible_hostname }} has been successfully provisioned.
delegate_to: localhost
- name: Sending an e-mail using Gmail SMTP servers
mail:
host: smtp.gmail.com
port: 587
username: username@gmail.com
password: mysecret
to: John Smith <john.smith@example.com>
subject: Ansible-report
body: System {{ ansible_hostname }} has been successfully provisioned.
delegate_to: localhost
- name: Send e-mail to a bunch of users, attaching files
mail:
host: 127.0.0.1
port: 2025
subject: Ansible-report
body: Hello, this is an e-mail. I hope you like it ;-)
from: jane@example.net (Jane Jolie)
to:
- John Doe <j.d@example.org>
- Suzie Something <sue@example.com>
cc: Charlie Root <root@localhost>
attach:
- /etc/group
- /tmp/avatar2.png
headers:
- Reply-To=john@example.com
- X-Special="Something or other"
charset: us-ascii
delegate_to: localhost
- name: Sending an e-mail using the remote machine, not the Ansible controller node
mail:
host: localhost
port: 25
to: John Smith <john.smith@example.com>
subject: Ansible-report
body: System {{ ansible_hostname }} has been successfully provisioned.
- name: Sending an e-mail using Legacy SSL to the remote machine
mail:
host: localhost
port: 25
to: John Smith <john.smith@example.com>
subject: Ansible-report
body: System {{ ansible_hostname }} has been successfully provisioned.
secure: always
- name: Sending an e-mail using StartTLS to the remote machine
mail:
host: localhost
port: 25
to: John Smith <john.smith@example.com>
subject: Ansible-report
body: System {{ ansible_hostname }} has been successfully provisioned.
secure: starttls
'''
import os
import smtplib
import ssl
import traceback
from email import encoders
from email.utils import parseaddr, formataddr, formatdate
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import PY3
from ansible.module_utils._text import to_native
def main():
module = AnsibleModule(
argument_spec=dict(
username=dict(type='str'),
password=dict(type='str', no_log=True),
host=dict(type='str', default='localhost'),
port=dict(type='int', default=25),
sender=dict(type='str', default='root', aliases=['from']),
to=dict(type='list', default=['root'], aliases=['recipients']),
cc=dict(type='list', default=[]),
bcc=dict(type='list', default=[]),
subject=dict(type='str', required=True, aliases=['msg']),
body=dict(type='str'),
attach=dict(type='list', default=[]),
headers=dict(type='list', default=[]),
charset=dict(type='str', default='utf-8'),
subtype=dict(type='str', default='plain', choices=['html', 'plain']),
secure=dict(type='str', default='try', choices=['always', 'never', 'starttls', 'try']),
timeout=dict(type='int', default=20),
),
required_together=[['password', 'username']],
)
username = module.params.get('username')
password = module.params.get('password')
host = module.params.get('host')
port = module.params.get('port')
sender = module.params.get('sender')
recipients = module.params.get('to')
copies = module.params.get('cc')
blindcopies = module.params.get('bcc')
subject = module.params.get('subject')
body = module.params.get('body')
attach_files = module.params.get('attach')
headers = module.params.get('headers')
charset = module.params.get('charset')
subtype = module.params.get('subtype')
secure = module.params.get('secure')
timeout = module.params.get('timeout')
code = 0
secure_state = False
sender_phrase, sender_addr = parseaddr(sender)
if not body:
body = subject
try:
if secure != 'never':
try:
if PY3:
smtp = smtplib.SMTP_SSL(host=host, port=port, timeout=timeout)
else:
smtp = smtplib.SMTP_SSL(timeout=timeout)
code, smtpmessage = smtp.connect(host, port)
secure_state = True
except ssl.SSLError as e:
if secure == 'always':
module.fail_json(rc=1, msg='Unable to start an encrypted session to %s:%s: %s' %
(host, port, to_native(e)), exception=traceback.format_exc())
except Exception:
pass
if not secure_state:
if PY3:
smtp = smtplib.SMTP(host=host, port=port, timeout=timeout)
else:
smtp = smtplib.SMTP(timeout=timeout)
code, smtpmessage = smtp.connect(host, port)
except smtplib.SMTPException as e:
module.fail_json(rc=1, msg='Unable to Connect %s:%s: %s' % (host, port, to_native(e)), exception=traceback.format_exc())
try:
smtp.ehlo()
except smtplib.SMTPException as e:
module.fail_json(rc=1, msg='Helo failed for host %s:%s: %s' % (host, port, to_native(e)), exception=traceback.format_exc())
if int(code) > 0:
if not secure_state and secure in ('starttls', 'try'):
if smtp.has_extn('STARTTLS'):
try:
smtp.starttls()
secure_state = True
except smtplib.SMTPException as e:
module.fail_json(rc=1, msg='Unable to start an encrypted session to %s:%s: %s' %
(host, port, to_native(e)), exception=traceback.format_exc())
try:
smtp.ehlo()
except smtplib.SMTPException as e:
module.fail_json(rc=1, msg='Helo failed for host %s:%s: %s' % (host, port, to_native(e)), exception=traceback.format_exc())
else:
if secure == 'starttls':
module.fail_json(rc=1, msg='StartTLS is not offered on server %s:%s' % (host, port))
if username and password:
if smtp.has_extn('AUTH'):
try:
smtp.login(username, password)
except smtplib.SMTPAuthenticationError:
module.fail_json(rc=1, msg='Authentication to %s:%s failed, please check your username and/or password' % (host, port))
except smtplib.SMTPException:
module.fail_json(rc=1, msg='No Suitable authentication method was found on %s:%s' % (host, port))
else:
module.fail_json(rc=1, msg="No Authentication on the server at %s:%s" % (host, port))
if not secure_state and (username and password):
module.warn('Username and Password was sent without encryption')
msg = MIMEMultipart(_charset=charset)
msg['From'] = formataddr((sender_phrase, sender_addr))
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = Header(subject, charset)
msg.preamble = "Multipart message"
for header in headers:
# NOTE: Backward compatible with old syntax using '|' as delimiter
for hdr in [x.strip() for x in header.split('|')]:
try:
h_key, h_val = hdr.split('=')
h_val = to_native(Header(h_val, charset))
msg.add_header(h_key, h_val)
except Exception:
module.warn("Skipping header '%s', unable to parse" % hdr)
if 'X-Mailer' not in msg:
msg.add_header('X-Mailer', 'Ansible mail module')
addr_list = []
for addr in [x.strip() for x in blindcopies]:
addr_list.append(parseaddr(addr)[1]) # address only, w/o phrase
to_list = []
for addr in [x.strip() for x in recipients]:
to_list.append(formataddr(parseaddr(addr)))
addr_list.append(parseaddr(addr)[1]) # address only, w/o phrase
msg['To'] = ", ".join(to_list)
cc_list = []
for addr in [x.strip() for x in copies]:
cc_list.append(formataddr(parseaddr(addr)))
addr_list.append(parseaddr(addr)[1]) # address only, w/o phrase
msg['Cc'] = ", ".join(cc_list)
part = MIMEText(body + "\n\n", _subtype=subtype, _charset=charset)
msg.attach(part)
# NOTE: Backware compatibility with old syntax using space as delimiter is not retained
# This breaks files with spaces in it :-(
for filename in attach_files:
try:
part = MIMEBase('application', 'octet-stream')
with open(filename, 'rb') as fp:
part.set_payload(fp.read())
encoders.encode_base64(part)
part.add_header('Content-disposition', 'attachment', filename=os.path.basename(filename))
msg.attach(part)
except Exception as e:
module.fail_json(rc=1, msg="Failed to send mail: can't attach file %s: %s" %
(filename, to_native(e)), exception=traceback.format_exc())
composed = msg.as_string()
try:
result = smtp.sendmail(sender_addr, set(addr_list), composed)
except Exception as e:
module.fail_json(rc=1, msg="Failed to send mail to '%s': %s" %
(", ".join(set(addr_list)), to_native(e)), exception=traceback.format_exc())
smtp.quit()
if result:
for key in result:
module.warn("Failed to send mail to '%s': %s %s" % (key, result[key][0], result[key][1]))
module.exit_json(msg='Failed to send mail to at least one recipient', result=result)
module.exit_json(msg='Mail sent successfully', result=result)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,138 @@
#!/usr/bin/python
# coding: utf-8
# (c) 2018, Jan Christian Grünhage <jan.christian@gruenhage.xyz>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
author: "Jan Christian Grünhage (@jcgruenhage)"
module: matrix
short_description: Send notifications to matrix
description:
- This module sends html formatted notifications to matrix rooms.
options:
msg_plain:
description:
- Plain text form of the message to send to matrix, usually markdown
required: true
msg_html:
description:
- HTML form of the message to send to matrix
required: true
room_id:
description:
- ID of the room to send the notification to
required: true
hs_url:
description:
- URL of the homeserver, where the CS-API is reachable
required: true
token:
description:
- Authentication token for the API call. If provided, user_id and password are not required
user_id:
description:
- The user id of the user
password:
description:
- The password to log in with
requirements:
- matrix-client (Python library)
'''
EXAMPLES = '''
- name: Send matrix notification with token
matrix:
msg_plain: "**hello world**"
msg_html: "<b>hello world</b>"
room_id: "!12345678:server.tld"
hs_url: "https://matrix.org"
token: "{{ matrix_auth_token }}"
- name: Send matrix notification with user_id and password
matrix:
msg_plain: "**hello world**"
msg_html: "<b>hello world</b>"
room_id: "!12345678:server.tld"
hs_url: "https://matrix.org"
user_id: "ansible_notification_bot"
password: "{{ matrix_auth_password }}"
'''
RETURN = '''
'''
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
MATRIX_IMP_ERR = None
try:
from matrix_client.client import MatrixClient
except ImportError:
MATRIX_IMP_ERR = traceback.format_exc()
matrix_found = False
else:
matrix_found = True
def run_module():
module_args = dict(
msg_plain=dict(type='str', required=True),
msg_html=dict(type='str', required=True),
room_id=dict(type='str', required=True),
hs_url=dict(type='str', required=True),
token=dict(type='str', required=False, no_log=True),
user_id=dict(type='str', required=False),
password=dict(type='str', required=False, no_log=True),
)
result = dict(
changed=False,
message=''
)
module = AnsibleModule(
argument_spec=module_args,
mutually_exclusive=[['password', 'token']],
required_one_of=[['password', 'token']],
required_together=[['user_id', 'password']],
supports_check_mode=True
)
if not matrix_found:
module.fail_json(msg=missing_required_lib('matrix-client'), exception=MATRIX_IMP_ERR)
if module.check_mode:
return result
# create a client object
client = MatrixClient(module.params['hs_url'])
if module.params['token'] is not None:
client.api.token = module.params['token']
else:
client.login(module.params['user_id'], module.params['password'], sync=False)
# make sure we are in a given room and return a room object for it
room = client.join_room(module.params['room_id'])
# send an html formatted messages
room.send_html(module.params['msg_html'], module.params['msg_plain'])
module.exit_json(**result)
def main():
run_module()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,150 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Benjamin Jolivot <bjolivot@gmail.com>
# Inspired by slack module :
# # (c) 2017, Steve Pletcher <steve@steve-pletcher.com>
# # (c) 2016, René Moser <mail@renemoser.net>
# # (c) 2015, Stefan Berggren <nsg@nsg.cc>
# # (c) 2014, Ramon de la Fuente <ramon@delafuente.nl>)
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
module: mattermost
short_description: Send Mattermost notifications
description:
- Sends notifications to U(http://your.mattermost.url) via the Incoming WebHook integration.
author: "Benjamin Jolivot (@bjolivot)"
options:
url:
description:
- Mattermost url (i.e. http://mattermost.yourcompany.com).
required: true
api_key:
description:
- Mattermost webhook api key. Log into your mattermost site, go to
Menu -> Integration -> Incoming Webhook -> Add Incoming Webhook.
This will give you full URL. api_key is the last part.
http://mattermost.example.com/hooks/C(API_KEY)
required: true
text:
description:
- Text to send. Note that the module does not handle escaping characters.
required: true
channel:
description:
- Channel to send the message to. If absent, the message goes to the channel selected for the I(api_key).
username:
description:
- This is the sender of the message (Username Override need to be enabled by mattermost admin, see mattermost doc.
default: Ansible
icon_url:
description:
- Url for the message sender's icon.
default: https://www.ansible.com/favicon.ico
validate_certs:
description:
- If C(no), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
default: yes
type: bool
'''
EXAMPLES = """
- name: Send notification message via Mattermost
mattermost:
url: http://mattermost.example.com
api_key: my_api_key
text: '{{ inventory_hostname }} completed'
- name: Send notification message via Mattermost all options
mattermost:
url: http://mattermost.example.com
api_key: my_api_key
text: '{{ inventory_hostname }} completed'
channel: notifications
username: 'Ansible on {{ inventory_hostname }}'
icon_url: http://www.example.com/some-image-file.png
"""
RETURN = '''
payload:
description: Mattermost payload
returned: success
type: str
webhook_url:
description: URL the webhook is sent to
returned: success
type: str
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
def main():
module = AnsibleModule(
supports_check_mode=True,
argument_spec=dict(
url=dict(type='str', required=True),
api_key=dict(type='str', required=True, no_log=True),
text=dict(type='str', required=True),
channel=dict(type='str', default=None),
username=dict(type='str', default='Ansible'),
icon_url=dict(type='str', default='https://www.ansible.com/favicon.ico'),
validate_certs=dict(default='yes', type='bool'),
)
)
# init return dict
result = dict(changed=False, msg="OK")
# define webhook
webhook_url = "{0}/hooks/{1}".format(module.params['url'], module.params['api_key'])
result['webhook_url'] = webhook_url
# define payload
payload = {}
for param in ['text', 'channel', 'username', 'icon_url']:
if module.params[param] is not None:
payload[param] = module.params[param]
payload = module.jsonify(payload)
result['payload'] = payload
# http headers
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
}
# notes:
# Nothing is done in check mode
# it'll pass even if your server is down or/and if your token is invalid.
# If someone find good way to check...
# send request if not in test mode
if module.check_mode is False:
response, info = fetch_url(module=module, url=webhook_url, headers=headers, method='POST', data=payload)
# something's wrong
if info['status'] != 200:
# some problem
result['msg'] = "Failed to send mattermost message, the error was: {0}".format(info['msg'])
module.fail_json(**result)
# Looks good
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,241 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2013, 2014, Jan-Piet Mens <jpmens () gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: mqtt
short_description: Publish a message on an MQTT topic for the IoT
description:
- Publish a message on an MQTT topic.
options:
server:
description:
- MQTT broker address/name
default: localhost
port:
description:
- MQTT broker port number
default: 1883
username:
description:
- Username to authenticate against the broker.
password:
description:
- Password for C(username) to authenticate against the broker.
client_id:
description:
- MQTT client identifier
default: hostname + pid
topic:
description:
- MQTT topic name
required: true
payload:
description:
- Payload. The special string C("None") may be used to send a NULL
(i.e. empty) payload which is useful to simply notify with the I(topic)
or to clear previously retained messages.
required: true
qos:
description:
- QoS (Quality of Service)
default: 0
choices: [ "0", "1", "2" ]
retain:
description:
- Setting this flag causes the broker to retain (i.e. keep) the message so that
applications that subsequently subscribe to the topic can received the last
retained message immediately.
type: bool
default: 'no'
ca_cert:
description:
- The path to the Certificate Authority certificate files that are to be
treated as trusted by this client. If this is the only option given
then the client will operate in a similar manner to a web browser. That
is to say it will require the broker to have a certificate signed by the
Certificate Authorities in ca_certs and will communicate using TLS v1,
but will not attempt any form of authentication. This provides basic
network encryption but may not be sufficient depending on how the broker
is configured.
aliases: [ ca_certs ]
client_cert:
description:
- The path pointing to the PEM encoded client certificate. If this is not
None it will be used as client information for TLS based
authentication. Support for this feature is broker dependent.
aliases: [ certfile ]
client_key:
description:
- The path pointing to the PEM encoded client private key. If this is not
None it will be used as client information for TLS based
authentication. Support for this feature is broker dependent.
aliases: [ keyfile ]
tls_version:
description:
- Specifies the version of the SSL/TLS protocol to be used.
- By default (if the python version supports it) the highest TLS version is
detected. If unavailable, TLS v1 is used.
type: str
choices:
- tlsv1.1
- tlsv1.2
requirements: [ mosquitto ]
notes:
- This module requires a connection to an MQTT broker such as Mosquitto
U(http://mosquitto.org) and the I(Paho) C(mqtt) Python client (U(https://pypi.org/project/paho-mqtt/)).
author: "Jan-Piet Mens (@jpmens)"
'''
EXAMPLES = '''
- mqtt:
topic: 'service/ansible/{{ ansible_hostname }}'
payload: 'Hello at {{ ansible_date_time.iso8601 }}'
qos: 0
retain: False
client_id: ans001
delegate_to: localhost
'''
# ===========================================
# MQTT module support methods.
#
import os
import ssl
import traceback
import platform
from distutils.version import LooseVersion
HAS_PAHOMQTT = True
PAHOMQTT_IMP_ERR = None
try:
import socket
import paho.mqtt.publish as mqtt
except ImportError:
PAHOMQTT_IMP_ERR = traceback.format_exc()
HAS_PAHOMQTT = False
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils._text import to_native
# ===========================================
# Main
#
def main():
tls_map = {}
try:
tls_map['tlsv1.2'] = ssl.PROTOCOL_TLSv1_2
except AttributeError:
pass
try:
tls_map['tlsv1.1'] = ssl.PROTOCOL_TLSv1_1
except AttributeError:
pass
module = AnsibleModule(
argument_spec=dict(
server=dict(default='localhost'),
port=dict(default=1883, type='int'),
topic=dict(required=True),
payload=dict(required=True),
client_id=dict(default=None),
qos=dict(default="0", choices=["0", "1", "2"]),
retain=dict(default=False, type='bool'),
username=dict(default=None),
password=dict(default=None, no_log=True),
ca_cert=dict(default=None, type='path', aliases=['ca_certs']),
client_cert=dict(default=None, type='path', aliases=['certfile']),
client_key=dict(default=None, type='path', aliases=['keyfile']),
tls_version=dict(default=None, choices=['tlsv1.1', 'tlsv1.2'])
),
supports_check_mode=True
)
if not HAS_PAHOMQTT:
module.fail_json(msg=missing_required_lib('paho-mqtt'), exception=PAHOMQTT_IMP_ERR)
server = module.params.get("server", 'localhost')
port = module.params.get("port", 1883)
topic = module.params.get("topic")
payload = module.params.get("payload")
client_id = module.params.get("client_id", '')
qos = int(module.params.get("qos", 0))
retain = module.params.get("retain")
username = module.params.get("username", None)
password = module.params.get("password", None)
ca_certs = module.params.get("ca_cert", None)
certfile = module.params.get("client_cert", None)
keyfile = module.params.get("client_key", None)
tls_version = module.params.get("tls_version", None)
if client_id is None:
client_id = "%s_%s" % (socket.getfqdn(), os.getpid())
if payload and payload == 'None':
payload = None
auth = None
if username is not None:
auth = {'username': username, 'password': password}
tls = None
if ca_certs is not None:
if tls_version:
tls_version = tls_map.get(tls_version, ssl.PROTOCOL_SSLv23)
else:
if LooseVersion(platform.python_version()) <= "3.5.2":
# Specifying `None` on later versions of python seems sufficient to
# instruct python to autonegotiate the SSL/TLS connection. On versions
# 3.5.2 and lower though we need to specify the version.
#
# Note that this is an alias for PROTOCOL_TLS, but PROTOCOL_TLS was
# not available until 3.5.3.
tls_version = ssl.PROTOCOL_SSLv23
tls = {
'ca_certs': ca_certs,
'certfile': certfile,
'keyfile': keyfile,
'tls_version': tls_version,
}
try:
mqtt.single(
topic,
payload,
qos=qos,
retain=retain,
client_id=client_id,
hostname=server,
port=port,
auth=auth,
tls=tls
)
except Exception as e:
module.fail_json(
msg="unable to publish to MQTT broker %s" % to_native(e),
exception=traceback.format_exc()
)
module.exit_json(changed=False, topic=topic)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,135 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2014, Matt Martz <matt@sivel.net>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
module: nexmo
short_description: Send a SMS via nexmo
description:
- Send a SMS message via nexmo
author: "Matt Martz (@sivel)"
options:
api_key:
description:
- Nexmo API Key
required: true
api_secret:
description:
- Nexmo API Secret
required: true
src:
description:
- Nexmo Number to send from
required: true
dest:
description:
- Phone number(s) to send SMS message to
required: true
msg:
description:
- Message to text to send. Messages longer than 160 characters will be
split into multiple messages
required: true
validate_certs:
description:
- If C(no), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: 'yes'
extends_documentation_fragment:
- url
'''
EXAMPLES = """
- name: Send notification message via Nexmo
nexmo:
api_key: 640c8a53
api_secret: 0ce239a6
src: 12345678901
dest:
- 10987654321
- 16789012345
msg: '{{ inventory_hostname }} completed'
delegate_to: localhost
"""
import json
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url, url_argument_spec
NEXMO_API = 'https://rest.nexmo.com/sms/json'
def send_msg(module):
failed = list()
responses = dict()
msg = {
'api_key': module.params.get('api_key'),
'api_secret': module.params.get('api_secret'),
'from': module.params.get('src'),
'text': module.params.get('msg')
}
for number in module.params.get('dest'):
msg['to'] = number
url = "%s?%s" % (NEXMO_API, urlencode(msg))
headers = dict(Accept='application/json')
response, info = fetch_url(module, url, headers=headers)
if info['status'] != 200:
failed.append(number)
responses[number] = dict(failed=True)
try:
responses[number] = json.load(response)
except Exception:
failed.append(number)
responses[number] = dict(failed=True)
else:
for message in responses[number]['messages']:
if int(message['status']) != 0:
failed.append(number)
responses[number] = dict(failed=True, **responses[number])
if failed:
msg = 'One or messages failed to send'
else:
msg = ''
module.exit_json(failed=bool(failed), msg=msg, changed=False,
responses=responses)
def main():
argument_spec = url_argument_spec()
argument_spec.update(
dict(
api_key=dict(required=True, no_log=True),
api_secret=dict(required=True, no_log=True),
src=dict(required=True, type='int'),
dest=dict(required=True, type='list'),
msg=dict(required=True),
),
)
module = AnsibleModule(
argument_spec=argument_spec
)
send_msg(module)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,296 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2017 Marc Sensenich <hello@marc-sensenich.com>
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
module: office_365_connector_card
short_description: Use webhooks to create Connector Card messages within an Office 365 group
description:
- Creates Connector Card messages through
- Office 365 Connectors U(https://dev.outlook.com/Connectors)
author: "Marc Sensenich (@marc-sensenich)"
notes:
- This module is not idempotent, therefore if the same task is run twice
there will be two Connector Cards created
options:
webhook:
description:
- The webhook URL is given to you when you create a new Connector.
required: true
summary:
description:
- A string used for summarizing card content.
- This will be shown as the message subject.
- This is required if the text parameter isn't populated.
color:
description:
- Accent color used for branding or indicating status in the card.
title:
description:
- A title for the Connector message. Shown at the top of the message.
text:
description:
- The main text of the card.
- This will be rendered below the sender information and optional title,
- and above any sections or actions present.
actions:
description:
- This array of objects will power the action links
- found at the bottom of the card.
sections:
description:
- Contains a list of sections to display in the card.
- For more information see https://dev.outlook.com/Connectors/reference.
'''
EXAMPLES = """
- name: Create a simple Connector Card
office_365_connector_card:
webhook: https://outlook.office.com/webhook/GUID/IncomingWebhook/GUID/GUID
text: 'Hello, World!'
- name: Create a Connector Card with the full format
office_365_connector_card:
webhook: https://outlook.office.com/webhook/GUID/IncomingWebhook/GUID/GUID
summary: This is the summary property
title: This is the **card's title** property
text: This is the **card's text** property. Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
color: E81123
sections:
- title: This is the **section's title** property
activity_image: http://connectorsdemo.azurewebsites.net/images/MSC12_Oscar_002.jpg
activity_title: This is the section's **activityTitle** property
activity_subtitle: This is the section's **activitySubtitle** property
activity_text: This is the section's **activityText** property.
hero_image:
image: http://connectorsdemo.azurewebsites.net/images/WIN12_Scene_01.jpg
title: This is the image's alternate text
text: This is the section's text property. Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
facts:
- name: This is a fact name
value: This is a fact value
- name: This is a fact name
value: This is a fact value
- name: This is a fact name
value: This is a fact value
images:
- image: http://connectorsdemo.azurewebsites.net/images/MicrosoftSurface_024_Cafe_OH-06315_VS_R1c.jpg
title: This is the image's alternate text
- image: http://connectorsdemo.azurewebsites.net/images/WIN12_Scene_01.jpg
title: This is the image's alternate text
- image: http://connectorsdemo.azurewebsites.net/images/WIN12_Anthony_02.jpg
title: This is the image's alternate text
actions:
- "@type": ActionCard
name: Comment
inputs:
- "@type": TextInput
id: comment
is_multiline: true
title: Input's title property
actions:
- "@type": HttpPOST
name: Save
target: http://...
- "@type": ActionCard
name: Due Date
inputs:
- "@type": DateInput
id: dueDate
title: Input's title property
actions:
- "@type": HttpPOST
name: Save
target: http://...
- "@type": HttpPOST
name: Action's name prop.
target: http://...
- "@type": OpenUri
name: Action's name prop
targets:
- os: default
uri: http://...
- start_group: true
title: This is the title of a **second section**
text: This second section is visually separated from the first one by setting its
**startGroup** property to true.
"""
RETURN = """
"""
# import module snippets
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
OFFICE_365_CARD_CONTEXT = "http://schema.org/extensions"
OFFICE_365_CARD_TYPE = "MessageCard"
OFFICE_365_CARD_EMPTY_PAYLOAD_MSG = "Summary or Text is required."
OFFICE_365_INVALID_WEBHOOK_MSG = "The Incoming Webhook was not reachable."
def build_actions(actions):
action_items = []
for action in actions:
action_item = snake_dict_to_camel_dict(action)
action_items.append(action_item)
return action_items
def build_sections(sections):
sections_created = []
for section in sections:
sections_created.append(build_section(section))
return sections_created
def build_section(section):
section_payload = dict()
if 'title' in section:
section_payload['title'] = section['title']
if 'start_group' in section:
section_payload['startGroup'] = section['start_group']
if 'activity_image' in section:
section_payload['activityImage'] = section['activity_image']
if 'activity_title' in section:
section_payload['activityTitle'] = section['activity_title']
if 'activity_subtitle' in section:
section_payload['activitySubtitle'] = section['activity_subtitle']
if 'activity_text' in section:
section_payload['activityText'] = section['activity_text']
if 'hero_image' in section:
section_payload['heroImage'] = section['hero_image']
if 'text' in section:
section_payload['text'] = section['text']
if 'facts' in section:
section_payload['facts'] = section['facts']
if 'images' in section:
section_payload['images'] = section['images']
if 'actions' in section:
section_payload['potentialAction'] = build_actions(section['actions'])
return section_payload
def build_payload_for_connector_card(module, summary=None, color=None, title=None, text=None, actions=None, sections=None):
payload = dict()
payload['@context'] = OFFICE_365_CARD_CONTEXT
payload['@type'] = OFFICE_365_CARD_TYPE
if summary is not None:
payload['summary'] = summary
if color is not None:
payload['themeColor'] = color
if title is not None:
payload['title'] = title
if text is not None:
payload['text'] = text
if actions:
payload['potentialAction'] = build_actions(actions)
if sections:
payload['sections'] = build_sections(sections)
payload = module.jsonify(payload)
return payload
def do_notify_connector_card_webhook(module, webhook, payload):
headers = {
'Content-Type': 'application/json'
}
response, info = fetch_url(
module=module,
url=webhook,
headers=headers,
method='POST',
data=payload
)
if info['status'] == 200:
module.exit_json(changed=True)
elif info['status'] == 400 and module.check_mode:
if info['body'] == OFFICE_365_CARD_EMPTY_PAYLOAD_MSG:
module.exit_json(changed=True)
else:
module.fail_json(msg=OFFICE_365_INVALID_WEBHOOK_MSG)
else:
module.fail_json(
msg="failed to send %s as a connector card to Incoming Webhook: %s"
% (payload, info['msg'])
)
def main():
module = AnsibleModule(
argument_spec=dict(
webhook=dict(required=True, no_log=True),
summary=dict(type='str'),
color=dict(type='str'),
title=dict(type='str'),
text=dict(type='str'),
actions=dict(type='list'),
sections=dict(type='list')
),
supports_check_mode=True
)
webhook = module.params['webhook']
summary = module.params['summary']
color = module.params['color']
title = module.params['title']
text = module.params['text']
actions = module.params['actions']
sections = module.params['sections']
payload = build_payload_for_connector_card(
module,
summary,
color,
title,
text,
actions,
sections)
if module.check_mode:
# In check mode, send an empty payload to validate connection
check_mode_payload = build_payload_for_connector_card(module)
do_notify_connector_card_webhook(module, webhook, check_mode_payload)
do_notify_connector_card_webhook(module, webhook, payload)
if __name__ == '__main__':
main()

View file

@ -0,0 +1 @@
say.py

View file

@ -0,0 +1,184 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
author: "Willy Barro (@willybarro)"
requirements: [ pushbullet.py ]
module: pushbullet
short_description: Sends notifications to Pushbullet
description:
- This module sends push notifications via Pushbullet to channels or devices.
options:
api_key:
description:
- Push bullet API token
required: true
channel:
description:
- The channel TAG you wish to broadcast a push notification,
as seen on the "My Channels" > "Edit your channel" at
Pushbullet page.
device:
description:
- The device NAME you wish to send a push notification,
as seen on the Pushbullet main page.
push_type:
description:
- Thing you wish to push.
default: note
choices: [ "note", "link" ]
title:
description:
- Title of the notification.
required: true
body:
description:
- Body of the notification, e.g. Details of the fault you're alerting.
notes:
- Requires pushbullet.py Python package on the remote host.
You can install it via pip with ($ pip install pushbullet.py).
See U(https://github.com/randomchars/pushbullet.py)
'''
EXAMPLES = '''
# Sends a push notification to a device
- pushbullet:
api_key: "ABC123abc123ABC123abc123ABC123ab"
device: "Chrome"
title: "You may see this on Google Chrome"
# Sends a link to a device
- pushbullet:
api_key: ABC123abc123ABC123abc123ABC123ab
device: Chrome
push_type: link
title: Ansible Documentation
body: https://docs.ansible.com/
# Sends a push notification to a channel
- pushbullet:
api_key: ABC123abc123ABC123abc123ABC123ab
channel: my-awesome-channel
title: Broadcasting a message to the #my-awesome-channel folks
# Sends a push notification with title and body to a channel
- pushbullet:
api_key: ABC123abc123ABC123abc123ABC123ab
channel: my-awesome-channel
title: ALERT! Signup service is down
body: Error rate on signup service is over 90% for more than 2 minutes
'''
import traceback
PUSHBULLET_IMP_ERR = None
try:
from pushbullet import PushBullet
from pushbullet.errors import InvalidKeyError, PushError
except ImportError:
PUSHBULLET_IMP_ERR = traceback.format_exc()
pushbullet_found = False
else:
pushbullet_found = True
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
# ===========================================
# Main
#
def main():
module = AnsibleModule(
argument_spec=dict(
api_key=dict(type='str', required=True, no_log=True),
channel=dict(type='str', default=None),
device=dict(type='str', default=None),
push_type=dict(type='str', default="note", choices=['note', 'link']),
title=dict(type='str', required=True),
body=dict(type='str', default=None),
url=dict(type='str', default=None),
),
mutually_exclusive=(
['channel', 'device'],
),
supports_check_mode=True
)
api_key = module.params['api_key']
channel = module.params['channel']
device = module.params['device']
push_type = module.params['push_type']
title = module.params['title']
body = module.params['body']
url = module.params['url']
if not pushbullet_found:
module.fail_json(msg=missing_required_lib('pushbullet.py'), exception=PUSHBULLET_IMP_ERR)
# Init pushbullet
try:
pb = PushBullet(api_key)
target = None
except InvalidKeyError:
module.fail_json(msg="Invalid api_key")
# Checks for channel/device
if device is None and channel is None:
module.fail_json(msg="You need to provide a channel or a device.")
# Search for given device
if device is not None:
devices_by_nickname = {}
for d in pb.devices:
devices_by_nickname[d.nickname] = d
if device in devices_by_nickname:
target = devices_by_nickname[device]
else:
module.fail_json(msg="Device '%s' not found. Available devices: '%s'" % (device, "', '".join(devices_by_nickname.keys())))
# Search for given channel
if channel is not None:
channels_by_tag = {}
for c in pb.channels:
channels_by_tag[c.channel_tag] = c
if channel in channels_by_tag:
target = channels_by_tag[channel]
else:
module.fail_json(msg="Channel '%s' not found. Available channels: '%s'" % (channel, "', '".join(channels_by_tag.keys())))
# If in check mode, exit saying that we succeeded
if module.check_mode:
module.exit_json(changed=False, msg="OK")
# Send push notification
try:
if push_type == "link":
target.push_link(title, url, body)
else:
target.push_note(title, body)
module.exit_json(changed=False, msg="OK")
except PushError as e:
module.fail_json(msg="An error occurred, Pushbullet's response: %s" % str(e))
module.fail_json(msg="An unknown error has occurred")
if __name__ == '__main__':
main()

View file

@ -0,0 +1,127 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2012, Jim Richardson <weaselkeeper@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: pushover
short_description: Send notifications via U(https://pushover.net)
description:
- Send notifications via pushover, to subscriber list of devices, and email
addresses. Requires pushover app on devices.
notes:
- You will require a pushover.net account to use this module. But no account
is required to receive messages.
options:
msg:
description:
- What message you wish to send.
required: true
app_token:
description:
- Pushover issued token identifying your pushover app.
required: true
user_key:
description:
- Pushover issued authentication key for your user.
required: true
title:
description:
- Message title.
required: false
pri:
description:
- Message priority (see U(https://pushover.net) for details).
required: false
author: "Jim Richardson (@weaselkeeper)"
'''
EXAMPLES = '''
- pushover:
msg: '{{ inventory_hostname }} is acting strange ...'
app_token: wxfdksl
user_key: baa5fe97f2c5ab3ca8f0bb59
delegate_to: localhost
- pushover:
title: 'Alert!'
msg: '{{ inventory_hostname }} has exploded in flames, It is now time to panic'
pri: 1
app_token: wxfdksl
user_key: baa5fe97f2c5ab3ca8f0bb59
delegate_to: localhost
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.urls import fetch_url
class Pushover(object):
''' Instantiates a pushover object, use it to send notifications '''
base_uri = 'https://api.pushover.net'
def __init__(self, module, user, token):
self.module = module
self.user = user
self.token = token
def run(self, priority, msg, title):
''' Do, whatever it is, we do. '''
url = '%s/1/messages.json' % (self.base_uri)
# parse config
options = dict(user=self.user,
token=self.token,
priority=priority,
message=msg)
if title is not None:
options = dict(options,
title=title)
data = urlencode(options)
headers = {"Content-type": "application/x-www-form-urlencoded"}
r, info = fetch_url(self.module, url, method='POST', data=data, headers=headers)
if info['status'] != 200:
raise Exception(info)
return r.read()
def main():
module = AnsibleModule(
argument_spec=dict(
title=dict(type='str'),
msg=dict(required=True),
app_token=dict(required=True, no_log=True),
user_key=dict(required=True, no_log=True),
pri=dict(required=False, default='0', choices=['-2', '-1', '0', '1', '2']),
),
)
msg_object = Pushover(module, module.params['user_key'], module.params['app_token'])
try:
response = msg_object.run(module.params['pri'], module.params['msg'], module.params['title'])
except Exception:
module.fail_json(msg='Unable to send msg via pushover')
module.exit_json(msg='message sent successfully: %s' % response, changed=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,209 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2018, John Imison <john+github@imison.net>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: rabbitmq_publish
short_description: Publish a message to a RabbitMQ queue.
description:
- Publish a message on a RabbitMQ queue using a blocking connection.
options:
url:
description:
- An URL connection string to connect to the RabbitMQ server.
- I(url) and I(host)/I(port)/I(user)/I(pass)/I(vhost) are mutually exclusive, use either or but not both.
proto:
description:
- The protocol to use.
choices: [amqps, amqp]
host:
description:
- The RabbitMQ server hostname or IP.
port:
description:
- The RabbitMQ server port.
username:
description:
- The RabbitMQ username.
password:
description:
- The RabbitMQ password.
vhost:
description:
- The virtual host to target.
- If default vhost is required, use C('%2F').
queue:
description:
- The queue to publish a message to. If no queue is specified, RabbitMQ will return a random queue name.
exchange:
description:
- The exchange to publish a message to.
routing_key:
description:
- The routing key.
body:
description:
- The body of the message.
- A C(body) cannot be provided if a C(src) is specified.
src:
description:
- A file to upload to the queue. Automatic mime type detection is attempted if content_type is not defined (left as default).
- A C(src) cannot be provided if a C(body) is specified.
- The filename is added to the headers of the posted message to RabbitMQ. Key being the C(filename), value is the filename.
aliases: ['file']
content_type:
description:
- The content type of the body.
default: text/plain
durable:
description:
- Set the queue to be durable.
default: False
type: bool
exclusive:
description:
- Set the queue to be exclusive.
default: False
type: bool
auto_delete:
description:
- Set the queue to auto delete.
default: False
type: bool
headers:
description:
- A dictionary of headers to post with the message.
default: {}
type: dict
cafile:
description:
- CA file used during connection to the RabbitMQ server over SSL.
- If this option is specified, also I(certfile) and I(keyfile) must be specified.
certfile:
description:
- Client certificate to establish SSL connection.
- If this option is specified, also I(cafile) and I(keyfile) must be specified.
keyfile:
description:
- Client key to establish SSL connection.
- If this option is specified, also I(cafile) and I(certfile) must be specified.
requirements: [ pika ]
notes:
- This module requires the pika python library U(https://pika.readthedocs.io/).
- Pika is a pure-Python implementation of the AMQP 0-9-1 protocol that tries to stay fairly independent of the underlying network support library.
- This module is tested against RabbitMQ. Other AMQP 0.9.1 protocol based servers may work but not tested/guaranteed.
- The certificate authentication was tested with certificates created
via U(https://www.rabbitmq.com/ssl.html#automated-certificate-generation) and RabbitMQ
configuration variables C(ssl_options.verify = verify_peer) & C(ssl_options.fail_if_no_peer_cert = true).
author: "John Imison (@Im0)"
'''
EXAMPLES = '''
- name: Publish a message to a queue with headers
rabbitmq_publish:
url: "amqp://guest:guest@192.168.0.32:5672/%2F"
queue: 'test'
body: "Hello world from ansible module rabbitmq_publish"
content_type: "text/plain"
headers:
myHeader: myHeaderValue
- name: Publish a file to a queue
rabbitmq_publish:
url: "amqp://guest:guest@192.168.0.32:5672/%2F"
queue: 'images'
file: 'path/to/logo.gif'
- name: RabbitMQ auto generated queue
rabbitmq_publish:
url: "amqp://guest:guest@192.168.0.32:5672/%2F"
body: "Hello world random queue from ansible module rabbitmq_publish"
content_type: "text/plain"
- name: Publish with certs
rabbitmq_publish:
url: "amqps://guest:guest@192.168.0.32:5671/%2F"
body: "Hello test queue from ansible module rabbitmq_publish via SSL certs"
queue: 'test'
content_type: "text/plain"
cafile: 'ca_certificate.pem'
certfile: 'client_certificate.pem'
keyfile: 'client_key.pem'
'''
RETURN = '''
result:
description:
- Contains the status I(msg), content type I(content_type) and the queue name I(queue).
returned: success
type: dict
sample: |
'result': { 'content_type': 'text/plain', 'msg': 'Successfully published to queue test', 'queue': 'test' }
'''
try:
import pika
HAS_PIKA = True
except ImportError:
HAS_PIKA = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native, to_text
from ansible_collections.community.general.plugins.module_utils.rabbitmq import RabbitClient
def main():
argument_spec = RabbitClient.rabbitmq_argument_spec()
argument_spec.update(
exchange=dict(type='str', default=''),
routing_key=dict(type='str', required=False),
body=dict(type='str', required=False),
src=dict(aliases=['file'], type='path', required=False),
content_type=dict(default="text/plain", type='str'),
durable=dict(default=False, type='bool'),
exclusive=dict(default=False, type='bool'),
auto_delete=dict(default=False, type='bool'),
headers=dict(default={}, type='dict'),
cafile=dict(type='str', required=False),
certfile=dict(type='str', required=False),
keyfile=dict(type='str', required=False),
)
module = AnsibleModule(
argument_spec=argument_spec,
mutually_exclusive=[['body', 'src']],
required_together=[['cafile', 'certfile', 'keyfile']],
supports_check_mode=False
)
rabbitmq = RabbitClient(module)
if rabbitmq.basic_publish():
rabbitmq.close_connection()
module.exit_json(changed=True, result={"msg": "Successfully published to queue %s" % rabbitmq.queue,
"queue": rabbitmq.queue,
"content_type": rabbitmq.content_type})
else:
rabbitmq.close_connection()
module.fail_json(changed=False, msg="Unsuccessful publishing to queue %s" % rabbitmq.queue)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,235 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2016, Deepak Kothandan <deepak.kothandan@outlook.com>
# (c) 2015, Stefan Berggren <nsg@nsg.cc>
# (c) 2014, Ramon de la Fuente <ramon@delafuente.nl>
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
module: rocketchat
short_description: Send notifications to Rocket Chat
description:
- The C(rocketchat) module sends notifications to Rocket Chat via the Incoming WebHook integration
author: "Ramon de la Fuente (@ramondelafuente)"
options:
domain:
description:
- The domain for your environment without protocol. (i.e.
C(example.com) or C(chat.example.com))
required: true
token:
description:
- Rocket Chat Incoming Webhook integration token. This provides
authentication to Rocket Chat's Incoming webhook for posting
messages.
required: true
protocol:
description:
- Specify the protocol used to send notification messages before the webhook url. (i.e. http or https)
default: https
choices:
- 'http'
- 'https'
msg:
description:
- Message to be sent.
channel:
description:
- Channel to send the message to. If absent, the message goes to the channel selected for the I(token)
specified during the creation of webhook.
username:
description:
- This is the sender of the message.
default: "Ansible"
icon_url:
description:
- URL for the message sender's icon.
default: "https://www.ansible.com/favicon.ico"
icon_emoji:
description:
- Emoji for the message sender. The representation for the available emojis can be
got from Rocket Chat. (for example :thumbsup:) (if I(icon_emoji) is set, I(icon_url) will not be used)
link_names:
description:
- Automatically create links for channels and usernames in I(msg).
default: 1
choices:
- 1
- 0
validate_certs:
description:
- If C(no), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: 'yes'
color:
description:
- Allow text to use default colors - use the default of 'normal' to not send a custom color bar at the start of the message
default: 'normal'
choices:
- 'normal'
- 'good'
- 'warning'
- 'danger'
attachments:
description:
- Define a list of attachments.
'''
EXAMPLES = """
- name: Send notification message via Rocket Chat
rocketchat:
token: thetoken/generatedby/rocketchat
domain: chat.example.com
msg: '{{ inventory_hostname }} completed'
delegate_to: localhost
- name: Send notification message via Rocket Chat all options
rocketchat:
domain: chat.example.com
token: thetoken/generatedby/rocketchat
msg: '{{ inventory_hostname }} completed'
channel: #ansible
username: 'Ansible on {{ inventory_hostname }}'
icon_url: http://www.example.com/some-image-file.png
link_names: 0
delegate_to: localhost
- name: insert a color bar in front of the message for visibility purposes and use the default webhook icon and name configured in rocketchat
rocketchat:
token: thetoken/generatedby/rocketchat
domain: chat.example.com
msg: '{{ inventory_hostname }} is alive!'
color: good
username: ''
icon_url: ''
delegate_to: localhost
- name: Use the attachments API
rocketchat:
token: thetoken/generatedby/rocketchat
domain: chat.example.com
attachments:
- text: Display my system load on host A and B
color: #ff00dd
title: System load
fields:
- title: System A
value: 'load average: 0,74, 0,66, 0,63'
short: True
- title: System B
value: 'load average: 5,16, 4,64, 2,43'
short: True
delegate_to: localhost
"""
RETURN = """
changed:
description: A flag indicating if any change was made or not.
returned: success
type: bool
sample: false
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
ROCKETCHAT_INCOMING_WEBHOOK = '%s://%s/hooks/%s'
def build_payload_for_rocketchat(module, text, channel, username, icon_url, icon_emoji, link_names, color, attachments):
payload = {}
if color == "normal" and text is not None:
payload = dict(text=text)
elif text is not None:
payload = dict(attachments=[dict(text=text, color=color)])
if channel is not None:
if (channel[0] == '#') or (channel[0] == '@'):
payload['channel'] = channel
else:
payload['channel'] = '#' + channel
if username is not None:
payload['username'] = username
if icon_emoji is not None:
payload['icon_emoji'] = icon_emoji
else:
payload['icon_url'] = icon_url
if link_names is not None:
payload['link_names'] = link_names
if attachments is not None:
if 'attachments' not in payload:
payload['attachments'] = []
if attachments is not None:
for attachment in attachments:
if 'fallback' not in attachment:
attachment['fallback'] = attachment['text']
payload['attachments'].append(attachment)
payload = "payload=" + module.jsonify(payload)
return payload
def do_notify_rocketchat(module, domain, token, protocol, payload):
if token.count('/') < 1:
module.fail_json(msg="Invalid Token specified, provide a valid token")
rocketchat_incoming_webhook = ROCKETCHAT_INCOMING_WEBHOOK % (protocol, domain, token)
response, info = fetch_url(module, rocketchat_incoming_webhook, data=payload)
if info['status'] != 200:
module.fail_json(msg="failed to send message, return status=%s" % str(info['status']))
def main():
module = AnsibleModule(
argument_spec=dict(
domain=dict(type='str', required=True, default=None),
token=dict(type='str', required=True, no_log=True),
protocol=dict(type='str', default='https', choices=['http', 'https']),
msg=dict(type='str', required=False, default=None),
channel=dict(type='str', default=None),
username=dict(type='str', default='Ansible'),
icon_url=dict(type='str', default='https://www.ansible.com/favicon.ico'),
icon_emoji=dict(type='str', default=None),
link_names=dict(type='int', default=1, choices=[0, 1]),
validate_certs=dict(default='yes', type='bool'),
color=dict(type='str', default='normal', choices=['normal', 'good', 'warning', 'danger']),
attachments=dict(type='list', required=False, default=None)
)
)
domain = module.params['domain']
token = module.params['token']
protocol = module.params['protocol']
text = module.params['msg']
channel = module.params['channel']
username = module.params['username']
icon_url = module.params['icon_url']
icon_emoji = module.params['icon_emoji']
link_names = module.params['link_names']
color = module.params['color']
attachments = module.params['attachments']
payload = build_payload_for_rocketchat(module, text, channel, username, icon_url, icon_emoji, link_names, color, attachments)
do_notify_rocketchat(module, domain, token, protocol, payload)
module.exit_json(msg="OK")
if __name__ == '__main__':
main()

View file

@ -0,0 +1,93 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2013, Michael DeHaan <michael@ansible.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: say
short_description: Makes a computer to speak.
description:
- makes a computer speak! Amuse your friends, annoy your coworkers!
notes:
- In 2.5, this module has been renamed from C(osx_say) to M(say).
- If you like this module, you may also be interested in the osx_say callback plugin.
- A list of available voices, with language, can be found by running C(say -v ?) on a OSX host and C(espeak --voices) on a Linux host.
options:
msg:
description:
What to say
required: true
voice:
description:
What voice to use
required: false
requirements: [ say or espeak or espeak-ng ]
author:
- "Ansible Core Team"
- "Michael DeHaan (@mpdehaan)"
'''
EXAMPLES = '''
- say:
msg: '{{ inventory_hostname }} is all done'
voice: Zarvox
delegate_to: localhost
'''
import platform
from ansible.module_utils.basic import AnsibleModule
def say(module, executable, msg, voice):
cmd = [executable, msg]
if voice:
cmd.extend(('-v', voice))
module.run_command(cmd, check_rc=True)
def main():
module = AnsibleModule(
argument_spec=dict(
msg=dict(required=True),
voice=dict(required=False),
),
supports_check_mode=True
)
msg = module.params['msg']
voice = module.params['voice']
possibles = ('say', 'espeak', 'espeak-ng')
if platform.system() != 'Darwin':
# 'say' binary available, it might be GNUstep tool which doesn't support 'voice' parameter
voice = None
for possible in possibles:
executable = module.get_bin_path(possible)
if executable:
break
else:
module.fail_json(msg='Unable to find either %s' % ', '.join(possibles))
if module.check_mode:
module.exit_json(msg=msg, changed=False)
say(module, executable, msg, voice)
module.exit_json(msg=msg, changed=True)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,252 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2015, Matt Makai <matthew.makai@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: sendgrid
short_description: Sends an email with the SendGrid API
description:
- "Sends an email with a SendGrid account through their API, not through
the SMTP service."
notes:
- "This module is non-idempotent because it sends an email through the
external API. It is idempotent only in the case that the module fails."
- "Like the other notification modules, this one requires an external
dependency to work. In this case, you'll need an active SendGrid
account."
- "In order to use api_key, cc, bcc, attachments, from_name, html_body, headers
you must pip install sendgrid"
- "since 2.2 username and password are not required if you supply an api_key"
requirements:
- sendgrid python library
options:
username:
description:
- username for logging into the SendGrid account.
- Since 2.2 it is only required if api_key is not supplied.
password:
description:
- password that corresponds to the username
- Since 2.2 it is only required if api_key is not supplied.
from_address:
description:
- the address in the "from" field for the email
required: true
to_addresses:
description:
- a list with one or more recipient email addresses
required: true
subject:
description:
- the desired subject for the email
required: true
api_key:
description:
- sendgrid API key to use instead of username/password
cc:
description:
- a list of email addresses to cc
bcc:
description:
- a list of email addresses to bcc
attachments:
description:
- a list of relative or explicit paths of files you want to attach (7MB limit as per SendGrid docs)
from_name:
description:
- the name you want to appear in the from field, i.e 'John Doe'
html_body:
description:
- whether the body is html content that should be rendered
type: bool
default: 'no'
headers:
description:
- a dict to pass on as headers
author: "Matt Makai (@makaimc)"
'''
EXAMPLES = '''
# send an email to a single recipient that the deployment was successful
- sendgrid:
username: "{{ sendgrid_username }}"
password: "{{ sendgrid_password }}"
from_address: "ansible@mycompany.com"
to_addresses:
- "ops@mycompany.com"
subject: "Deployment success."
body: "The most recent Ansible deployment was successful."
delegate_to: localhost
# send an email to more than one recipient that the build failed
- sendgrid:
username: "{{ sendgrid_username }}"
password: "{{ sendgrid_password }}"
from_address: "build@mycompany.com"
to_addresses:
- "ops@mycompany.com"
- "devteam@mycompany.com"
subject: "Build failure!."
body: "Unable to pull source repository from Git server."
delegate_to: localhost
'''
# =======================================
# sendgrid module support methods
#
import os
import traceback
SENDGRID_IMP_ERR = None
try:
import sendgrid
HAS_SENDGRID = True
except ImportError:
SENDGRID_IMP_ERR = traceback.format_exc()
HAS_SENDGRID = False
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils._text import to_bytes
from ansible.module_utils.urls import fetch_url
def post_sendgrid_api(module, username, password, from_address, to_addresses,
subject, body, api_key=None, cc=None, bcc=None, attachments=None,
html_body=False, from_name=None, headers=None):
if not HAS_SENDGRID:
SENDGRID_URI = "https://api.sendgrid.com/api/mail.send.json"
AGENT = "Ansible"
data = {'api_user': username, 'api_key': password,
'from': from_address, 'subject': subject, 'text': body}
encoded_data = urlencode(data)
to_addresses_api = ''
for recipient in to_addresses:
recipient = to_bytes(recipient, errors='surrogate_or_strict')
to_addresses_api += '&to[]=%s' % recipient
encoded_data += to_addresses_api
headers = {'User-Agent': AGENT,
'Content-type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'}
return fetch_url(module, SENDGRID_URI, data=encoded_data, headers=headers, method='POST')
else:
if api_key:
sg = sendgrid.SendGridClient(api_key)
else:
sg = sendgrid.SendGridClient(username, password)
message = sendgrid.Mail()
message.set_subject(subject)
for recip in to_addresses:
message.add_to(recip)
if cc:
for recip in cc:
message.add_cc(recip)
if bcc:
for recip in bcc:
message.add_bcc(recip)
if headers:
message.set_headers(headers)
if attachments:
for f in attachments:
name = os.path.basename(f)
message.add_attachment(name, f)
if from_name:
message.set_from('%s <%s.' % (from_name, from_address))
else:
message.set_from(from_address)
if html_body:
message.set_html(body)
else:
message.set_text(body)
return sg.send(message)
# =======================================
# Main
#
def main():
module = AnsibleModule(
argument_spec=dict(
username=dict(required=False),
password=dict(required=False, no_log=True),
api_key=dict(required=False, no_log=True),
bcc=dict(required=False, type='list'),
cc=dict(required=False, type='list'),
headers=dict(required=False, type='dict'),
from_address=dict(required=True),
from_name=dict(required=False),
to_addresses=dict(required=True, type='list'),
subject=dict(required=True),
body=dict(required=True),
html_body=dict(required=False, default=False, type='bool'),
attachments=dict(required=False, type='list')
),
supports_check_mode=True,
mutually_exclusive=[
['api_key', 'password'],
['api_key', 'username']
],
required_together=[['username', 'password']],
)
username = module.params['username']
password = module.params['password']
api_key = module.params['api_key']
bcc = module.params['bcc']
cc = module.params['cc']
headers = module.params['headers']
from_name = module.params['from_name']
from_address = module.params['from_address']
to_addresses = module.params['to_addresses']
subject = module.params['subject']
body = module.params['body']
html_body = module.params['html_body']
attachments = module.params['attachments']
sendgrid_lib_args = [api_key, bcc, cc, headers, from_name, html_body, attachments]
if any(lib_arg is not None for lib_arg in sendgrid_lib_args) and not HAS_SENDGRID:
reason = 'when using any of the following arguments: ' \
'api_key, bcc, cc, headers, from_name, html_body, attachments'
module.fail_json(msg=missing_required_lib('sendgrid', reason=reason),
exception=SENDGRID_IMP_ERR)
response, info = post_sendgrid_api(module, username, password,
from_address, to_addresses, subject, body, attachments=attachments,
bcc=bcc, cc=cc, headers=headers, html_body=html_body, api_key=api_key)
if not HAS_SENDGRID:
if info['status'] != 200:
module.fail_json(msg="unable to send email through SendGrid API: %s" % info['msg'])
else:
if response != 200:
module.fail_json(msg="unable to send email through SendGrid API: %s" % info['message'])
module.exit_json(msg=subject, changed=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,308 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Steve Pletcher <steve@steve-pletcher.com>
# (c) 2016, René Moser <mail@renemoser.net>
# (c) 2015, Stefan Berggren <nsg@nsg.cc>
# (c) 2014, Ramon de la Fuente <ramon@delafuente.nl>
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}
DOCUMENTATION = '''
module: slack
short_description: Send Slack notifications
description:
- The C(slack) module sends notifications to U(http://slack.com) via the Incoming WebHook integration
author: "Ramon de la Fuente (@ramondelafuente)"
options:
domain:
description:
- Slack (sub)domain for your environment without protocol. (i.e.
C(example.slack.com)) In 1.8 and beyond, this is deprecated and may
be ignored. See token documentation for information.
token:
description:
- Slack integration token. This authenticates you to the slack service.
Prior to 1.8, a token looked like C(3Ffe373sfhRE6y42Fg3rvf4GlK). In
1.8 and above, ansible adapts to the new slack API where tokens look
like C(G922VJP24/D921DW937/3Ffe373sfhRE6y42Fg3rvf4GlK). If tokens
are in the new format then slack will ignore any value of domain. If
the token is in the old format the domain is required. Ansible has no
control of when slack will get rid of the old API. When slack does
that the old format will stop working. ** Please keep in mind the tokens
are not the API tokens but are the webhook tokens. In slack these are
found in the webhook URL which are obtained under the apps and integrations.
The incoming webhooks can be added in that area. In some cases this may
be locked by your Slack admin and you must request access. It is there
that the incoming webhooks can be added. The key is on the end of the
URL given to you in that section.
required: true
msg:
description:
- Message to send. Note that the module does not handle escaping characters.
Plain-text angle brackets and ampersands should be converted to HTML entities (e.g. & to &amp;) before sending.
See Slack's documentation (U(https://api.slack.com/docs/message-formatting)) for more.
channel:
description:
- Channel to send the message to. If absent, the message goes to the channel selected for the I(token).
thread_id:
description:
- Optional. Timestamp of message to thread this message to as a float. https://api.slack.com/docs/message-threading
username:
description:
- This is the sender of the message.
default: "Ansible"
icon_url:
description:
- Url for the message sender's icon (default C(https://www.ansible.com/favicon.ico))
icon_emoji:
description:
- Emoji for the message sender. See Slack documentation for options.
(if I(icon_emoji) is set, I(icon_url) will not be used)
link_names:
description:
- Automatically create links for channels and usernames in I(msg).
default: 1
choices:
- 1
- 0
parse:
description:
- Setting for the message parser at Slack
choices:
- 'full'
- 'none'
validate_certs:
description:
- If C(no), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: 'yes'
color:
description:
- Allow text to use default colors - use the default of 'normal' to not send a custom color bar at the start of the message.
- Allowed values for color can be one of 'normal', 'good', 'warning', 'danger', any valid 3 digit or 6 digit hex color value.
- Specifying value in hex is supported from version 2.8.
default: 'normal'
attachments:
description:
- Define a list of attachments. This list mirrors the Slack JSON API.
- For more information, see also in the (U(https://api.slack.com/docs/attachments)).
'''
EXAMPLES = """
- name: Send notification message via Slack
slack:
token: thetoken/generatedby/slack
msg: '{{ inventory_hostname }} completed'
delegate_to: localhost
- name: Send notification message via Slack all options
slack:
token: thetoken/generatedby/slack
msg: '{{ inventory_hostname }} completed'
channel: '#ansible'
thread_id: 1539917263.000100
username: 'Ansible on {{ inventory_hostname }}'
icon_url: http://www.example.com/some-image-file.png
link_names: 0
parse: 'none'
delegate_to: localhost
- name: insert a color bar in front of the message for visibility purposes and use the default webhook icon and name configured in Slack
slack:
token: thetoken/generatedby/slack
msg: '{{ inventory_hostname }} is alive!'
color: good
username: ''
icon_url: ''
- name: insert a color bar in front of the message with valid hex color value
slack:
token: thetoken/generatedby/slack
msg: 'This message uses color in hex value'
color: '#00aacc'
username: ''
icon_url: ''
- name: Use the attachments API
slack:
token: thetoken/generatedby/slack
attachments:
- text: Display my system load on host A and B
color: '#ff00dd'
title: System load
fields:
- title: System A
value: "load average: 0,74, 0,66, 0,63"
short: True
- title: System B
value: 'load average: 5,16, 4,64, 2,43'
short: True
- name: Send a message with a link using Slack markup
slack:
token: thetoken/generatedby/slack
msg: We sent this message using <https://www.ansible.com|Ansible>!
- name: Send a message with angle brackets and ampersands
slack:
token: thetoken/generatedby/slack
msg: This message has &lt;brackets&gt; &amp; ampersands in plain text.
"""
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
OLD_SLACK_INCOMING_WEBHOOK = 'https://%s/services/hooks/incoming-webhook?token=%s'
SLACK_INCOMING_WEBHOOK = 'https://hooks.slack.com/services/%s'
# Escaping quotes and apostrophes to avoid ending string prematurely in ansible call.
# We do not escape other characters used as Slack metacharacters (e.g. &, <, >).
escape_table = {
'"': "\"",
"'": "\'",
}
def is_valid_hex_color(color_choice):
if re.match(r'^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$', color_choice):
return True
return False
def escape_quotes(text):
'''Backslash any quotes within text.'''
return "".join(escape_table.get(c, c) for c in text)
def build_payload_for_slack(module, text, channel, thread_id, username, icon_url, icon_emoji, link_names,
parse, color, attachments):
payload = {}
if color == "normal" and text is not None:
payload = dict(text=escape_quotes(text))
elif text is not None:
# With a custom color we have to set the message as attachment, and explicitly turn markdown parsing on for it.
payload = dict(attachments=[dict(text=escape_quotes(text), color=color, mrkdwn_in=["text"])])
if channel is not None:
if (channel[0] == '#') or (channel[0] == '@'):
payload['channel'] = channel
else:
payload['channel'] = '#' + channel
if thread_id is not None:
payload['thread_ts'] = thread_id
if username is not None:
payload['username'] = username
if icon_emoji is not None:
payload['icon_emoji'] = icon_emoji
else:
payload['icon_url'] = icon_url
if link_names is not None:
payload['link_names'] = link_names
if parse is not None:
payload['parse'] = parse
if attachments is not None:
if 'attachments' not in payload:
payload['attachments'] = []
if attachments is not None:
keys_to_escape = [
'title',
'text',
'author_name',
'pretext',
'fallback',
]
for attachment in attachments:
for key in keys_to_escape:
if key in attachment:
attachment[key] = escape_quotes(attachment[key])
if 'fallback' not in attachment:
attachment['fallback'] = attachment['text']
payload['attachments'].append(attachment)
payload = module.jsonify(payload)
return payload
def do_notify_slack(module, domain, token, payload):
if token.count('/') >= 2:
# New style token
slack_incoming_webhook = SLACK_INCOMING_WEBHOOK % (token)
else:
if not domain:
module.fail_json(msg="Slack has updated its webhook API. You need to specify a token of the form "
"XXXX/YYYY/ZZZZ in your playbook")
slack_incoming_webhook = OLD_SLACK_INCOMING_WEBHOOK % (domain, token)
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
}
response, info = fetch_url(module=module, url=slack_incoming_webhook, headers=headers, method='POST', data=payload)
if info['status'] != 200:
obscured_incoming_webhook = SLACK_INCOMING_WEBHOOK % ('[obscured]')
module.fail_json(msg=" failed to send %s to %s: %s" % (payload, obscured_incoming_webhook, info['msg']))
def main():
module = AnsibleModule(
argument_spec=dict(
domain=dict(type='str', required=False, default=None),
token=dict(type='str', required=True, no_log=True),
msg=dict(type='str', required=False, default=None),
channel=dict(type='str', default=None),
thread_id=dict(type='float', default=None),
username=dict(type='str', default='Ansible'),
icon_url=dict(type='str', default='https://www.ansible.com/favicon.ico'),
icon_emoji=dict(type='str', default=None),
link_names=dict(type='int', default=1, choices=[0, 1]),
parse=dict(type='str', default=None, choices=['none', 'full']),
validate_certs=dict(default='yes', type='bool'),
color=dict(type='str', default='normal'),
attachments=dict(type='list', required=False, default=None)
)
)
domain = module.params['domain']
token = module.params['token']
text = module.params['msg']
channel = module.params['channel']
thread_id = module.params['thread_id']
username = module.params['username']
icon_url = module.params['icon_url']
icon_emoji = module.params['icon_emoji']
link_names = module.params['link_names']
parse = module.params['parse']
color = module.params['color']
attachments = module.params['attachments']
color_choices = ['normal', 'good', 'warning', 'danger']
if color not in color_choices and not is_valid_hex_color(color):
module.fail_json(msg="Color value specified should be either one of %r "
"or any valid hex value with length 3 or 6." % color_choices)
payload = build_payload_for_slack(module, text, channel, thread_id, username, icon_url, icon_emoji, link_names,
parse, color, attachments)
do_notify_slack(module, domain, token, payload)
module.exit_json(msg="OK")
if __name__ == '__main__':
main()

View file

@ -0,0 +1,167 @@
#!/usr/bin/python
# Copyright (c) 2017 Tim Rightnour <thegarbledone@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: syslogger
short_description: Log messages in the syslog
description:
- "Uses syslog to add log entries to the host."
- "Can specify facility and priority."
options:
msg:
description:
- This is the message to place in syslog
required: true
priority:
description:
- Set the log priority
choices: [ "emerg", "alert", "crit", "err", "warning", "notice", "info", "debug" ]
required: false
default: "info"
facility:
description:
- Set the log facility
choices: [ "kern", "user", "mail", "daemon", "auth", "lpr", "news",
"uucp", "cron", "syslog", "local0", "local1", "local2",
"local3", "local4", "local5", "local6", "local7" ]
required: false
default: "daemon"
log_pid:
description:
- Log the pid in brackets
type: bool
required: false
default: "no"
author:
- Tim Rightnour (@garbled1)
'''
EXAMPLES = '''
# Full example
- name: Test syslog
syslogger:
msg: "Hello from ansible"
priority: "err"
facility: "daemon"
log_pid: true
# Basic usage
- name: Simple Usage
syslogger:
msg: "I will end up as daemon.info"
'''
RETURN = '''
'''
from ansible.module_utils.basic import AnsibleModule
import syslog
def get_facility(x):
return {
'kern': syslog.LOG_KERN,
'user': syslog.LOG_USER,
'mail': syslog.LOG_MAIL,
'daemon': syslog.LOG_DAEMON,
'auth': syslog.LOG_AUTH,
'lpr': syslog.LOG_LPR,
'news': syslog.LOG_NEWS,
'uucp': syslog.LOG_UUCP,
'cron': syslog.LOG_CRON,
'syslog': syslog.LOG_SYSLOG,
'local0': syslog.LOG_LOCAL0,
'local1': syslog.LOG_LOCAL1,
'local2': syslog.LOG_LOCAL2,
'local3': syslog.LOG_LOCAL3,
'local4': syslog.LOG_LOCAL4,
'local5': syslog.LOG_LOCAL5,
'local6': syslog.LOG_LOCAL6,
'local7': syslog.LOG_LOCAL7
}.get(x, syslog.LOG_DAEMON)
def get_priority(x):
return {
'emerg': syslog.LOG_EMERG,
'alert': syslog.LOG_ALERT,
'crit': syslog.LOG_CRIT,
'err': syslog.LOG_ERR,
'warning': syslog.LOG_WARNING,
'notice': syslog.LOG_NOTICE,
'info': syslog.LOG_INFO,
'debug': syslog.LOG_DEBUG
}.get(x, syslog.LOG_INFO)
def run_module():
# define the available arguments/parameters that a user can pass to
# the module
module_args = dict(
msg=dict(type='str', required=True),
priority=dict(type='str', required=False,
choices=["emerg", "alert", "crit", "err", "warning",
"notice", "info", "debug"],
default='info'),
facility=dict(type='str', required=False,
choices=["kern", "user", "mail", "daemon", "auth",
"lpr", "news", "uucp", "cron", "syslog",
"local0", "local1", "local2", "local3",
"local4", "local5", "local6", "local7"],
default='daemon'),
log_pid=dict(type='bool', required=False, default=False)
)
module = AnsibleModule(
argument_spec=module_args,
)
result = dict(
changed=False,
priority=module.params['priority'],
facility=module.params['facility'],
log_pid=module.params['log_pid'],
msg=module.params['msg']
)
# do the logging
try:
if module.params['log_pid']:
syslog.openlog('ansible_syslogger',
logoption=syslog.LOG_PID,
facility=get_facility(module.params['facility']))
else:
syslog.openlog('ansible_syslogger',
facility=get_facility(module.params['facility']))
syslog.syslog(get_priority(module.params['priority']),
module.params['msg'])
syslog.closelog()
result['changed'] = True
except Exception:
module.fail_json(error='Failed to write to syslog', **result)
module.exit_json(**result)
def main():
run_module()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,115 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2016, Artem Feofanov <artem.feofanov@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
module: telegram
author: "Artem Feofanov (@tyouxa)"
short_description: module for sending notifications via telegram
description:
- Send notifications via telegram bot, to a verified group or user
notes:
- You will require a telegram account and create telegram bot to use this module.
options:
msg:
description:
- What message you wish to send.
required: true
msg_format:
description:
- Message format. Formatting options `markdown` and `html` described in
Telegram API docs (https://core.telegram.org/bots/api#formatting-options).
If option `plain` set, message will not be formatted.
default: plain
choices: [ "plain", "markdown", "html" ]
token:
description:
- Token identifying your telegram bot.
required: true
chat_id:
description:
- Telegram group or user chat_id
required: true
'''
EXAMPLES = """
- name: send a message to chat in playbook
telegram:
token: '9999999:XXXXXXXXXXXXXXXXXXXXXXX'
chat_id: 000000
msg: Ansible task finished
"""
RETURN = """
msg:
description: The message you attempted to send
returned: success
type: str
sample: "Ansible task finished"
telegram_error:
description: Error message gotten from Telegram API
returned: failure
type: str
sample: "Bad Request: message text is empty"
"""
import json
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import quote
from ansible.module_utils.urls import fetch_url
def main():
module = AnsibleModule(
argument_spec=dict(
token=dict(type='str', required=True, no_log=True),
chat_id=dict(type='str', required=True, no_log=True),
msg_format=dict(type='str', required=False, default='plain',
choices=['plain', 'markdown', 'html']),
msg=dict(type='str', required=True)),
supports_check_mode=True
)
token = quote(module.params.get('token'))
chat_id = quote(module.params.get('chat_id'))
msg_format = quote(module.params.get('msg_format'))
msg = quote(module.params.get('msg'))
url = 'https://api.telegram.org/bot' + token + \
'/sendMessage?text=' + msg + '&chat_id=' + chat_id
if msg_format in ('markdown', 'html'):
url += '&parse_mode=' + msg_format
if module.check_mode:
module.exit_json(changed=False)
response, info = fetch_url(module, url)
if info['status'] == 200:
module.exit_json(changed=True)
else:
body = json.loads(info['body'])
module.fail_json(msg="failed to send message, return status=%s" % str(info['status']),
telegram_error=body['description'])
if __name__ == '__main__':
main()

View file

@ -0,0 +1,169 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2015, Matt Makai <matthew.makai@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: twilio
short_description: Sends a text message to a mobile phone through Twilio.
description:
- Sends a text message to a phone number through the Twilio messaging API.
notes:
- This module is non-idempotent because it sends an email through the
external API. It is idempotent only in the case that the module fails.
- Like the other notification modules, this one requires an external
dependency to work. In this case, you'll need a Twilio account with
a purchased or verified phone number to send the text message.
options:
account_sid:
description:
user's Twilio account token found on the account page
required: true
auth_token:
description: user's Twilio authentication token
required: true
msg:
description:
the body of the text message
required: true
to_numbers:
description:
one or more phone numbers to send the text message to,
format +15551112222
required: true
aliases: [ to_number ]
from_number:
description:
the Twilio number to send the text message from, format +15551112222
required: true
media_url:
description:
a URL with a picture, video or sound clip to send with an MMS
(multimedia message) instead of a plain SMS
required: false
author: "Matt Makai (@makaimc)"
'''
EXAMPLES = '''
# send an SMS about the build status to (555) 303 5681
# note: replace account_sid and auth_token values with your credentials
# and you have to have the 'from_number' on your Twilio account
- twilio:
msg: All servers with webserver role are now configured.
account_sid: ACXXXXXXXXXXXXXXXXX
auth_token: ACXXXXXXXXXXXXXXXXX
from_number: +15552014545
to_number: +15553035681
delegate_to: localhost
# send an SMS to multiple phone numbers about the deployment
# note: replace account_sid and auth_token values with your credentials
# and you have to have the 'from_number' on your Twilio account
- twilio:
msg: This server configuration is now complete.
account_sid: ACXXXXXXXXXXXXXXXXX
auth_token: ACXXXXXXXXXXXXXXXXX
from_number: +15553258899
to_numbers:
- +15551113232
- +12025551235
- +19735559010
delegate_to: localhost
# send an MMS to a single recipient with an update on the deployment
# and an image of the results
# note: replace account_sid and auth_token values with your credentials
# and you have to have the 'from_number' on your Twilio account
- twilio:
msg: Deployment complete!
account_sid: ACXXXXXXXXXXXXXXXXX
auth_token: ACXXXXXXXXXXXXXXXXX
from_number: +15552014545
to_number: +15553035681
media_url: https://demo.twilio.com/logo.png
delegate_to: localhost
'''
# =======================================
# twilio module support methods
#
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.urls import fetch_url
def post_twilio_api(module, account_sid, auth_token, msg, from_number,
to_number, media_url=None):
URI = "https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json" \
% (account_sid,)
AGENT = "Ansible"
data = {'From': from_number, 'To': to_number, 'Body': msg}
if media_url:
data['MediaUrl'] = media_url
encoded_data = urlencode(data)
headers = {'User-Agent': AGENT,
'Content-type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
}
# Hack module params to have the Basic auth params that fetch_url expects
module.params['url_username'] = account_sid.replace('\n', '')
module.params['url_password'] = auth_token.replace('\n', '')
return fetch_url(module, URI, data=encoded_data, headers=headers)
# =======================================
# Main
#
def main():
module = AnsibleModule(
argument_spec=dict(
account_sid=dict(required=True),
auth_token=dict(required=True, no_log=True),
msg=dict(required=True),
from_number=dict(required=True),
to_numbers=dict(required=True, aliases=['to_number'], type='list'),
media_url=dict(default=None, required=False),
),
supports_check_mode=True
)
account_sid = module.params['account_sid']
auth_token = module.params['auth_token']
msg = module.params['msg']
from_number = module.params['from_number']
to_numbers = module.params['to_numbers']
media_url = module.params['media_url']
for number in to_numbers:
r, info = post_twilio_api(module, account_sid, auth_token, msg,
from_number, number, media_url)
if info['status'] not in [200, 201]:
body_message = "unknown error"
if 'body' in info:
body = module.from_json(info['body'])
body_message = body['message']
module.fail_json(msg="unable to send message to %s: %s" % (number, body_message))
module.exit_json(msg=msg, changed=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,128 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: typetalk
short_description: Send a message to typetalk
description:
- Send a message to typetalk using typetalk API
options:
client_id:
description:
- OAuth2 client ID
required: true
client_secret:
description:
- OAuth2 client secret
required: true
topic:
description:
- topic id to post message
required: true
msg:
description:
- message body
required: true
requirements: [ json ]
author: "Takashi Someda (@tksmd)"
'''
EXAMPLES = '''
- typetalk:
client_id: 12345
client_secret: 12345
topic: 1
msg: install completed
'''
import json
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.urls import fetch_url, ConnectionError
def do_request(module, url, params, headers=None):
data = urlencode(params)
if headers is None:
headers = dict()
headers = dict(headers, **{
'User-Agent': 'Ansible/typetalk module',
})
r, info = fetch_url(module, url, data=data, headers=headers)
if info['status'] != 200:
exc = ConnectionError(info['msg'])
exc.code = info['status']
raise exc
return r
def get_access_token(module, client_id, client_secret):
params = {
'client_id': client_id,
'client_secret': client_secret,
'grant_type': 'client_credentials',
'scope': 'topic.post'
}
res = do_request(module, 'https://typetalk.com/oauth2/access_token', params)
return json.load(res)['access_token']
def send_message(module, client_id, client_secret, topic, msg):
"""
send message to typetalk
"""
try:
access_token = get_access_token(module, client_id, client_secret)
url = 'https://typetalk.com/api/v1/topics/%d' % topic
headers = {
'Authorization': 'Bearer %s' % access_token,
}
do_request(module, url, {'message': msg}, headers)
return True, {'access_token': access_token}
except ConnectionError as e:
return False, e
def main():
module = AnsibleModule(
argument_spec=dict(
client_id=dict(required=True),
client_secret=dict(required=True, no_log=True),
topic=dict(required=True, type='int'),
msg=dict(required=True),
),
supports_check_mode=False
)
if not json:
module.fail_json(msg="json module is required")
client_id = module.params["client_id"]
client_secret = module.params["client_secret"]
topic = module.params["topic"]
msg = module.params["msg"]
res, error = send_message(module, client_id, client_secret, topic, msg)
if not res:
module.fail_json(msg='fail to send message with response code %s' % error.code)
module.exit_json(changed=True, topic=topic, msg=msg)
if __name__ == '__main__':
main()