mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-08 22:33:25 +00:00
Copying snapshot of extras modules
This commit is contained in:
committed by
Matt Clay
parent
8afa090417
commit
d4b117843a
143
lib/ansible/modules/extras/notification/campfire
Normal file
143
lib/ansible/modules/extras/notification/campfire
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
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.
|
||||
version_added: "1.2"
|
||||
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: [ urllib2, cgi ]
|
||||
author: Adam Garside <adam.garside@gmail.com>
|
||||
'''
|
||||
|
||||
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."
|
||||
'''
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
try:
|
||||
import urllib2
|
||||
except ImportError:
|
||||
module.fail_json(msg="urllib2 is required")
|
||||
|
||||
try:
|
||||
import cgi
|
||||
except ImportError:
|
||||
module.fail_json(msg="cgi is required")
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
subscription=dict(required=True),
|
||||
token=dict(required=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"
|
||||
|
||||
try:
|
||||
|
||||
# Setup basic auth using token as the username
|
||||
pm = urllib2.HTTPPasswordMgrWithDefaultRealm()
|
||||
pm.add_password(None, URI, token, 'X')
|
||||
|
||||
# Setup Handler and define the opener for the request
|
||||
handler = urllib2.HTTPBasicAuthHandler(pm)
|
||||
opener = urllib2.build_opener(handler)
|
||||
|
||||
target_url = '%s/room/%s/speak.xml' % (URI, room)
|
||||
|
||||
# Send some audible notification if requested
|
||||
if notify:
|
||||
req = urllib2.Request(target_url, NSTR % cgi.escape(notify))
|
||||
req.add_header('Content-Type', 'application/xml')
|
||||
req.add_header('User-agent', AGENT)
|
||||
response = opener.open(req)
|
||||
|
||||
# Send the message
|
||||
req = urllib2.Request(target_url, MSTR % cgi.escape(msg))
|
||||
req.add_header('Content-Type', 'application/xml')
|
||||
req.add_header('User-agent', AGENT)
|
||||
response = opener.open(req)
|
||||
|
||||
except urllib2.HTTPError, e:
|
||||
if not (200 <= e.code < 300):
|
||||
module.fail_json(msg="unable to send msg: '%s', campfire api"
|
||||
" returned error code: '%s'" %
|
||||
(msg, e.code))
|
||||
|
||||
except Exception, e:
|
||||
module.fail_json(msg="unable to send msg: %s" % msg)
|
||||
|
||||
module.exit_json(changed=True, room=room, msg=msg, notify=notify)
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
192
lib/ansible/modules/extras/notification/flowdock
Normal file
192
lib/ansible/modules/extras/notification/flowdock
Normal file
@@ -0,0 +1,192 @@
|
||||
#!/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/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: flowdock
|
||||
version_added: "1.2"
|
||||
author: Matt Coddington
|
||||
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
|
||||
|
||||
# informational: requirements for nodes
|
||||
requirements: [ urllib, urllib2 ]
|
||||
'''
|
||||
|
||||
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
|
||||
'''
|
||||
|
||||
# ===========================================
|
||||
# Module execution.
|
||||
#
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
token=dict(required=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 *
|
||||
|
||||
main()
|
||||
|
||||
99
lib/ansible/modules/extras/notification/grove
Normal file
99
lib/ansible/modules/extras/notification/grove
Normal file
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
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@zimbatm.com>
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- grove: >
|
||||
channel_token=6Ph62VBBJOccmtTPZbubiPzdrhipZXtg
|
||||
service=my-app
|
||||
message=deployed {{ target }}
|
||||
'''
|
||||
|
||||
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),
|
||||
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 *
|
||||
main()
|
||||
149
lib/ansible/modules/extras/notification/hipchat
Normal file
149
lib/ansible/modules/extras/notification/hipchat
Normal file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
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
|
||||
required: false
|
||||
default: 'https://api.hipchat.com/v1/rooms/message'
|
||||
version_added: 1.6.0
|
||||
|
||||
|
||||
# informational: requirements for nodes
|
||||
requirements: [ urllib, urllib2 ]
|
||||
author: WAKAYAMA Shirou
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- hipchat: token=AAAAAA room=notify msg="Ansible task finished"
|
||||
'''
|
||||
|
||||
# ===========================================
|
||||
# HipChat module specific support methods.
|
||||
#
|
||||
|
||||
MSG_URI = "https://api.hipchat.com/v1/rooms/message"
|
||||
|
||||
def send_msg(module, token, room, msg_from, msg, msg_format='text',
|
||||
color='yellow', notify=False, api=MSG_URI):
|
||||
'''sending message to hipchat'''
|
||||
|
||||
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
|
||||
|
||||
if notify:
|
||||
params['notify'] = 1
|
||||
else:
|
||||
params['notify'] = 0
|
||||
|
||||
url = api + "?auth_token=%s" % (token)
|
||||
data = urllib.urlencode(params)
|
||||
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']))
|
||||
|
||||
|
||||
# ===========================================
|
||||
# Module execution.
|
||||
#
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
token=dict(required=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=MSG_URI),
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
token = module.params["token"]
|
||||
room = 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:
|
||||
send_msg(module, token, room, msg_from, msg, msg_format, color, notify, api)
|
||||
except Exception, e:
|
||||
module.fail_json(msg="unable to sent msg: %s" % e)
|
||||
|
||||
changed = True
|
||||
module.exit_json(changed=changed, room=room, msg_from=msg_from, msg=msg)
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.urls import *
|
||||
|
||||
main()
|
||||
215
lib/ansible/modules/extras/notification/irc
Normal file
215
lib/ansible/modules/extras/notification/irc
Normal file
@@ -0,0 +1,215 @@
|
||||
#!/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/>.
|
||||
#
|
||||
|
||||
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. May be shortened, depending on server's NICKLEN setting.
|
||||
required: false
|
||||
default: ansible
|
||||
msg:
|
||||
description:
|
||||
- The message body.
|
||||
required: true
|
||||
default: null
|
||||
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").
|
||||
required: false
|
||||
default: "none"
|
||||
choices: [ "none", "yellow", "red", "green", "blue", "black" ]
|
||||
channel:
|
||||
description:
|
||||
- Channel name
|
||||
required: true
|
||||
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
|
||||
|
||||
# informational: requirements for nodes
|
||||
requirements: [ socket ]
|
||||
author: Jan-Piet Mens, Matt Martz
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- irc: server=irc.example.net channel="#t1" msg="Hello world"
|
||||
|
||||
- local_action: irc port=6669
|
||||
channel="#t1"
|
||||
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(channel, msg, server='localhost', port='6667', key=None,
|
||||
nick="ansible", color='none', passwd=False, timeout=30, use_ssl=False):
|
||||
'''send message to IRC'''
|
||||
|
||||
colornumbers = {
|
||||
'black': "01",
|
||||
'red': "04",
|
||||
'green': "09",
|
||||
'yellow': "08",
|
||||
'blue': "12",
|
||||
}
|
||||
|
||||
try:
|
||||
colornumber = colornumbers[color]
|
||||
colortext = "\x03" + colornumber
|
||||
except:
|
||||
colortext = ""
|
||||
|
||||
message = 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)
|
||||
|
||||
irc.send('PRIVMSG %s :%s\r\n' % (channel, message))
|
||||
sleep(1)
|
||||
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(default=6667),
|
||||
nick=dict(default='ansible'),
|
||||
msg=dict(required=True),
|
||||
color=dict(default="none", choices=["yellow", "red", "green",
|
||||
"blue", "black", "none"]),
|
||||
channel=dict(required=True),
|
||||
key=dict(),
|
||||
passwd=dict(),
|
||||
timeout=dict(type='int', default=30),
|
||||
use_ssl=dict(type='bool', default=False)
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
server = module.params["server"]
|
||||
port = module.params["port"]
|
||||
nick = module.params["nick"]
|
||||
msg = module.params["msg"]
|
||||
color = module.params["color"]
|
||||
channel = module.params["channel"]
|
||||
key = module.params["key"]
|
||||
passwd = module.params["passwd"]
|
||||
timeout = module.params["timeout"]
|
||||
use_ssl = module.params["use_ssl"]
|
||||
|
||||
try:
|
||||
send_msg(channel, msg, server, port, key, nick, color, passwd, timeout, use_ssl)
|
||||
except Exception, e:
|
||||
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 *
|
||||
main()
|
||||
146
lib/ansible/modules/extras/notification/jabber
Normal file
146
lib/ansible/modules/extras/notification/jabber
Normal file
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
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: [ xmpp ]
|
||||
author: Brian Coca
|
||||
'''
|
||||
|
||||
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),
|
||||
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="xmpp 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)
|
||||
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:
|
||||
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 *
|
||||
main()
|
||||
252
lib/ansible/modules/extras/notification/mail
Normal file
252
lib/ansible/modules/extras/notification/mail
Normal file
@@ -0,0 +1,252 @@
|
||||
#!/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/>.
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
author: Dag Wieers
|
||||
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.
|
||||
aliases: [ msg ]
|
||||
required: true
|
||||
body:
|
||||
description:
|
||||
- The body of the email being sent.
|
||||
default: $subject
|
||||
required: false
|
||||
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
|
||||
"""
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example playbook sending mail to root
|
||||
- local_action: mail msg='System {{ ansible_hostname }} has been successfully provisioned.'
|
||||
|
||||
# Send e-mail to a bunch of users, attaching files
|
||||
- local_action: 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
|
||||
'''
|
||||
|
||||
import os
|
||||
import sys
|
||||
import smtplib
|
||||
|
||||
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(
|
||||
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')
|
||||
)
|
||||
)
|
||||
|
||||
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')
|
||||
|
||||
sender_phrase, sender_addr = parseaddr(sender)
|
||||
|
||||
if not body:
|
||||
body = subject
|
||||
|
||||
try:
|
||||
smtp = smtplib.SMTP(host, port=int(port))
|
||||
except Exception, e:
|
||||
module.fail_json(rc=1, msg='Failed to send mail to server %s on port %s: %s' % (host, port, e))
|
||||
|
||||
|
||||
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", _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:
|
||||
module.fail_json(rc=1, msg="Failed to send mail: can't attach file %s: %s" % (file, e))
|
||||
sys.exit()
|
||||
|
||||
composed = msg.as_string()
|
||||
|
||||
try:
|
||||
smtp.sendmail(sender_addr, set(addr_list), composed)
|
||||
except Exception, e:
|
||||
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 *
|
||||
main()
|
||||
166
lib/ansible/modules/extras/notification/mqtt
Normal file
166
lib/ansible/modules/extras/notification/mqtt
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/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/>.
|
||||
#
|
||||
|
||||
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
|
||||
|
||||
# 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
|
||||
'''
|
||||
|
||||
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),
|
||||
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),
|
||||
),
|
||||
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)
|
||||
|
||||
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 }
|
||||
|
||||
try:
|
||||
rc = mqtt.single(topic, payload,
|
||||
qos=qos,
|
||||
retain=retain,
|
||||
client_id=client_id,
|
||||
hostname=server,
|
||||
port=port,
|
||||
auth=auth)
|
||||
except Exception, e:
|
||||
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 *
|
||||
main()
|
||||
140
lib/ansible/modules/extras/notification/nexmo
Normal file
140
lib/ansible/modules/extras/notification/nexmo
Normal file
@@ -0,0 +1,140 @@
|
||||
#!/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/>.
|
||||
|
||||
DOCUMENTATION = """
|
||||
module: nexmo
|
||||
short_description: Send a SMS via nexmo
|
||||
description:
|
||||
- Send a SMS message via nexmo
|
||||
version_added: 1.6
|
||||
author: Matt Martz
|
||||
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"
|
||||
"""
|
||||
|
||||
|
||||
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 *
|
||||
|
||||
main()
|
||||
74
lib/ansible/modules/extras/notification/osx_say
Normal file
74
lib/ansible/modules/extras/notification/osx_say
Normal file
@@ -0,0 +1,74 @@
|
||||
#!/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/>.
|
||||
|
||||
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: Michael DeHaan
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- local_action: osx_say msg="{{inventory_hostname}} is all done" voice=Zarvox
|
||||
'''
|
||||
|
||||
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 *
|
||||
main()
|
||||
173
lib/ansible/modules/extras/notification/slack
Normal file
173
lib/ansible/modules/extras/notification/slack
Normal file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (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/>.
|
||||
|
||||
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 <ramon@delafuente.nl>
|
||||
options:
|
||||
domain:
|
||||
description:
|
||||
- Slack (sub)domain for your environment without protocol.
|
||||
(i.e. C(future500.slack.com))
|
||||
required: true
|
||||
token:
|
||||
description:
|
||||
- Slack integration token
|
||||
required: true
|
||||
msg:
|
||||
description:
|
||||
- Message to send.
|
||||
required: true
|
||||
channel:
|
||||
description:
|
||||
- Channel to send the message to. If absent, the message goes to the channel selected for the I(token).
|
||||
required: false
|
||||
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(http://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
|
||||
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
|
||||
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'
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
- name: Send notification message via Slack
|
||||
local_action:
|
||||
module: slack
|
||||
domain: future500.slack.com
|
||||
token: thetokengeneratedbyslack
|
||||
msg: "{{ inventory_hostname }} completed"
|
||||
|
||||
- name: Send notification message via Slack all options
|
||||
local_action:
|
||||
module: slack
|
||||
domain: future500.slack.com
|
||||
token: thetokengeneratedbyslack
|
||||
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'
|
||||
|
||||
"""
|
||||
|
||||
|
||||
SLACK_INCOMING_WEBHOOK = 'https://%s/services/hooks/incoming-webhook?token=%s'
|
||||
|
||||
def build_payload_for_slack(module, text, channel, username, icon_url, icon_emoji, link_names, parse):
|
||||
payload = dict(text=text)
|
||||
|
||||
if channel is not None:
|
||||
payload['channel'] = channel if (channel[0] == '#') else '#'+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
|
||||
|
||||
payload="payload=" + module.jsonify(payload)
|
||||
return payload
|
||||
|
||||
def do_notify_slack(module, domain, token, payload):
|
||||
slack_incoming_webhook = SLACK_INCOMING_WEBHOOK % (domain, token)
|
||||
|
||||
response, info = fetch_url(module, slack_incoming_webhook, data=payload)
|
||||
if info['status'] != 200:
|
||||
obscured_incoming_webhook = SLACK_INCOMING_WEBHOOK % (domain, '[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=True),
|
||||
token = dict(type='str', required=True),
|
||||
msg = dict(type='str', required=True),
|
||||
channel = dict(type='str', default=None),
|
||||
username = dict(type='str', default='Ansible'),
|
||||
icon_url = dict(type='str', default='http://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'),
|
||||
)
|
||||
)
|
||||
|
||||
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']
|
||||
|
||||
payload = build_payload_for_slack(module, text, channel, username, icon_url, icon_emoji, link_names, parse)
|
||||
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 *
|
||||
main()
|
||||
190
lib/ansible/modules/extras/notification/sns
Normal file
190
lib/ansible/modules/extras/notification/sns
Normal file
@@ -0,0 +1,190 @@
|
||||
#!/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/>.
|
||||
|
||||
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@gmail.com>
|
||||
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" ]
|
||||
author: Michael J. Schultz
|
||||
"""
|
||||
|
||||
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"
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.ec2 import *
|
||||
|
||||
try:
|
||||
import boto
|
||||
import boto.sns
|
||||
except ImportError:
|
||||
print "failed=True msg='boto required for this module'"
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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:
|
||||
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:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
module.exit_json(msg="OK")
|
||||
|
||||
main()
|
||||
135
lib/ansible/modules/extras/notification/twilio
Normal file
135
lib/ansible/modules/extras/notification/twilio
Normal file
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2014, 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/>.
|
||||
|
||||
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 an the Twilio SMS service.
|
||||
notes:
|
||||
- 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 account id for Twilio found on the account page
|
||||
required: true
|
||||
auth_token:
|
||||
description: user's authentication token for Twilio found on the account page
|
||||
required: true
|
||||
msg:
|
||||
description:
|
||||
the body of the text message
|
||||
required: true
|
||||
to_number:
|
||||
description:
|
||||
what phone number to send the text message to, format +15551112222
|
||||
required: true
|
||||
from_number:
|
||||
description:
|
||||
what phone number to send the text message from, format +15551112222
|
||||
required: true
|
||||
|
||||
requirements: [ urllib, urllib2 ]
|
||||
author: Matt Makai
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# send a text message from the local server about the build status to (555) 303 5681
|
||||
# note: you have to have purchased the 'from_number' on your Twilio account
|
||||
- local_action: text msg="All servers with webserver role are now configured."
|
||||
account_sid={{ twilio_account_sid }}
|
||||
auth_token={{ twilio_auth_token }}
|
||||
from_number=+15552014545 to_number=+15553035681
|
||||
|
||||
# send a text message from a server to (555) 111 3232
|
||||
# note: you have to have purchased the 'from_number' on your Twilio account
|
||||
- text: msg="This server's configuration is now complete."
|
||||
account_sid={{ twilio_account_sid }}
|
||||
auth_token={{ twilio_auth_token }}
|
||||
from_number=+15553258899 to_number=+15551113232
|
||||
|
||||
'''
|
||||
|
||||
# =======================================
|
||||
# text module support methods
|
||||
#
|
||||
try:
|
||||
import urllib, urllib2
|
||||
except ImportError:
|
||||
module.fail_json(msg="urllib and urllib2 are required")
|
||||
|
||||
import base64
|
||||
|
||||
|
||||
def post_text(module, account_sid, auth_token, msg, from_number, to_number):
|
||||
URI = "https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json" \
|
||||
% (account_sid,)
|
||||
AGENT = "Ansible/1.5"
|
||||
|
||||
data = {'From':from_number, 'To':to_number, 'Body':msg}
|
||||
encoded_data = urllib.urlencode(data)
|
||||
request = urllib2.Request(URI)
|
||||
base64string = base64.encodestring('%s:%s' % \
|
||||
(account_sid, auth_token)).replace('\n', '')
|
||||
request.add_header('User-Agent', AGENT)
|
||||
request.add_header('Content-type', 'application/x-www-form-urlencoded')
|
||||
request.add_header('Accept', 'application/ansible')
|
||||
request.add_header('Authorization', 'Basic %s' % base64string)
|
||||
return urllib2.urlopen(request, encoded_data)
|
||||
|
||||
|
||||
# =======================================
|
||||
# Main
|
||||
#
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
account_sid=dict(required=True),
|
||||
auth_token=dict(required=True),
|
||||
msg=dict(required=True),
|
||||
from_number=dict(required=True),
|
||||
to_number=dict(required=True),
|
||||
),
|
||||
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']
|
||||
|
||||
try:
|
||||
response = post_text(module, account_sid, auth_token, msg,
|
||||
from_number, to_number)
|
||||
except Exception, e:
|
||||
module.fail_json(msg="unable to send text message to %s" % to_number)
|
||||
|
||||
module.exit_json(msg=msg, changed=False)
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
116
lib/ansible/modules/extras/notification/typetalk
Normal file
116
lib/ansible/modules/extras/notification/typetalk
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
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: [ urllib, urllib2, json ]
|
||||
author: Takashi Someda <someda@isenshi.com>
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- typetalk: client_id=12345 client_secret=12345 topic=1 msg="install completed"
|
||||
'''
|
||||
|
||||
try:
|
||||
import urllib
|
||||
except ImportError:
|
||||
urllib = None
|
||||
|
||||
try:
|
||||
import urllib2
|
||||
except ImportError:
|
||||
urllib2 = None
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
json = None
|
||||
|
||||
|
||||
def do_request(url, params, headers={}):
|
||||
data = urllib.urlencode(params)
|
||||
headers = dict(headers, **{
|
||||
'User-Agent': 'Ansible/typetalk module',
|
||||
})
|
||||
return urllib2.urlopen(urllib2.Request(url, data, headers))
|
||||
|
||||
|
||||
def get_access_token(client_id, client_secret):
|
||||
params = {
|
||||
'client_id': client_id,
|
||||
'client_secret': client_secret,
|
||||
'grant_type': 'client_credentials',
|
||||
'scope': 'topic.post'
|
||||
}
|
||||
res = do_request('https://typetalk.in/oauth2/access_token', params)
|
||||
return json.load(res)['access_token']
|
||||
|
||||
|
||||
def send_message(client_id, client_secret, topic, msg):
|
||||
"""
|
||||
send message to typetalk
|
||||
"""
|
||||
try:
|
||||
access_token = get_access_token(client_id, client_secret)
|
||||
url = 'https://typetalk.in/api/v1/topics/%d' % topic
|
||||
headers = {
|
||||
'Authorization': 'Bearer %s' % access_token,
|
||||
}
|
||||
do_request(url, {'message': msg}, headers)
|
||||
return True, {'access_token': access_token}
|
||||
except urllib2.HTTPError, e:
|
||||
return False, e
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
client_id=dict(required=True),
|
||||
client_secret=dict(required=True),
|
||||
topic=dict(required=True, type='int'),
|
||||
msg=dict(required=True),
|
||||
),
|
||||
supports_check_mode=False
|
||||
)
|
||||
|
||||
if not (urllib and urllib2 and json):
|
||||
module.fail_json(msg="urllib, urllib2 and json modules are 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(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)
|
||||
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
Reference in New Issue
Block a user