utils.slack

slack

Common code useful for sending slack messages.

Example Usage: from utils import slack from utilss.slack import send

  1#!/usr/bin/env python3
  2"""
  3slack
  4
  5Common code useful for sending slack messages.
  6
  7Example Usage:
  8    from utils import slack
  9    from utilss.slack import send
 10"""
 11
 12import json
 13import logging
 14import os
 15from urllib.request import Request, urlopen
 16from urllib.error import URLError, HTTPError
 17
 18SLACK_WEBHOOK_URL = os.environ.get('SLACK_WEBHOOK_URL', 'None')
 19
 20GO_SERVER_URL = os.environ.get('GO_SERVER_URL', 'None')
 21GO_PIPELINE_NAME = os.environ.get('GO_PIPELINE_NAME', 'None')
 22GO_PIPELINE_GROUP_NAME = os.environ.get('GO_PIPELINE_GROUP_NAME', 'None')
 23GO_PIPELINE_LABEL = os.environ.get('GO_PIPELINE_LABEL', 'None')
 24GO_PIPELINE_COUNTER = os.environ.get('GO_PIPELINE_COUNTER', 'None')
 25GO_TRIGGER_USER = os.environ.get('GO_TRIGGER_USER', 'None')
 26GO_STAGE_NAME = os.environ.get('GO_STAGE_NAME', 'None')
 27GO_STAGE_COUNTER = os.environ.get('GO_STAGE_COUNTER', 'None')
 28GO_JOB_NAME = os.environ.get('GO_JOB_NAME', 'None')
 29GO_ENVIRONMENT_NAME = os.environ.get('GO_ENVIRONMENT_NAME', 'None')
 30
 31#
 32# Need to iterate on this. Name is not always MYGITY
 33#
 34GO_REVISION_MYGITY = os.environ.get('GO_REVISION_MYGITY', 'None')
 35GO_MATERIAL_BRANCH_MYGITY = os.environ.get('GO_MATERIAL_BRANCH_MYGITY', 'None')
 36
 37#
 38# For testing
 39#
 40# export SLACK_WEBHOOK_URL=https://fake123454321.com/
 41# export GO_SERVER_URL=https://gocd.cloudops.rekor.io/go
 42# export GO_ENVIRONMENT_NAME=build-prod
 43# export GO_PIPELINE_GROUP_NAME=build-prod
 44# export GO_TO_REVISION_MYGITY=40c9a6ea1716e1a3f12db4314644f5f1829f995d
 45# export GO_FROM_REVISION_MYGITY=40c9a6ea1716e1a3f12db4314644f5f1829f995d
 46# export GO_TRIGGER_USER=changes
 47# export GO_REVISION_MYGITY=40c9a6ea1716e1a3f12db4314644f5f1829f995d
 48# export GO_PIPELINE_NAME=cdk
 49# export GO_MATERIAL_BRANCH_MYGITY=master
 50
 51# export GO_MATERIAL_URL_MYGITY=git@bitbucket.org:openalpr/rekor-ops-gocd.git
 52# export GO_JAVA_HOME=/gocd-jre
 53# export GO_PIPELINE_LABEL=37
 54# export GO_EA_MODE=prod
 55# export GO_STAGE_NAME=buildStg
 56# export GO_STAGE_COUNTER=1
 57# export GO_PIPELINE_COUNTER=37
 58# export GO_JOB_NAME=buildJob
 59
 60# ${GO_SERVER_URL}/tab/build/detail/${GO_PIPELINE_NAME}/${GO_PIPELINE_LABEL}/${GO_STAGE_NAME}/${GO_STAGE_COUNTER}/${GO_JOB_NAME}#tab-console
 61
 62
 63logger = logging.getLogger()
 64logger.setLevel(logging.INFO)
 65
 66message_parsed = False
 67
 68pretty_alarm_name = ""
 69alarm_name = ""
 70old_state = ""
 71new_state = ""
 72reason = ""
 73alarm_description = ""
 74
 75channel = "gocd"
 76msg = None
 77
 78
 79def parser(msg, basic_msg=None, json_block=None) -> dict:
 80    """
 81    parser takes a message and creates a formatted / prettified slack message
 82
 83    msg: String with message
 84    basic_msg: True/False, if True, will craft a small/basic message
 85    json_block: True/Falswe, if True, will use whatever you have in msg as the block formatting
 86    """
 87
 88    if json_block:
 89        message = json.loads(msg)
 90    else:
 91        if basic_msg:
 92            message = {
 93              "text": msg,
 94              "channel": channel,
 95              "username": "gocd-slack-bot",
 96              "icon_emoji": ":gocd:"
 97            }
 98        else:
 99            message = {
100                "username": "gocd-slack-bot",
101                "icon_emoji": ":gocd:",
102                "channel": channel,
103                "blocks": [
104                    {
105                        "type": "section",
106                        "text": {
107                            "type": "mrkdwn",
108                            "text": "*"+msg+"*"
109                        }
110                    },
111                    {
112                        "type": "section",
113                        "fields": [
114                            {
115                                "type": "mrkdwn",
116                                "text": "*Environment*\n"+GO_ENVIRONMENT_NAME
117                            },
118                            {
119                                "type": "mrkdwn",
120                                "text": "*Pipeline Group*\n"+GO_PIPELINE_GROUP_NAME
121                            },
122                            {
123                                "type": "mrkdwn",
124                                "text": "*Pipeline*\n"+GO_PIPELINE_NAME
125                            },
126                            {
127                                "type": "mrkdwn",
128                                "text": "*Pipeline Build #*\n"+GO_PIPELINE_LABEL
129                            },
130                            {
131                                "type": "mrkdwn",
132                                "text": "*Stage Name*\n"+GO_STAGE_NAME
133                            },
134                            {
135                                "type": "mrkdwn",
136                                "text": "*Stage Counter*\n"+GO_STAGE_COUNTER
137                            },
138                            {
139                                "type": "mrkdwn",
140                                "text": "*Job Name*\n"+GO_JOB_NAME
141                            },
142                            {
143                                "type": "mrkdwn",
144                                "text": "*Trigger User*\n"+GO_TRIGGER_USER
145                            },
146                            {
147                                "type": "mrkdwn",
148                                "text": "*Material Branch*\n"+GO_MATERIAL_BRANCH_MYGITY
149                            },
150                            {
151                                "type": "mrkdwn",
152                                "text": "*Material Revision*\n"+GO_REVISION_MYGITY
153                            }
154                        ]
155                    },
156                    {
157                        "type": "section",
158                        "text": {
159                            "type": "mrkdwn",
160                            "text": "*Console Logs:*\n<"+GO_SERVER_URL+"/pipelines/"+GO_PIPELINE_NAME+"/"+GO_PIPELINE_LABEL+"/"+GO_STAGE_NAME+"/"+GO_STAGE_COUNTER+"|GoCD Logs>"
161                        }
162                    }
163                ]
164            }
165    return message
166
167
168def send(message, basic_msg=None, json_block=None) -> bool:
169    """
170    Slack.send()
171
172    Sends a formatted message. If message is a String, will use Slack.parser() before sending.
173
174    message: String or Dict (assumes it's processed through Slack.parser())
175    basic_msg: True/False, if True, will craft a small/basic message when calling Slack.parser()
176    json_block: True/Falswe, if True, will use whatever you have in msg as the block formatting when calling Slack.parser()
177    """
178    if type(message) == str:
179        message = parser(msg=message, basic_msg=basic_msg, json_block=json_block)
180
181    req = Request(SLACK_WEBHOOK_URL, json.dumps(message).encode('utf-8'))
182    try:
183        response = urlopen(req)
184        body = response.read()
185        print(body)
186        logger.info("Message posted")
187    except HTTPError as e:
188        logger.error("Request failed: %d %s", e.code, e.reason)
189        return False
190    except URLError as e:
191        logger.error("Server connection failed: %s", e.reason)
192        return False
193
194    return True
def parser(msg, basic_msg=None, json_block=None) -> dict:
 80def parser(msg, basic_msg=None, json_block=None) -> dict:
 81    """
 82    parser takes a message and creates a formatted / prettified slack message
 83
 84    msg: String with message
 85    basic_msg: True/False, if True, will craft a small/basic message
 86    json_block: True/Falswe, if True, will use whatever you have in msg as the block formatting
 87    """
 88
 89    if json_block:
 90        message = json.loads(msg)
 91    else:
 92        if basic_msg:
 93            message = {
 94              "text": msg,
 95              "channel": channel,
 96              "username": "gocd-slack-bot",
 97              "icon_emoji": ":gocd:"
 98            }
 99        else:
