From 652b7523075d5352891bdbe10bf0ea6280d15b5a Mon Sep 17 00:00:00 2001 From: Pierre Guinoiseau Date: Tue, 5 Jul 2016 11:56:02 +1200 Subject: [PATCH 1/6] Docker container improvements - Update to Ubuntu 16.04 - No self-update with git, rebuilding the container is cleaner and gobot seldom gets updates - Move the code into /gobot, just for the sake of shorter paths - Fewer layers --- Dockerfile | 25 ++++++++++--------------- start_gobot.sh | 7 ++----- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/Dockerfile b/Dockerfile index cc2b516..a1890c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,26 +2,21 @@ # To build: sudo docker build [--no-cache=true] [--pull=true] --rm=true -t gobot . # To run e.g: sudo docker run --name=gobot -d gobot -e "JID=myjid@chat" -e "JPASSWD=pwd" -e "JROOM=room" -e "JNICK=nick" -e "GODOMAIN=domain" -e "GOSTAGES=stage,names" - -FROM ubuntu:14.04 +FROM ubuntu:16.04 MAINTAINER Eugene Venter # install required packages -RUN apt-get update && apt-get -y install git python python-dev python-pip - - -RUN useradd -ms /bin/bash iamgobot - -USER iamgobot -WORKDIR /home/iamgobot +RUN apt-get update && \ + apt-get -y install python python-dev python-pip && \ + apt-get clean && \ + rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* -RUN git clone http://github.com/eugeneventer/gobot.git -RUN git config --global user.name gobot -RUN git config --global user.email gobothasnoemail +RUN useradd -m -s /bin/bash iamgobot -USER root -RUN pip install -r gobot/requirements.txt +ADD . /gobot +RUN pip install -r /gobot/requirements.txt USER iamgobot -ENTRYPOINT ["/bin/bash", "/home/iamgobot/gobot/start_gobot.sh"] +WORKDIR /gobot +CMD ["/bin/sh", "/gobot/start_gobot.sh"] diff --git a/start_gobot.sh b/start_gobot.sh index 13dacee..2538630 100644 --- a/start_gobot.sh +++ b/start_gobot.sh @@ -1,5 +1,2 @@ -#!/bin/bash - -# first, ensure git repo is up to date -cd /home/iamgobot/gobot && git pull -python gobot.py -j $JID -p $JPASSWD -r $JROOM -n $JNICK -g $GODOMAIN -s $GOSTAGES +#!/bin/sh +exec python /gobot/gobot.py -j $JID -p $JPASSWD -r $JROOM -n $JNICK -g $GODOMAIN -s $GOSTAGES From 24d94d06bce7cc2167d8c0167342dc9398d46e79 Mon Sep 17 00:00:00 2001 From: Pierre Guinoiseau Date: Tue, 5 Jul 2016 14:45:37 +1200 Subject: [PATCH 2/6] Allow setting the password in a env variable GOBOT_PASSWORD instead of a command-line argument --- gobot.py | 8 ++++++-- start_gobot.sh | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gobot.py b/gobot.py index 21488ab..51049b0 100644 --- a/gobot.py +++ b/gobot.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import os import sys import logging import getpass @@ -123,7 +124,7 @@ def gocd_listen_stop(self, event): optp.add_option("-j", "--jabberid", dest="jabberid", help="Jabber ID") optp.add_option("-p", "--password", dest="password", - help="password") + help="password (insecure, use env variable GOBOT_PASSWORD instead)") optp.add_option("-n", "--nick", dest="nick", help="Nickname") optp.add_option("-r", "--room", dest="room", @@ -142,7 +143,10 @@ def gocd_listen_stop(self, event): if opts.jabberid is None: opts.jabberid = raw_input("Username: ") if opts.password is None: - opts.password = getpass.getpass("Password: ") + if os.environ.get('GOBOT_PASSWORD'): + opts.password = os.environ.get('GOBOT_PASSWORD') + else: + opts.password = getpass.getpass("Password: ") if opts.nick is None: opts.nick = raw_input("Nickname: ") if opts.room is None: diff --git a/start_gobot.sh b/start_gobot.sh index 2538630..a4b2082 100644 --- a/start_gobot.sh +++ b/start_gobot.sh @@ -1,2 +1,7 @@ #!/bin/sh -exec python /gobot/gobot.py -j $JID -p $JPASSWD -r $JROOM -n $JNICK -g $GODOMAIN -s $GOSTAGES + +if [ -z "${GOBOT_PASSWORD}" ]; then + GOBOT_PASSWORD="${JPASSWD}"; export GOBOT_PASSWORD +fi + +exec python /gobot/gobot.py -j "${JID}" -r "${JROOM}" -n "${JNICK}" -g "${GODOMAIN}" -s "${GOSTAGES}" From 758a8339960eab0ed59e75cd436f26499eca1915 Mon Sep 17 00:00:00 2001 From: Pierre Guinoiseau Date: Tue, 5 Jul 2016 14:56:41 +1200 Subject: [PATCH 3/6] Modify Dockerfile to re-run pip install only when needed and add only the files we need --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index a1890c7..4f140ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,8 +14,9 @@ RUN apt-get update && \ RUN useradd -m -s /bin/bash iamgobot -ADD . /gobot -RUN pip install -r /gobot/requirements.txt +ADD requirements.txt /tmp/ +RUN pip install -r /tmp/requirements.txt && rm -f /tmp/requirements.txt +ADD gobot.py start_gobot.sh taglines.txt /gobot/ USER iamgobot WORKDIR /gobot From 00e6699a76a7f1711127bc40804de5b55bdcd512 Mon Sep 17 00:00:00 2001 From: Pierre Guinoiseau Date: Tue, 5 Jul 2016 14:57:22 +1200 Subject: [PATCH 4/6] Make gobot.py PEP8 compliant --- gobot.py | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/gobot.py b/gobot.py index 51049b0..ba170d8 100644 --- a/gobot.py +++ b/gobot.py @@ -15,7 +15,7 @@ # ensure utf8 encoding if sys.version_info < (3, 0): - reload(sys) + reload(sys) # noqa sys.setdefaultencoding('utf8') else: raw_input = input @@ -32,20 +32,14 @@ def __init__(self, jabberid, password, room, nick, godomain, stages): self.stages = stages self.add_event_handler("session_start", self.start) - self.add_event_handler("groupchat_message", self.bot_message) - self.add_event_handler('gocd_listen', self.gocd_listen, threaded=True) - self.add_event_handler('disconnected', self.gocd_listen_stop) def start(self, event): self.get_roster() self.send_presence() - self.plugin['xep_0045'].joinMUC(self.room, - self.nick, - wait=True) - + self.plugin['xep_0045'].joinMUC(self.room, self.nick, wait=True) self.event('gocd_listen') def bot_message(self, msg): @@ -57,7 +51,8 @@ def bot_message(self, msg): tagfile = open('taglines.txt') tagline = next(tagfile) for num, aline in enumerate(tagfile): - if random.randrange(num + 2): continue + if random.randrange(num + 2): + continue tagline = aline tagfile.close() @@ -67,23 +62,28 @@ def bot_message(self, msg): def gocd_listen(self, event): failedpipes = [] + def gocd_message(ws, message): msg = json.loads(message) pipename = msg['pipeline']['name'] stage = msg['pipeline']['stage'] if stage['name'] in self.stages: - golink = 'https://%s/go/tab/pipeline/history/%s' % (self.godomain, pipename) + golink = 'https://{domain}/go/tab/pipeline/history/{pipe}'.format( + domain=self.godomain, pipe=pipename) if stage['state'] == 'Passed' and pipename in failedpipes: failedpipes.remove(pipename) - self.send_message(mto=self.room, - mbody="%s (%s) fixed :) - %s" % (pipename, stage['name'], golink), - mtype='groupchat') + self.send_message( + mto=self.room, + mbody="{pipe} ({stage}) fixed :) - {link}".format( + pipe=pipename, stage=stage['name'], link=golink), + mtype='groupchat') elif stage['state'] == 'Failed' and pipename not in failedpipes: failedpipes.append(pipename) - self.send_message(mto=self.room, - mbody='%s (%s) broken :( - %s' % (pipename, stage['name'], golink), - mtype='groupchat') - + self.send_message( + mto=self.room, + mbody='{pipe} ({stage}) broken :( - {link}'.format( + pipe=pipename, stage=stage['name'], link=golink), + mtype='groupchat') def gocd_error(ws, error): logging.error("GOCD ERROR!!!") @@ -94,20 +94,20 @@ def gocd_close(ws): websocket.enableTrace(True) - self.ws = websocket.WebSocketApp("ws://%s:8887/" % self.godomain, - on_message = gocd_message, - on_error = gocd_error, - on_close = gocd_close) + self.ws = websocket.WebSocketApp("ws://{domain}:8887/".format(domain=self.godomain), + on_message=gocd_message, + on_error=gocd_error, + on_close=gocd_close) sleepsecs = 60 while (1): try: self.ws.run_forever() - logging.error("Trying websocket reconnect in %s seconds" % sleepsecs) + logging.error("Trying websocket reconnect in {} seconds".format(sleepsecs)) time.sleep(sleepsecs) except: logging.error("Unexpected error:", sys.exc_info()[0]) - logging.error("Trying websocket reconnect in %s seconds" % sleepsecs) + logging.error("Trying websocket reconnect in {} seconds".format(sleepsecs)) time.sleep(sleepsecs) def gocd_listen_stop(self, event): @@ -153,9 +153,9 @@ def gocd_listen_stop(self, event): opts.room = raw_input("Room: ") xmpp = GoBot(opts.jabberid, opts.password, opts.room, opts.nick, opts.godomain, opts.stages.split(',')) - xmpp.register_plugin('xep_0030') # Service Discovery - xmpp.register_plugin('xep_0045') # Multi-User Chat - xmpp.register_plugin('xep_0199') # XMPP Ping + xmpp.register_plugin('xep_0030') # Service Discovery + xmpp.register_plugin('xep_0045') # Multi-User Chat + xmpp.register_plugin('xep_0199') # XMPP Ping if xmpp.connect(): xmpp.process(block=True) From e8736b69f4e05d780756fb1d3535eec1570351d1 Mon Sep 17 00:00:00 2001 From: Pierre Guinoiseau Date: Tue, 5 Jul 2016 15:04:01 +1200 Subject: [PATCH 5/6] Install pyasn1 for SSL certificate verification --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 56ae8a5..870989b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ +pyasn1 +pyasn1-modules sleekxmpp dnspython websocket-client From 8c0381815c39d6b301b6363af54f1b176db18136 Mon Sep 17 00:00:00 2001 From: Pierre Guinoiseau Date: Tue, 5 Jul 2016 15:12:22 +1200 Subject: [PATCH 6/6] Move from optparse to argparse --- gobot.py | 62 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/gobot.py b/gobot.py index ba170d8..164ce45 100644 --- a/gobot.py +++ b/gobot.py @@ -4,7 +4,7 @@ import sys import logging import getpass -from optparse import OptionParser +import argparse import json import random @@ -116,43 +116,43 @@ def gocd_listen_stop(self, event): if __name__ == '__main__': # Setup the command line arguments. - optp = OptionParser() - - optp.add_option('-q', '--quiet', help='set logging to ERROR', - action='store_const', dest='loglevel', - const=logging.ERROR, default=logging.INFO) - optp.add_option("-j", "--jabberid", dest="jabberid", - help="Jabber ID") - optp.add_option("-p", "--password", dest="password", - help="password (insecure, use env variable GOBOT_PASSWORD instead)") - optp.add_option("-n", "--nick", dest="nick", - help="Nickname") - optp.add_option("-r", "--room", dest="room", - help="Room to join") - optp.add_option("-g", "--godomain", dest="godomain", - help="GoCD domain to connect to") - optp.add_option("-s", "--stages", dest="stages", - help="comma-seperated list of stage names to report on") - - opts, args = optp.parse_args() + argp = argparse.ArgumentParser(description="GoCD bot") + + argp.add_argument('-q', '--quiet', help='set logging to ERROR', + action='store_const', dest='loglevel', + const=logging.ERROR, default=logging.INFO) + argp.add_argument("-j", "--jabberid", dest="jabberid", + help="Jabber ID") + argp.add_argument("-p", "--password", dest="password", + help="password (insecure, use env variable GOBOT_PASSWORD instead)") + argp.add_argument("-n", "--nick", dest="nick", + help="Nickname") + argp.add_argument("-r", "--room", dest="room", + help="Room to join") + argp.add_argument("-g", "--godomain", dest="godomain", + help="GoCD domain to connect to") + argp.add_argument("-s", "--stages", dest="stages", + help="comma-seperated list of stage names to report on") + + args = argp.parse_args() # Setup logging. - logging.basicConfig(level=opts.loglevel, + logging.basicConfig(level=args.loglevel, format='%(levelname)-8s %(message)s') - if opts.jabberid is None: - opts.jabberid = raw_input("Username: ") - if opts.password is None: + if args.jabberid is None: + args.jabberid = raw_input("Username: ") + if args.password is None: if os.environ.get('GOBOT_PASSWORD'): - opts.password = os.environ.get('GOBOT_PASSWORD') + args.password = os.environ.get('GOBOT_PASSWORD') else: - opts.password = getpass.getpass("Password: ") - if opts.nick is None: - opts.nick = raw_input("Nickname: ") - if opts.room is None: - opts.room = raw_input("Room: ") + args.password = getpass.getpass("Password: ") + if args.nick is None: + args.nick = raw_input("Nickname: ") + if args.room is None: + args.room = raw_input("Room: ") - xmpp = GoBot(opts.jabberid, opts.password, opts.room, opts.nick, opts.godomain, opts.stages.split(',')) + xmpp = GoBot(args.jabberid, args.password, args.room, args.nick, args.godomain, args.stages.split(',')) xmpp.register_plugin('xep_0030') # Service Discovery xmpp.register_plugin('xep_0045') # Multi-User Chat xmpp.register_plugin('xep_0199') # XMPP Ping