347b425c67
This can happen if the server has a NICKLEN setting which is less than the length of the specified nick. With this patch we now grab that nick and use it moving forward, instead of failing because we didn't get back the one we specified, in the connection response.
193 lines
5.3 KiB
Python
193 lines
5.3 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# (c) 2013, Jan-Piet Mens <jpmens () gmail.com>
|
|
#
|
|
# This file is part of Ansible
|
|
#
|
|
# Ansible is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Ansible is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: irc
|
|
version_added: "1.2"
|
|
short_description: Send a message to an IRC channel
|
|
description:
|
|
- Send a message to an IRC channel. This is a very simplistic implementation.
|
|
options:
|
|
server:
|
|
description:
|
|
- IRC server name/address
|
|
required: false
|
|
default: localhost
|
|
port:
|
|
description:
|
|
- IRC server port number
|
|
required: false
|
|
default: 6667
|
|
nick:
|
|
description:
|
|
- Nickname. May be shortened, depending on server's NICKLEN setting.
|
|
required: false
|
|
default: ansible
|
|
msg:
|
|
description:
|
|
- The message body.
|
|
required: true
|
|
default: null
|
|
color:
|
|
description:
|
|
- Text color for the message. Default is black.
|
|
required: false
|
|
default: black
|
|
choices: [ "yellow", "red", "green", "blue", "black" ]
|
|
channel:
|
|
description:
|
|
- Channel name
|
|
required: true
|
|
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
|
|
|
|
# informational: requirements for nodes
|
|
requirements: [ socket ]
|
|
author: Jan-Piet Mens, Matt Martz
|
|
'''
|
|
|
|
EXAMPLES = '''
|
|
- irc: server=irc.example.net channel="#t1" msg="Hello world"
|
|
|
|
- local_action: irc port=6669
|
|
channel="#t1"
|
|
msg="All finished at {{ ansible_date_time.iso8601 }}"
|
|
color=red
|
|
nick=ansibleIRC
|
|
'''
|
|
|
|
# ===========================================
|
|
# IRC module support methods.
|
|
#
|
|
|
|
import re
|
|
import socket
|
|
|
|
from time import sleep
|
|
|
|
|
|
def send_msg(channel, msg, server='localhost', port='6667',
|
|
nick="ansible", color='black', passwd=False, timeout=30):
|
|
'''send message to IRC'''
|
|
|
|
colornumbers = {
|
|
'black': "01",
|
|
'red': "04",
|
|
'green': "09",
|
|
'yellow': "08",
|
|
'blue': "12",
|
|
}
|
|
|
|
try:
|
|
colornumber = colornumbers[color]
|
|
except:
|
|
colornumber = "01" # black
|
|
|
|
message = "\x03" + colornumber + msg
|
|
|
|
irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
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')
|
|
time.sleep(0.5)
|
|
|
|
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')
|
|
time.sleep(0.5)
|
|
|
|
irc.send('PRIVMSG %s :%s\r\n' % (channel, message))
|
|
time.sleep(1)
|
|
irc.send('PART %s\r\n' % channel)
|
|
irc.send('QUIT\r\n')
|
|
time.sleep(1)
|
|
irc.close()
|
|
|
|
# ===========================================
|
|
# Main
|
|
#
|
|
|
|
|
|
def main():
|
|
module = AnsibleModule(
|
|
argument_spec=dict(
|
|
server=dict(default='localhost'),
|
|
port=dict(default=6667),
|
|
nick=dict(default='ansible'),
|
|
msg=dict(required=True),
|
|
color=dict(default="black", choices=["yellow", "red", "green",
|
|
"blue", "black"]),
|
|
channel=dict(required=True),
|
|
passwd=dict(),
|
|
timeout=dict(type='int', default=30)
|
|
),
|
|
supports_check_mode=True
|
|
)
|
|
|
|
server = module.params["server"]
|
|
port = module.params["port"]
|
|
nick = module.params["nick"]
|
|
msg = module.params["msg"]
|
|
color = module.params["color"]
|
|
channel = module.params["channel"]
|
|
passwd = module.params["passwd"]
|
|
timeout = module.params["timeout"]
|
|
|
|
try:
|
|
send_msg(channel, msg, server, port, nick, color, passwd, timeout)
|
|
except Exception, e:
|
|
module.fail_json(msg="unable to send to IRC: %s" % e)
|
|
|
|
module.exit_json(changed=False, channel=channel, nick=nick,
|
|
msg=msg)
|
|
|
|
# import module snippets
|
|
from ansible.module_utils.basic import *
|
|
main()
|