mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-08 14:22:46 +00:00
Relocating extras into lib/ansible/modules/ after merge
This commit is contained in:
committed by
Matt Clay
parent
c65ba07d2c
commit
011ea55a8f
0
lib/ansible/modules/notification/__init__.py
Normal file
0
lib/ansible/modules/notification/__init__.py
Normal file
150
lib/ansible/modules/notification/campfire.py
Normal file
150
lib/ansible/modules/notification/campfire.py
Normal 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()
|
||||
199
lib/ansible/modules/notification/flowdock.py
Normal file
199
lib/ansible/modules/notification/flowdock.py
Normal 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()
|
||||
123
lib/ansible/modules/notification/grove.py
Normal file
123
lib/ansible/modules/notification/grove.py
Normal 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()
|
||||
103
lib/ansible/modules/notification/hall.py
Executable file
103
lib/ansible/modules/notification/hall.py
Executable 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()
|
||||
224
lib/ansible/modules/notification/hipchat.py
Normal file
224
lib/ansible/modules/notification/hipchat.py
Normal 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()
|
||||
315
lib/ansible/modules/notification/irc.py
Normal file
315
lib/ansible/modules/notification/irc.py
Normal 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()
|
||||
176
lib/ansible/modules/notification/jabber.py
Normal file
176
lib/ansible/modules/notification/jabber.py
Normal 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()
|
||||
317
lib/ansible/modules/notification/mail.py
Normal file
317
lib/ansible/modules/notification/mail.py
Normal 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()
|
||||
216
lib/ansible/modules/notification/mqtt.py
Normal file
216
lib/ansible/modules/notification/mqtt.py
Normal 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()
|
||||
146
lib/ansible/modules/notification/nexmo.py
Normal file
146
lib/ansible/modules/notification/nexmo.py
Normal 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()
|
||||
85
lib/ansible/modules/notification/osx_say.py
Normal file
85
lib/ansible/modules/notification/osx_say.py
Normal 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()
|
||||
193
lib/ansible/modules/notification/pushbullet.py
Normal file
193
lib/ansible/modules/notification/pushbullet.py
Normal 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()
|
||||
123
lib/ansible/modules/notification/pushover.py
Normal file
123
lib/ansible/modules/notification/pushover.py
Normal 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()
|
||||
255
lib/ansible/modules/notification/rocketchat.py
Normal file
255
lib/ansible/modules/notification/rocketchat.py
Normal 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()
|
||||
275
lib/ansible/modules/notification/sendgrid.py
Normal file
275
lib/ansible/modules/notification/sendgrid.py
Normal 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()
|
||||
295
lib/ansible/modules/notification/slack.py
Normal file
295
lib/ansible/modules/notification/slack.py
Normal 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 = {
|
||||
'&': "&",
|
||||
'>': ">",
|
||||
'<': "<",
|
||||
'"': "\"",
|
||||
"'": "\'",
|
||||
}
|
||||
|
||||
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()
|
||||
205
lib/ansible/modules/notification/sns.py
Normal file
205
lib/ansible/modules/notification/sns.py
Normal 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()
|
||||
105
lib/ansible/modules/notification/telegram.py
Normal file
105
lib/ansible/modules/notification/telegram.py
Normal 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()
|
||||
181
lib/ansible/modules/notification/twilio.py
Normal file
181
lib/ansible/modules/notification/twilio.py
Normal 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()
|
||||
145
lib/ansible/modules/notification/typetalk.py
Normal file
145
lib/ansible/modules/notification/typetalk.py
Normal 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()
|
||||
Reference in New Issue
Block a user