100            message = {
101                "username": "gocd-slack-bot",
102                "icon_emoji": ":gocd:",
103                "channel": channel,
104                "blocks": [
105                    {
106                        "type": "section",
107                        "text": {
108                            "type": "mrkdwn",
109                            "text": "*"+msg+"*"
110                        }
111                    },
112                    {
113                        "type": "section",
114                        "fields": [
115                            {
116                                "type": "mrkdwn",
117                                "text": "*Environment*\n"+GO_ENVIRONMENT_NAME
118                            },
119                            {
120                                "type": "mrkdwn",
121                                "text": "*Pipeline Group*\n"+GO_PIPELINE_GROUP_NAME
122                            },
123                            {
124                                "type": "mrkdwn",
125                                "text": "*Pipeline*\n"+GO_PIPELINE_NAME
126                            },
127                            {
128                                "type": "mrkdwn",
129                                "text": "*Pipeline Build #*\n"+GO_PIPELINE_LABEL
130                            },
131                            {
132                                "type": "mrkdwn",
133                                "text": "*Stage Name*\n"+GO_STAGE_NAME
134                            },
135                            {
136                                "type": "mrkdwn",
137                                "text": "*Stage Counter*\n"+GO_STAGE_COUNTER
138                            },
139                            {
140                                "type": "mrkdwn",
141                                "text": "*Job Name*\n"+GO_JOB_NAME
142                            },
143                            {
144                                "type": "mrkdwn",
145                                "text": "*Trigger User*\n"+GO_TRIGGER_USER
146                            },
147                            {
148                                "type": "mrkdwn",
149                                "text": "*Material Branch*\n"+GO_MATERIAL_BRANCH_MYGITY
150                            },
151                            {
152                                "type": "mrkdwn",
153                                "text": "*Material Revision*\n"+GO_REVISION_MYGITY
154                            }
155                        ]
156                    },
157                    {
158                        "type": "section",
159                        "text": {
160                            "type": "mrkdwn",
161                            "text": "*Console Logs:*\n<"+GO_SERVER_URL+"/pipelines/"+GO_PIPELINE_NAME+"/"+GO_PIPELINE_LABEL+"/"+GO_STAGE_NAME+"/"+GO_STAGE_COUNTER+"|GoCD Logs>"
162                        }
163                    }
164                ]
165            }
166    return message

