From c484d32a40b582c00cafef9f20d136188a1b24c2 Mon Sep 17 00:00:00 2001 From: Willy Barro Date: Sat, 24 Jan 2015 18:35:22 -0200 Subject: [PATCH 1/4] Add pushbullet module --- notification/pushbullet.py | 174 +++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 notification/pushbullet.py diff --git a/notification/pushbullet.py b/notification/pushbullet.py new file mode 100644 index 00000000000..d89c79ec941 --- /dev/null +++ b/notification/pushbullet.py @@ -0,0 +1,174 @@ +#!/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 . + +DOCUMENTATION = ''' +--- +author: Willy Barro +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: "1.8" +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 +except ImportError: + pushbullet_found = False +else: + pushbullet_found = True + +# =========================================== +# Main +# + +def main(): + module = AnsibleModule( + argument_spec = dict( + api_key = dict(type='str', required=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) + ), + 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'] + + if not pushbullet_found: + module.fail_json(msg="Python 'pushbullet.py' module is required. Install via: $ pip install pushbullet.py") + + # Init pushbullet + pb = PushBullet(api_key) + target = None + + # Checks for channel/device + if device is not None and channel is not None: + module.fail_json(msg="You can't use both device and channel at the same time.") + + 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 = {d.nickname: d for d in pb.devices} + + 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 = {c.channel_tag: c for c in pb.channels} + + 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) + + # Send push notification + success, result = target.push_note(title, body) + + if success: + module.exit_json(changed=True, msg="OK") + + # General failure + module.fail_json(msg="Some error ocurred, Pushbullet response: %s" % (result)) + +# import module snippets +from ansible.module_utils.basic import * +main() From 7ef07893ade1312b65c41d57e836f438471477d1 Mon Sep 17 00:00:00 2001 From: Willy Barro Date: Wed, 13 May 2015 19:13:38 -0300 Subject: [PATCH 2/4] Remove changed=True from pushbullet module By convention, notification modules should not return changed=True --- notification/pushbullet.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notification/pushbullet.py b/notification/pushbullet.py index d89c79ec941..ffc2b32232b 100644 --- a/notification/pushbullet.py +++ b/notification/pushbullet.py @@ -24,7 +24,7 @@ module: pushbullet short_description: Sends notifications to Pushbullet description: - This module sends push notifications via Pushbullet to channels or devices. -version_added: "1.8" +version_added: "2.0" options: api_key: description: @@ -164,7 +164,7 @@ def main(): success, result = target.push_note(title, body) if success: - module.exit_json(changed=True, msg="OK") + module.exit_json(changed=False, msg="OK") # General failure module.fail_json(msg="Some error ocurred, Pushbullet response: %s" % (result)) From 318983ee5366ec1846634fc1652c1c43d7fbf8c3 Mon Sep 17 00:00:00 2001 From: Willy Barro Date: Wed, 13 May 2015 19:22:46 -0300 Subject: [PATCH 3/4] Replace manual option check to mutually_exclusive AnsibleModule option Also return the message "OK" when in check mode to use the same message as the original success return. --- notification/pushbullet.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/notification/pushbullet.py b/notification/pushbullet.py index ffc2b32232b..5b255b4b549 100644 --- a/notification/pushbullet.py +++ b/notification/pushbullet.py @@ -114,6 +114,9 @@ def main(): title = dict(type='str', required=True), body = dict(type='str', default=None) ), + mutually_exclusive = ( + ['channel', 'device'], + ), supports_check_mode=True ) @@ -132,9 +135,6 @@ def main(): target = None # Checks for channel/device - if device is not None and channel is not None: - module.fail_json(msg="You can't use both device and channel at the same time.") - if device is None and channel is None: module.fail_json(msg="You need to provide a channel or a device.") @@ -158,7 +158,7 @@ def main(): # If in check mode, exit saying that we succeeded if module.check_mode: - module.exit_json(changed=False) + module.exit_json(changed=False, msg="OK") # Send push notification success, result = target.push_note(title, body) From a4232d657d29e5bef53a89aa56895ffcb970f554 Mon Sep 17 00:00:00 2001 From: Willy Barro Date: Wed, 13 May 2015 20:45:50 -0300 Subject: [PATCH 4/4] Handle invalid api key and general api errors on pushbullet pushbullet.py module has changed it's API and return types so we're now handling these exceptions. --- notification/pushbullet.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/notification/pushbullet.py b/notification/pushbullet.py index 5b255b4b549..5e758507279 100644 --- a/notification/pushbullet.py +++ b/notification/pushbullet.py @@ -95,6 +95,7 @@ EXAMPLES = ''' try: from pushbullet import PushBullet + from pushbullet.errors import InvalidKeyError, PushError except ImportError: pushbullet_found = False else: @@ -131,8 +132,11 @@ def main(): module.fail_json(msg="Python 'pushbullet.py' module is required. Install via: $ pip install pushbullet.py") # Init pushbullet - pb = PushBullet(api_key) - target = None + 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: @@ -161,13 +165,13 @@ def main(): module.exit_json(changed=False, msg="OK") # Send push notification - success, result = target.push_note(title, body) - - if success: + try: + 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)) - # General failure - module.fail_json(msg="Some error ocurred, Pushbullet response: %s" % (result)) + module.fail_json(msg="An unknown error has occurred") # import module snippets from ansible.module_utils.basic import *