diff --git a/event.py b/event.py new file mode 100644 index 0000000..9a7da33 --- /dev/null +++ b/event.py @@ -0,0 +1,44 @@ + +import yaml +import os +import glob +import re + +class Event( object ): + def __init__( self, path, glob ): + self.path = path + self.glob = glob + self.fields = {} + self.doc = "" + + def path_short( self ): + # XXX needs tidy + return "content/event/" + os.path.basename( self.path ) + + def open( self ): + for path in glob.glob( self.glob ): + if os.path.exists( path ): + self.path = path + self.read() + return False + return True + + def write( self ): + outfile = open( self.path, 'w', encoding = "utf-8" ) + outfile.write( ( '''\ +--- +%(yaml)s +--- +%(md)s +''' % { 'yaml': yaml.dump( self.fields, default_flow_style = False ), + 'md': self.doc, + } ) ) + + def read( self ): + indata = open( self.path, 'r', encoding = "utf-8" ).read() + try: + ( pre, yamldata, docdata ) = re.split( "^---$", indata, flags = re.MULTILINE ) + except ValueError: + return + self.yaml = yaml.load( yamldata ) + self.doc = docdata.strip() diff --git a/fih.py b/fih.py index 301995b..d0b370d 100644 --- a/fih.py +++ b/fih.py @@ -6,6 +6,8 @@ import subprocess import re import random import mattermostdriver +import event +import slugify random.seed( os.urandom( 8 ) ) @@ -47,70 +49,114 @@ def raw_incident_number_to_url( incident_number ): def is_incident_channel_name( channel_name ): return channel_name.startswith( app.config[ "MATTERMOST_INCIDENT_CHANNEL_PREFIX" ] ) +def channel_name_to_raw_incident_number( channel_name ): + return channel_name[ len( app.config[ "MATTERMOST_INCIDENT_CHANNEL_PREFIX" ] ): ] -def mattermost_incident_command( cmd ): - app.mm.posts.create_post( options = { 'channel_id': request.form[ 'channel_id' ], - 'message': "### Executing `" + cmd + "`...", + +def mattermost_incident_command( command, args, channel_id, raw_incident_number ): + app.mm.posts.create_post( options = { 'channel_id': channel_id, + 'message': "### Executing `" + command + "`...", } ) - if cmd == "PUBLISH": + if command == "PUBLISH": cmdline = app.config[ "MERCURIAL_BIN" ] + " update" message = exec_to_message( cmdline ) - app.mm.posts.create_post( options = { 'channel_id': request.form[ 'channel_id' ], + app.mm.posts.create_post( options = { 'channel_id': channel_id, 'message': message, } ) + channel = app.mm.channels.get_channel( channel_id ) + slug = slugify.slugify( channel[ 'purpose' ] ) + ev = event.Event( path = app.config[ "STATUS_EVENT_SCHEME" ] % { "incident_number": raw_incident_number, + "slug": slug, + }, + glob = app.config[ "STATUS_EVENT_GLOB" ] % { "incident_number": raw_incident_number, + }, + ) + new = ev.open() + ev.doc = channel[ 'header' ] + ev.fields[ '$title@' ] = channel[ 'purpose' ] + ev.fields[ '$slug' ] = raw_incident_number + if not ev.fields.get( '$date' ): + ev.fields[ '$date' ] = {} + if not ev.fields[ '$date' ].get( 'published' ): + ev.fields[ '$date' ][ 'published' ] = datetime.datetime.utcnow().strftime( "%Y-%m-%d %H:%M" ) + written = ev.write() + + app.mm.posts.create_post( options = { 'channel_id': channel_id, + 'message': "#### Written `%s`:\n\n```\n%s```" % ( ev.path_short(), written ), + } ) + + if new: + cmdline = app.config[ "MERCURIAL_BIN" ] + " add " + ev.path_short() + message = exec_to_message( cmdline ) + if message: + app.mm.posts.create_post( options = { 'channel_id': channel_id, + 'message': message, + } ) + + cmdline = app.config[ "MERCURIAL_BIN" ] + " commit -m 'add event for incident " + raw_incident_number + " via FIH' " + ev.path_short() + message = exec_to_message( cmdline ) + if message: + app.mm.posts.create_post( options = { 'channel_id': channel_id, + 'message': message, + } ) + for pull_from in app.config[ "MERCURIAL_PUSH_TO" ]: cmdline = app.config[ "MERCURIAL_BIN" ] + " pull " + pull_from message = exec_to_message( cmdline ) - app.mm.posts.create_post( options = { 'channel_id': request.form[ 'channel_id' ], - 'message': message, - } ) + if message: + app.mm.posts.create_post( options = { 'channel_id': channel_id, + 'message': message, + } ) cmdline = app.config[ "MERCURIAL_BIN" ] + " merge" message = exec_to_message( cmdline ) - app.mm.posts.create_post( options = { 'channel_id': request.form[ 'channel_id' ], - 'message': message, - } ) + if message: + app.mm.posts.create_post( options = { 'channel_id': channel_id, + 'message': message, + } ) cmdline = app.config[ "MERCURIAL_BIN" ] + " commit -m 'merge from " + pull_from + "'" message = exec_to_message( cmdline ) - app.mm.posts.create_post( options = { 'channel_id': request.form[ 'channel_id' ], - 'message': message, - } ) + if message: + app.mm.posts.create_post( options = { 'channel_id': channel_id, + 'message': message, + } ) for deploy_to in app.config[ "GROW_DEPLOY_TO" ]: cmdline = app.config[ "GROW_BIN" ] + " deploy -f " + deploy_to message = exec_to_message( cmdline ) - app.mm.posts.create_post( options = { 'channel_id': request.form[ 'channel_id' ], - 'message': message, - } ) + if message: + app.mm.posts.create_post( options = { 'channel_id': channel_id, + 'message': message, + } ) - elif cmd == "START": + elif command == "START": pass - elif cmd == "ETR": + elif command == "ETR": pass - elif cmd == "RESOLVED": + elif command == "RESOLVED": pass - elif cmd == "CLOSED": + elif command == "CLOSED": pass - elif cmd == "TIMELINE": + elif command == "TIMELINE": pass - elif cmd == "INCIDENT": + elif command == "INCIDENT": pass - elif cmd == "DEGRADED": + elif command == "DEGRADED": pass - elif cmd == "MAINTENANCE": + elif command == "MAINTENANCE": pass - elif cmd == "NOTICE": + elif command == "NOTICE": pass - elif cmd == "OK": + elif command == "OK": pass else: return "WTF command?" app.mm.posts.create_post( options = { 'channel_id': request.form[ 'channel_id' ], - 'message': "### Finished `" + cmd + "`!", + 'message': "### Finished `" + command + "`!", } ) return "OK" @@ -196,8 +242,14 @@ def mattermost_incident(): if request.form[ 'token' ] in app.config[ 'MATTERMOST_COMMAND_TOKENS' ]: if is_incident_channel_name( request.form[ 'channel_name' ] ): - cmd = request.form[ 'text' ].strip().split()[ 0 ].upper() - return mattermost_incident_command( cmd ) + text = request.form[ 'text' ].strip().split() + raw_incident_number = channel_name_to_raw_incident_number( request.form[ 'channel_name' ] ) + + return mattermost_incident_command( command = text[ 0 ].upper(), + args = " ".join( text[ 1: ] ), + channel_id = request.form[ 'channel_id' ], + raw_incident_number = raw_incident_number, + ) else: return mattermost_incident_start( description = request.form[ 'text' ], team_id = request.form[ 'team_id' ],