Relocating extras into lib/ansible/modules/ after merge

This commit is contained in:
James Cammarata
2016-12-08 00:36:57 -05:00
committed by Matt Clay
parent c65ba07d2c
commit 011ea55a8f
596 changed files with 0 additions and 266 deletions

View File

@@ -0,0 +1,150 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# 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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: campfire
version_added: "1.2"
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.
'''
import cgi
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 % cgi.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 %cgi.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)
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,199 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2013 Matt Coddington <coddington@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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: flowdock
version_added: "1.2"
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'
choices: ['yes', 'no']
version_added: 1.5.1
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
'''
import urllib
# ===========================================
# 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="%s is required for the 'inbox' type" % item)
# 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 = urllib.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"])
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,123 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# 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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: grove
version_added: 1.4
short_description: Sends a notification to a grove.io channel
description:
- The M(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.
required: false
default: 'yes'
choices: ['yes', 'no']
version_added: 1.5.1
author: "Jonas Pfenniger (@zimbatm)"
'''
EXAMPLES = '''
- grove: >
channel_token=6Ph62VBBJOccmtTPZbubiPzdrhipZXtg
service=my-app
message=deployed {{ target }}
'''
import urllib
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 = urllib.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")
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,103 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2015, Billy Kimble <basslines@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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = """
module: hall
short_description: Send notification to Hall
description:
- "The M(hall) module connects to the U(https://hall.com) messaging API and allows you to deliver notication messages to rooms."
version_added: "2.0"
author: Billy Kimble (@bkimble) <basslines@gmail.com>
options:
room_token:
description:
- "Room token provided to you by setting up the Ansible room integation on U(https://hall.com)"
required: true
msg:
description:
- The message you wish to deliver as a notifcation
required: true
title:
description:
- The title of the message
required: true
picture:
description:
- "The full URL to the image you wish to use for the Icon of the message. Defaults to U(http://cdn2.hubspot.net/hub/330046/file-769078210-png/Official_Logos/ansible_logo_black_square_small.png?t=1421076128627)"
required: false
"""
EXAMPLES = """
- name: Send Hall notifiation
local_action:
module: hall
room_token: <hall room integration token>
title: Nginx
msg: Created virtual host file on {{ inventory_hostname }}
- name: Send Hall notification if EC2 servers were created.
when: ec2.instances|length > 0
local_action:
module: hall
room_token: <hall room integration token>
title: Server Creation
msg: "Created EC2 instance {{ item.id }} of type {{ item.instance_type }}.\\nInstance can be reached at {{ item.public_ip }} in the {{ item.region }} region."
with_items: "{{ ec2.instances }}"
"""
HALL_API_ENDPOINT = 'https://hall.com/api/1/services/generic/%s'
def send_request_to_hall(module, room_token, payload):
headers = {'Content-Type': 'application/json'}
payload=module.jsonify(payload)
api_endpoint = HALL_API_ENDPOINT % (room_token)
response, info = fetch_url(module, api_endpoint, data=payload, headers=headers)
if info['status'] != 200:
secure_url = HALL_API_ENDPOINT % ('[redacted]')
module.fail_json(msg=" failed to send %s to %s: %s" % (payload, secure_url, info['msg']))
def main():
module = AnsibleModule(
argument_spec = dict(
room_token = dict(type='str', required=True),
msg = dict(type='str', required=True),
title = dict(type='str', required=True),
picture = dict(type='str', default='http://cdn2.hubspot.net/hub/330046/file-769078210-png/Official_Logos/ansible_logo_black_square_small.png?t=1421076128627'),
)
)
room_token = module.params['room_token']
message = module.params['msg']
title = module.params['title']
picture = module.params['picture']
payload = {'title': title, 'message': message, 'picture': picture}
send_request_to_hall(module, room_token, payload)
module.exit_json(msg="OK")
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,224 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# 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/>.
ANSIBLE_METADATA = {'status': ['stableinterface'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: hipchat
version_added: "1.2"
short_description: Send a message to hipchat.
description:
- Send a message to hipchat
options:
token:
description:
- API token.
required: true
room:
description:
- ID or name of the room.
required: true
from:
description:
- Name the message will appear be sent from. max 15 characters.
Over 15, will be shorten.
required: false
default: Ansible
msg:
description:
- The message body.
required: true
default: null
color:
description:
- Background color for the message. Default is yellow.
required: false
default: yellow
choices: [ "yellow", "red", "green", "purple", "gray", "random" ]
msg_format:
description:
- message format. html or text. Default is text.
required: false
default: text
choices: [ "text", "html" ]
notify:
description:
- notify or not (change the tab color, play a sound, etc)
required: false
default: 'yes'
choices: [ "yes", "no" ]
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'
choices: ['yes', 'no']
version_added: 1.5.1
api:
description:
- API url if using a self-hosted hipchat server. For hipchat api version 2 use C(/v2) path in URI
required: false
default: 'https://api.hipchat.com/v1'
version_added: 1.6.0
requirements: [ ]
author: "WAKAYAMA Shirou (@shirou), BOURDEL Paul (@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 urllib
try:
import json
except ImportError:
import simplejson as json
# import module snippets
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
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 = urllib.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}', urllib.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:
e = get_exception()
module.fail_json(msg="unable to send msg: %s" % e)
changed = True
module.exit_json(changed=changed, room=room, msg_from=msg_from, msg=msg)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,315 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2013, Jan-Piet Mens <jpmens () 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/>.
#
ANSIBLE_METADATA = {'status': ['stableinterface'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: irc
version_added: "1.2"
short_description: Send a message to an IRC channel
description:
- Send a message to an IRC channel. This is a very simplistic implementation.
options:
server:
description:
- IRC server name/address
required: false
default: localhost
port:
description:
- IRC server port number
required: false
default: 6667
nick:
description:
- Nickname to send the message from. May be shortened, depending on server's NICKLEN setting.
required: false
default: ansible
msg:
description:
- The message body.
required: true
default: null
topic:
description:
- Set the channel topic
required: false
default: null
version_added: "2.0"
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.
required: false
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.
required: false
default: null
version_added: "2.0"
key:
description:
- Channel key
required: false
version_added: "1.7"
passwd:
description:
- Server password
required: false
timeout:
description:
- Timeout to use while waiting for successful registration and join
messages, this is to prevent an endless loop
default: 30
version_added: "1.5"
use_ssl:
description:
- Designates whether TLS/SSL should be used when connecting to the IRC server
default: False
version_added: "1.8"
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.
default: True
version_added: "2.0"
style:
description:
- Text style for the message. Note italic does not work on some clients
default: None
required: False
choices: [ "bold", "underline", "reverse", "italic" ]
version_added: "2.0"
# 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
from time import sleep
def send_msg(msg, server='localhost', port='6667', channel=None, nick_to=[], key=None, topic=None,
nick="ansible", color='none', passwd=False, timeout=30, use_ssl=False, part=True, style=None):
'''send message to IRC'''
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:
styletext = ""
try:
colornumber = colornumbers[color]
colortext = "\x03" + colornumber
except:
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('PASS %s\r\n' % passwd)
irc.send('NICK %s\r\n' % nick)
irc.send('USER %s %s %s :ansible IRC\r\n' % (nick, nick, nick))
motd = ''
start = time.time()
while 1:
motd += 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('^:\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')
sleep(0.5)
if key:
irc.send('JOIN %s %s\r\n' % (channel, key))
else:
irc.send('JOIN %s\r\n' % channel)
join = ''
start = time.time()
while 1:
join += irc.recv(1024)
if re.search('^:\S+ 366 %s %s :' % (nick, channel), join, flags=re.M):
break
elif time.time() - start > timeout:
raise Exception('Timeout waiting for IRC JOIN response')
sleep(0.5)
if topic is not None:
irc.send('TOPIC %s :%s\r\n' % (channel, topic))
sleep(1)
if nick_to:
for nick in nick_to:
irc.send('PRIVMSG %s :%s\r\n' % (nick, message))
if channel:
irc.send('PRIVMSG %s :%s\r\n' % (channel, message))
sleep(1)
if part:
irc.send('PART %s\r\n' % channel)
irc.send('QUIT\r\n')
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:
e = get_exception()
module.fail_json(msg="unable to send to IRC: %s" % e)
module.exit_json(changed=False, channel=channel, nick=nick,
msg=msg)
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.pycompat24 import get_exception
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,176 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# (c) 2015, Brian Coca <bcoca@ansible.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/>
ANSIBLE_METADATA = {'status': ['stableinterface'],
'supported_by': 'committer',
'version': '1.0'}
DOCUMENTATION = '''
---
version_added: "1.2"
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
default: null
host:
description:
- host to connect, overrides user info
required: false
port:
description:
- port to connect to, overrides default
required: false
default: 5222
encoding:
description:
- message encoding
required: false
# 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 os
import re
import time
HAS_XMPP = True
try:
import xmpp
except ImportError:
HAS_XMPP = False
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),
encoding=dict(required=False),
),
supports_check_mode=True
)
if not HAS_XMPP:
module.fail_json(msg="The required python xmpp library (xmpppy) is not installed")
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 = 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')
conn.send(xmpp.Presence(to=module.params['to']))
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:
e = get_exception()
module.fail_json(msg="unable to send msg: %s" % e)
module.exit_json(changed=False, to=to, user=user, msg=msg.getBody())
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.pycompat24 import get_exception
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,317 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2012 Dag Wieers <dag@wieers.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/>.
ANSIBLE_METADATA = {'status': ['stableinterface'],
'supported_by': 'committer',
'version': '1.0'}
DOCUMENTATION = """
---
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 him perform his
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.
version_added: "0.8"
options:
from:
description:
- The email-address the mail is sent from. May contain address and phrase.
default: root
required: false
to:
description:
- The email-address(es) the mail is being sent to. This is
a comma-separated list, which may contain address and phrase portions.
default: root
required: false
cc:
description:
- The email-address(es) the mail is being copied to. This is
a comma-separated list, which may contain address and phrase portions.
required: false
bcc:
description:
- The email-address(es) the mail is being 'blind' copied to. This is
a comma-separated list, which may contain address and phrase portions.
required: false
subject:
description:
- The subject of the email being sent.
required: true
body:
description:
- The body of the email being sent.
default: $subject
required: false
username:
description:
- If SMTP requires username
default: null
required: false
version_added: "1.9"
password:
description:
- If SMTP requires password
default: null
required: false
version_added: "1.9"
host:
description:
- The mail server
default: 'localhost'
required: false
port:
description:
- The mail server port
default: '25'
required: false
version_added: "1.0"
attach:
description:
- A space-separated list of pathnames of files to attach to the message.
Attached files will have their content-type set to C(application/octet-stream).
default: null
required: false
version_added: "1.0"
headers:
description:
- A vertical-bar-separated list of headers which should be added to the message.
Each individual header is specified as C(header=value) (see example below).
default: null
required: false
version_added: "1.0"
charset:
description:
- The character set of email being sent
default: 'us-ascii'
required: false
subtype:
description:
- The minor mime type, can be either text or html. The major type is always text.
default: 'plain'
required: false
version_added: "2.0"
"""
EXAMPLES = '''
# Example playbook sending mail to root
- mail:
subject: 'System {{ ansible_hostname }} has been successfully provisioned.'
delegate_to: localhost
# 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
# 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/pavatar2.png
headers: 'Reply-To=john@example.com|X-Special="Something or other"'
charset: utf8
delegate_to: localhost
# 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.'
'''
import os
import sys
import smtplib
import ssl
try:
from email import encoders
import email.utils
from email.utils import parseaddr, formataddr
from email.mime.base import MIMEBase
from mail.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
except ImportError:
from email import Encoders as encoders
import email.Utils
from email.Utils import parseaddr, formataddr
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
def main():
module = AnsibleModule(
argument_spec = dict(
username = dict(default=None),
password = dict(default=None, no_log=True),
host = dict(default='localhost'),
port = dict(default='25'),
sender = dict(default='root', aliases=['from']),
to = dict(default='root', aliases=['recipients']),
cc = dict(default=None),
bcc = dict(default=None),
subject = dict(required=True, aliases=['msg']),
body = dict(default=None),
attach = dict(default=None),
headers = dict(default=None),
charset = dict(default='us-ascii'),
subtype = dict(default='plain')
)
)
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')
sender_phrase, sender_addr = parseaddr(sender)
if not body:
body = subject
try:
try:
smtp = smtplib.SMTP_SSL(host, port=int(port))
except (smtplib.SMTPException, ssl.SSLError):
smtp = smtplib.SMTP(host, port=int(port))
except Exception:
e = get_exception()
module.fail_json(rc=1, msg='Failed to send mail to server %s on port %s: %s' % (host, port, e))
smtp.ehlo()
if username and password:
if smtp.has_extn('STARTTLS'):
smtp.starttls()
try:
smtp.login(username, password)
except smtplib.SMTPAuthenticationError:
module.fail_json(msg="Authentication to %s:%s failed, please check your username and/or password" % (host, port))
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = formataddr((sender_phrase, sender_addr))
msg.preamble = "Multipart message"
if headers is not None:
for hdr in [x.strip() for x in headers.split('|')]:
try:
h_key, h_val = hdr.split('=')
msg.add_header(h_key, h_val)
except:
pass
if 'X-Mailer' not in msg:
msg.add_header('X-Mailer', "Ansible")
to_list = []
cc_list = []
addr_list = []
if recipients is not None:
for addr in [x.strip() for x in recipients.split(',')]:
to_list.append( formataddr( parseaddr(addr)) )
addr_list.append( parseaddr(addr)[1] ) # address only, w/o phrase
if copies is not None:
for addr in [x.strip() for x in copies.split(',')]:
cc_list.append( formataddr( parseaddr(addr)) )
addr_list.append( parseaddr(addr)[1] ) # address only, w/o phrase
if blindcopies is not None:
for addr in [x.strip() for x in blindcopies.split(',')]:
addr_list.append( parseaddr(addr)[1] )
if len(to_list) > 0:
msg['To'] = ", ".join(to_list)
if len(cc_list) > 0:
msg['Cc'] = ", ".join(cc_list)
part = MIMEText(body + "\n\n", _subtype=subtype, _charset=charset)
msg.attach(part)
if attach_files is not None:
for file in attach_files.split():
try:
fp = open(file, 'rb')
part = MIMEBase('application', 'octet-stream')
part.set_payload(fp.read())
fp.close()
encoders.encode_base64(part)
part.add_header('Content-disposition', 'attachment', filename=os.path.basename(file))
msg.attach(part)
except Exception:
e = get_exception()
module.fail_json(rc=1, msg="Failed to send mail: can't attach file %s: %s" % (file, e))
composed = msg.as_string()
try:
smtp.sendmail(sender_addr, set(addr_list), composed)
except Exception:
e = get_exception()
module.fail_json(rc=1, msg='Failed to send mail to %s: %s' % (", ".join(addr_list), e))
smtp.quit()
module.exit_json(changed=False)
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.pycompat24 import get_exception
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,216 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2013, 2014, Jan-Piet Mens <jpmens () 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/>.
#
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: mqtt
short_description: Publish a message on an MQTT topic for the IoT
version_added: "1.2"
description:
- Publish a message on an MQTT topic.
options:
server:
description:
- MQTT broker address/name
required: false
default: localhost
port:
description:
- MQTT broker port number
required: false
default: 1883
username:
description:
- Username to authenticate against the broker.
required: false
password:
description:
- Password for C(username) to authenticate against the broker.
required: false
client_id:
description:
- MQTT client identifier
required: false
default: hostname + pid
topic:
description:
- MQTT topic name
required: true
default: null
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
default: null
qos:
description:
- QoS (Quality of Service)
required: false
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.
required: false
default: False
ca_certs:
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.
required: False
default: None
version_added: 2.3
certfile:
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.
required: False
default: None
version_added: 2.3
keyfile:
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.
required: False
default: None
version_added: 2.3
# informational: requirements for nodes
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.python.org/pypi/paho-mqtt)).
author: "Jan-Piet Mens (@jpmens)"
'''
EXAMPLES = '''
- local_action: mqtt
topic=service/ansible/{{ ansible_hostname }}
payload="Hello at {{ ansible_date_time.iso8601 }}"
qos=0
retain=false
client_id=ans001
'''
# ===========================================
# MQTT module support methods.
#
HAS_PAHOMQTT = True
try:
import socket
import paho.mqtt.publish as mqtt
except ImportError:
HAS_PAHOMQTT = False
# ===========================================
# Main
#
def main():
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_certs = dict(default = None, type='path'),
certfile = dict(default = None, type='path'),
keyfile = dict(default = None, type='path'),
),
supports_check_mode=True
)
if not HAS_PAHOMQTT:
module.fail_json(msg="Paho MQTT is not installed")
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_certs", None)
certfile = module.params.get("certfile", None)
keyfile = module.params.get("keyfile", 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:
tls = {'ca_certs': ca_certs, 'certfile': certfile,
'keyfile': keyfile}
try:
rc = mqtt.single(topic, payload,
qos=qos,
retain=retain,
client_id=client_id,
hostname=server,
port=port,
auth=auth,
tls=tls)
except Exception:
e = get_exception()
module.fail_json(msg="unable to publish to MQTT broker %s" % (e))
module.exit_json(changed=False, topic=topic)
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.pycompat24 import get_exception
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,146 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2014, Matt Martz <matt@sivel.net>
#
# 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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = """
module: nexmo
short_description: Send a SMS via nexmo
description:
- Send a SMS message via nexmo
version_added: 1.6
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.
required: false
default: 'yes'
choices:
- 'yes'
- 'no'
"""
EXAMPLES = """
- name: Send notification message via Nexmo
local_action:
module: nexmo
api_key: 640c8a53
api_secret: 0ce239a6
src: 12345678901
dest:
- 10987654321
- 16789012345
msg: "{{ inventory_hostname }} completed"
"""
import urllib
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, urllib.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:
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)
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,85 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2013, Michael DeHaan <michael@ansible.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/>.
ANSIBLE_METADATA = {'status': ['stableinterface'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: osx_say
version_added: "1.2"
short_description: Makes an OSX computer to speak.
description:
- makes an OS computer speak! Amuse your friends, annoy your coworkers!
notes:
- If you like this module, you may also be interested in the osx_say callback in the plugins/ directory of the source checkout.
options:
msg:
description:
What to say
required: true
voice:
description:
What voice to use
required: false
requirements: [ say ]
author:
- "Ansible Core Team"
- "Michael DeHaan (@mpdehaan)"
'''
EXAMPLES = '''
- osx_say:
msg: '{{ inventory_hostname }} is all done'
voice: Zarvox
delegate_to: localhost
'''
DEFAULT_VOICE='Trinoids'
def say(module, msg, voice):
module.run_command(["/usr/bin/say", msg, "--voice=%s" % (voice)], check_rc=True)
def main():
module = AnsibleModule(
argument_spec=dict(
msg=dict(required=True),
voice=dict(required=False, default=DEFAULT_VOICE),
),
supports_check_mode=False
)
if not os.path.exists("/usr/bin/say"):
module.fail_json(msg="/usr/bin/say is not installed")
msg = module.params['msg']
voice = module.params['voice']
say(module, msg, voice)
module.exit_json(msg=msg, changed=False)
# import module snippets
from ansible.module_utils.basic import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,193 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
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.
version_added: "2.0"
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.
required: false
default: null
device:
description:
- The device NAME you wish to send a push notification,
as seen on the Pushbullet main page.
required: false
default: null
push_type:
description:
- Thing you wish to push.
required: false
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.
required: false
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: "http://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"
'''
try:
from pushbullet import PushBullet
from pushbullet.errors import InvalidKeyError, PushError
except ImportError:
pushbullet_found = False
else:
pushbullet_found = True
# ===========================================
# 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="Python 'pushbullet.py' module is required. Install via: $ pip install pushbullet.py")
# 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")
# import module snippets
from ansible.module_utils.basic import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,123 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2012, Jim Richardson <weaselkeeper@gmail.com>
# All rights reserved.
#
# 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/>.
###
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: pushover
version_added: "2.0"
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
pri:
description:
- Message priority (see U(https://pushover.net) for details.)
required: false
author: "Jim Richardson (@weaselkeeper)"
'''
EXAMPLES = '''
- pushover:
msg: '{{ inventory_hostname }} has exploded in flames, It is now time to panic'
app_token: wxfdksl
user_key: baa5fe97f2c5ab3ca8f0bb59
delegate_to: localhost
'''
import urllib
class Pushover(object):
''' Instantiates a pushover object, use it to send notifications '''
base_uri = 'https://api.pushover.net'
port = 443
def __init__(self, module, user, token):
self.module = module
self.user = user
self.token = token
def run(self, priority, msg):
''' Do, whatever it is, we do. '''
url = '%s:%s/1/messages.json' % (self.base_uri, self.port)
# parse config
options = dict(user=self.user,
token=self.token,
priority=priority,
message=msg)
data = urllib.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(
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'])
except:
module.fail_json(msg='Unable to send msg via pushover')
module.exit_json(msg='message sent successfully: %s' % response, changed=False)
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,255 @@
#!/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>
#
# 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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = """
module: rocketchat
short_description: Send notifications to Rocket Chat
description:
- The M(rocketchat) module sends notifications to Rocket Chat via the Incoming WebHook integration
version_added: "2.2"
author: "Ramon de la Fuente (@ramondelafuente)"
options:
domain:
description:
- The domain for your environment without protocol. (i.e.
C(subdomain.domain.com or chat.domain.tld))
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)
required: false
default: https
choices:
- 'http'
- 'https'
msg:
description:
- Message to be sent.
required: false
default: None
channel:
description:
- Channel to send the message to. If absent, the message goes to the channel selected for the I(token)
specifed during the creation of webhook.
required: false
default: None
username:
description:
- This is the sender of the message.
required: false
default: "Ansible"
icon_url:
description:
- URL for the message sender's icon.
required: false
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)
required: false
default: None
link_names:
description:
- Automatically create links for channels and usernames in I(msg).
required: false
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.
required: false
default: 'yes'
choices:
- 'yes'
- 'no'
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
required: false
default: 'normal'
choices:
- 'normal'
- 'good'
- 'warning'
- 'danger'
attachments:
description:
- Define a list of attachments.
required: false
default: None
"""
EXAMPLES = """
- name: Send notification message via Rocket Chat
local_action:
module: rocketchat
token: thetoken/generatedby/rocketchat
domain: chat.example.com
msg: "{{ inventory_hostname }} completed"
- name: Send notification message via Rocket Chat all options
local_action:
module: 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
- 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: ""
- 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"
"""
RETURN = """
changed:
description: A flag indicating if any change was made or not.
returned: success
type: boolean
sample: false
"""
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")
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,275 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2015, Matt Makai <matthew.makai@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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
version_added: "2.0"
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.
required: false
default: null
password:
description:
- password that corresponds to the username
- Since 2.2 it is only required if api_key is not supplied.
required: false
default: null
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
version_added: 2.2
required: false
default: null
cc:
description:
- a list of email addresses to cc
version_added: 2.2
required: false
default: null
bcc:
description:
- a list of email addresses to bcc
version_added: 2.2
required: false
default: null
attachments:
description:
- a list of relative or explicit paths of files you want to attach (7MB limit as per SendGrid docs)
version_added: 2.2
required: false
default: null
from_name:
description:
- the name you want to appear in the from field, i.e 'John Doe'
version_added: 2.2
required: false
default: null
html_body:
description:
- whether the body is html content that should be rendered
version_added: 2.2
required: false
default: false
headers:
description:
- a dict to pass on as headers
version_added: 2.2
required: false
default: null
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 urllib
try:
import sendgrid
HAS_SENDGRID = True
except ImportError:
HAS_SENDGRID = False
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 = urllib.urlencode(data)
to_addresses_api = ''
for recipient in to_addresses:
if isinstance(recipient, unicode):
recipient = recipient.encode('utf-8')
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 != None for lib_arg in sendgrid_lib_args) and not HAS_SENDGRID:
module.fail_json(msg='You must install the sendgrid python library if you want to use any of the following arguments: api_key, bcc, cc, headers, from_name, html_body, attachments')
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)
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,295 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2016, René Moser <mail@renemoser.net>
# (c) 2015, Stefan Berggren <nsg@nsg.cc>
# (c) 2014, Ramon de la Fuente <ramon@delafuente.nl>
#
# 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/>.
ANSIBLE_METADATA = {'status': ['stableinterface'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = """
module: slack
short_description: Send Slack notifications
description:
- The M(slack) module sends notifications to U(http://slack.com) via the Incoming WebHook integration
version_added: "1.6"
author: "Ramon de la Fuente (@ramondelafuente)"
options:
domain:
description:
- Slack (sub)domain for your environment without protocol. (i.e.
C(future500.slack.com)) In 1.8 and beyond, this is deprecated and may
be ignored. See token documentation for information.
required: false
default: None
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.
required: true
msg:
description:
- Message to send.
required: false
default: None
channel:
description:
- Channel to send the message to. If absent, the message goes to the channel selected for the I(token).
required: false
default: None
username:
description:
- This is the sender of the message.
required: false
default: "Ansible"
icon_url:
description:
- Url for the message sender's icon (default C(https://www.ansible.com/favicon.ico))
required: false
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)
required: false
default: None
link_names:
description:
- Automatically create links for channels and usernames in I(msg).
required: false
default: 1
choices:
- 1
- 0
parse:
description:
- Setting for the message parser at Slack
required: false
default: None
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.
required: false
default: 'yes'
choices:
- 'yes'
- 'no'
color:
version_added: "2.0"
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
required: false
default: 'normal'
choices:
- 'normal'
- 'good'
- 'warning'
- 'danger'
attachments:
description:
- Define a list of attachments. This list mirrors the Slack JSON API. For more information, see https://api.slack.com/docs/attachments
required: false
default: None
"""
EXAMPLES = """
- name: Send notification message via Slack
local_action:
module: slack
token: thetoken/generatedby/slack
msg: "{{ inventory_hostname }} completed"
- name: Send notification message via Slack all options
local_action:
module: slack
token: thetoken/generatedby/slack
msg: "{{ inventory_hostname }} completed"
channel: "#ansible"
username: "Ansible on {{ inventory_hostname }}"
icon_url: "http://www.example.com/some-image-file.png"
link_names: 0
parse: 'none'
- 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: 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 notification message via Slack (deprecated API using domain)
local_action:
module: slack
domain: future500.slack.com
token: thetokengeneratedbyslack
msg: "{{ inventory_hostname }} completed"
"""
OLD_SLACK_INCOMING_WEBHOOK = 'https://%s/services/hooks/incoming-webhook?token=%s'
SLACK_INCOMING_WEBHOOK = 'https://hooks.slack.com/services/%s'
# See https://api.slack.com/docs/message-formatting#how_to_escape_characters
# Escaping quotes and apostrophe however is related to how Ansible handles them.
html_escape_table = {
'&': "&amp;",
'>': "&gt;",
'<': "&lt;",
'"': "\"",
"'": "\'",
}
def html_escape(text):
'''Produce entities within text.'''
return "".join(html_escape_table.get(c,c) for c in text)
def build_payload_for_slack(module, text, channel, username, icon_url, icon_emoji, link_names, parse, color, attachments):
payload = {}
if color == "normal" and text is not None:
payload = dict(text=html_escape(text))
elif text is not None:
# With a custom color we have to set the message as attachment, and explicitely turn markdown parsing on for it.
payload = dict(attachments=[dict(text=html_escape(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 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] = html_escape(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),
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', choices=['normal', 'good', 'warning', 'danger']),
attachments = dict(type='list', required=False, default=None)
)
)
domain = module.params['domain']
token = module.params['token']
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']
parse = module.params['parse']
color = module.params['color']
attachments = module.params['attachments']
payload = build_payload_for_slack(module, text, channel, username, icon_url, icon_emoji, link_names, parse, color, attachments)
do_notify_slack(module, domain, token, payload)
module.exit_json(msg="OK")
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,205 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2014, Michael J. Schultz <mjschultz@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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = """
module: sns
short_description: Send Amazon Simple Notification Service (SNS) messages
description:
- The M(sns) module sends notifications to a topic on your Amazon SNS account
version_added: 1.6
author: "Michael J. Schultz (@mjschultz)"
options:
msg:
description:
- Default message to send.
required: true
aliases: [ "default" ]
subject:
description:
- Subject line for email delivery.
required: false
topic:
description:
- The topic you want to publish to.
required: true
email:
description:
- Message to send to email-only subscription
required: false
sqs:
description:
- Message to send to SQS-only subscription
required: false
sms:
description:
- Message to send to SMS-only subscription
required: false
http:
description:
- Message to send to HTTP-only subscription
required: false
https:
description:
- Message to send to HTTPS-only subscription
required: false
aws_secret_key:
description:
- AWS secret key. If not set then the value of the AWS_SECRET_KEY environment variable is used.
required: false
default: None
aliases: ['ec2_secret_key', 'secret_key']
aws_access_key:
description:
- AWS access key. If not set then the value of the AWS_ACCESS_KEY environment variable is used.
required: false
default: None
aliases: ['ec2_access_key', 'access_key']
region:
description:
- The AWS region to use. If not specified then the value of the EC2_REGION environment variable, if any, is used.
required: false
aliases: ['aws_region', 'ec2_region']
requirements:
- "boto"
"""
EXAMPLES = """
- name: Send default notification message via SNS
local_action:
module: sns
msg: "{{ inventory_hostname }} has completed the play."
subject: "Deploy complete!"
topic: "deploy"
- name: Send notification messages via SNS with short message for SMS
local_action:
module: sns
msg: "{{ inventory_hostname }} has completed the play."
sms: "deployed!"
subject: "Deploy complete!"
topic: "deploy"
"""
try:
import json
except ImportError:
import simplejson as json
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ec2 import ec2_argument_spec, connect_to_aws, get_aws_connection_info
from ansible.module_utils.pycompat24 import get_exception
try:
import boto
import boto.ec2
import boto.sns
HAS_BOTO = True
except ImportError:
HAS_BOTO = False
def arn_topic_lookup(connection, short_topic):
response = connection.get_all_topics()
result = response[u'ListTopicsResponse'][u'ListTopicsResult']
# topic names cannot have colons, so this captures the full topic name
lookup_topic = ':{}'.format(short_topic)
for topic in result[u'Topics']:
if topic[u'TopicArn'].endswith(lookup_topic):
return topic[u'TopicArn']
return None
def main():
argument_spec = ec2_argument_spec()
argument_spec.update(
dict(
msg=dict(type='str', required=True, aliases=['default']),
subject=dict(type='str', default=None),
topic=dict(type='str', required=True),
email=dict(type='str', default=None),
sqs=dict(type='str', default=None),
sms=dict(type='str', default=None),
http=dict(type='str', default=None),
https=dict(type='str', default=None),
)
)
module = AnsibleModule(argument_spec=argument_spec)
if not HAS_BOTO:
module.fail_json(msg='boto required for this module')
msg = module.params['msg']
subject = module.params['subject']
topic = module.params['topic']
email = module.params['email']
sqs = module.params['sqs']
sms = module.params['sms']
http = module.params['http']
https = module.params['https']
region, ec2_url, aws_connect_params = get_aws_connection_info(module)
if not region:
module.fail_json(msg="region must be specified")
try:
connection = connect_to_aws(boto.sns, region, **aws_connect_params)
except boto.exception.NoAuthHandlerFound:
e = get_exception()
module.fail_json(msg=str(e))
# .publish() takes full ARN topic id, but I'm lazy and type shortnames
# so do a lookup (topics cannot contain ':', so thats the decider)
if ':' in topic:
arn_topic = topic
else:
arn_topic = arn_topic_lookup(connection, topic)
if not arn_topic:
module.fail_json(msg='Could not find topic: {}'.format(topic))
dict_msg = {'default': msg}
if email:
dict_msg.update(email=email)
if sqs:
dict_msg.update(sqs=sqs)
if sms:
dict_msg.update(sms=sms)
if http:
dict_msg.update(http=http)
if https:
dict_msg.update(https=https)
json_msg = json.dumps(dict_msg)
try:
connection.publish(topic=arn_topic, subject=subject,
message_structure='json', message=json_msg)
except boto.exception.BotoServerError:
e = get_exception()
module.fail_json(msg=str(e))
module.exit_json(msg="OK")
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,105 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2016, Artem Feofanov <artem.feofanov@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/>.
#
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = """
module: telegram
version_added: "2.2"
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
token:
description:
- Token identifying your telegram bot.
required: true
chat_id:
description:
- Telegram group or user chat_id
required: true
"""
EXAMPLES = """
send a message to chat in playbook
- telegram:
token: 'bot9999999:XXXXXXXXXXXXXXXXXXXXXXX'
chat_id: 000000
msg: Ansible task finished
"""
RETURN = """
msg:
description: The message you attempted to send
returned: success
type: string
sample: "Ansible task finished"
"""
import urllib
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 = dict(type='str',required=True)),
supports_check_mode=True
)
token = urllib.quote(module.params.get('token'))
chat_id = urllib.quote(module.params.get('chat_id'))
msg = urllib.quote(module.params.get('msg'))
url = 'https://api.telegram.org/' + token + '/sendMessage?text=' + msg + '&chat_id=' + chat_id
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:
module.fail_json(msg="failed to send message, return status=%s" % str(info['status']))
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,181 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2015, Matt Makai <matthew.makai@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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
version_added: "1.6"
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_number:
description:
one or more phone numbers to send the text message to,
format +15551112222
required: true
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's configuration is now complete."
account_sid: "ACXXXXXXXXXXXXXXXXX"
auth_token: "ACXXXXXXXXXXXXXXXXX"
from_number: "+15553258899"
to_number:
- "+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
#
import urllib
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 = urllib.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_number=dict(required=True),
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_number = module.params['to_number']
media_url = module.params['media_url']
if not isinstance(to_number, list):
to_number = [to_number]
for number in to_number:
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 = json.loads(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)
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,145 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# 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/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: typetalk
version_added: "1.6"
short_description: Send a message to typetalk
description:
- Send a message to typetalk using typetalk API ( http://developers.typetalk.in/ )
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 urllib
try:
import json
except ImportError:
try:
import simplejson as json
except ImportError:
json = None
# import module snippets
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url, ConnectionError
def do_request(module, url, params, headers=None):
data = urllib.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.in/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.in/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:
e = get_exception()
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()