parser takes a message and creates a formatted / prettified slack message

msg: String with message basic_msg: True/False, if True, will craft a small/basic message json_block: True/Falswe, if True, will use whatever you have in msg as the block formatting

def send(message, basic_msg=None, json_block=None) -> bool:
169def send(message, basic_msg=None, json_block=None) -> bool:
170    """
171    Slack.send()
172
173    Sends a formatted message. If message is a String, will use Slack.parser() before sending.
174
175    message: String or Dict (assumes it's processed through Slack.parser())
176    basic_msg: True/False, if True, will craft a small/basic message when calling Slack.parser()
177    json_block: True/Falswe, if True, will use whatever you have in msg as the block formatting when calling Slack.parser()
178    """
179    if type(message) == str:
180        message = parser(msg=message, basic_msg=basic_msg, json_block=json_block)
181
182    req = Request(SLACK_WEBHOOK_URL, json.dumps(message).encode('utf-8'))
183    try:
184        response = urlopen(req)
185        body = response.read()
186        print(body)
187        logger.info("Message posted")
188    except HTTPError as e:
189        logger.error("Request failed: %d %s", e.code, e.reason)
190        return False
191    except URLError as e:
192        logger.error("Server connection failed: %s", e.reason)
193        return False
194
195    return True

Slack.send()

Sends a formatted message. If message is a String, will use Slack.parser() before sending.

message: String or Dict (assumes it's processed through Slack.parser()) basic_msg: True/False, if True, will craft a small/basic message when calling Slack.parser() json_block: True/Falswe, if True, will use whatever you have in msg as the block formatting when calling Slack.parser()