Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

email notifier must split list of emails on spaces and build image for arm64 in CI #13

Merged
merged 8 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
target
.travis?
pom.xml
*.md
.gitignore
.idea
code/tests
code/requirements.tests.txt
__pycache__
32 changes: 23 additions & 9 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# This is a basic workflow to help you get started with Actions

name: CI
name: "Test and build notification scripts."

on:
push:
Expand All @@ -13,18 +11,34 @@ on:

jobs:
build:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04

steps:
- uses: actions/checkout@v2

- name: Run a one-line script
run: echo Hello, world!
- uses: actions/setup-python@v2
with:
python-version: '3.8'

- name: Run a multi-line script
- name: Run unit tests
run: |
echo Add other actions to build,
echo test, and deploy your project.
pip install -r requirements.tests.txt
pytest tests/ --junitxml=test-report.xml -v

- name: Multi-arch docker image build prerequired
run: sudo docker run --privileged linuxkit/binfmt:v0.7

- name: Build and deploy on architecture
env:
DOCKER_USERNAME: ${{ secrets.SIXSQ_DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.SIXSQ_DOCKER_PASSWORD }}
run: ./container-release.sh

- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action@v1
if: always()
with:
files: test-report.xml

notify:
if: always()
Expand Down
41 changes: 41 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Automatic release for every new tag
name: "Release"

on:
push:
tags:
- "*.*.*"

jobs:
build:
runs-on: ubuntu-20.04

steps:
- uses: actions/checkout@v2

- name: Multi-arch docker image build prerequired
run: sudo docker run --privileged linuxkit/binfmt:v0.7

- name: Build and deploy on architecture
env:
DOCKER_USERNAME: ${{ secrets.SIXSQ_DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.SIXSQ_DOCKER_PASSWORD }}
DOCKER_ORG: nuvla
run: ./container-release.sh


notify:
if: always()
name: Post Workflow Status To Slack
needs:
- build
runs-on: ubuntu-latest
steps:
- name: Slack Workflow Notification
uses: Gamesight/slack-workflow-status@master
with:
# Required Input
repo_token: ${{secrets.GITHUB_TOKEN}}
slack_webhook_url: ${{secrets.SLACK_WEBHOOK_URL}}
# Optional Input
icon_emoji: ':rocket:'
88 changes: 88 additions & 0 deletions container-release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/bin/bash -xe

###############################
# CHANGE THIS ON EVERY REPO #
DOCKER_IMAGE=$(basename `git rev-parse --show-toplevel`)
###############################

# default env vars in GH actions
GIT_BRANCH=$(echo ${GITHUB_REF} | awk -F'/' '{print $(NF)}' | sed -e 's/[^a-z0-9\._-]/-/g')

# non-tagged builds are not releases, so they always go on nuvladev
DOCKER_ORG=${DOCKER_ORG:-nuvladev}

MANIFEST=${DOCKER_ORG}/${DOCKER_IMAGE}:${GIT_BRANCH}

platforms=(amd64 arm64)


#
# remove any previous builds
#

rm -Rf target/*.tar
mkdir -p target

#
# generate image for each platform
#

for platform in "${platforms[@]}"; do
GIT_BUILD_TIME=$(date --utc +%FT%T.%3NZ)
docker run --rm --privileged -v ${PWD}:/tmp/work --entrypoint buildctl-daemonless.sh moby/buildkit:master \
build \
--frontend dockerfile.v0 \
--opt platform=linux/${platform} \
--opt filename=./Dockerfile \
--opt build-arg:GIT_BRANCH=${GIT_BRANCH} \
--opt build-arg:GIT_BUILD_TIME=${GIT_BUILD_TIME} \
--opt build-arg:GIT_COMMIT_ID=${GITHUB_SHA} \
--opt build-arg:GITHUB_RUN_NUMBER=${GITHUB_RUN_NUMBER} \
--opt build-arg:GITHUB_RUN_ID=${GITHUB_RUN_ID} \
--opt build-arg:PROJECT_URL=${GIHUB_SERVER_URL}/${GITHUB_REPOSITORY} \
--output type=docker,name=${MANIFEST}-${platform},dest=/tmp/work/target/${DOCKER_IMAGE}-${platform}.docker.tar \
--local context=/tmp/work \
--local dockerfile=/tmp/work \
--progress plain

done

#
# load all generated images
#

for platform in "${platforms[@]}"; do
docker load --input ./target/${DOCKER_IMAGE}-${platform}.docker.tar
done


manifest_args=(${MANIFEST})

#
# login to docker hub
#

unset HISTFILE
echo ${DOCKER_PASSWORD} | docker login -u ${DOCKER_USERNAME} --password-stdin

#
# push all generated images
#

for platform in "${platforms[@]}"; do
docker push ${MANIFEST}-${platform}
manifest_args+=("${MANIFEST}-${platform}")
done

#
# create manifest, update, and push
#

export DOCKER_CLI_EXPERIMENTAL=enabled
docker manifest create "${manifest_args[@]}"

for platform in "${platforms[@]}"; do
docker manifest annotate ${MANIFEST} ${MANIFEST}-${platform} --arch ${platform}
done

docker manifest push --purge ${MANIFEST}
2 changes: 2 additions & 0 deletions requirements.tests.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-r requirements.txt
pytest==7.0.1
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ kafka-python==2.0.2
requests==2.25.0
urllib3==1.26.2
Jinja2==2.11.2
# To fix https://github.com/aws/aws-sam-cli/issues/3661
markupsafe==2.0.1
26 changes: 18 additions & 8 deletions src/notify-email.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
#!/usr/bin/env python3

from notify_deps import *

import smtplib
import multiprocessing
import os
import requests
import smtplib
import time
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from jinja2 import Template
from datetime import datetime

from notify_deps import get_logger, timestamp_convert, main
from notify_deps import NUVLA_ENDPOINT


log_local = get_logger('email')

Expand All @@ -33,7 +37,7 @@ def get_nuvla_config():
headers = {'nuvla-authn-info': nuvla_api_authn_header}
resp = requests.get(config_url, headers=headers)
if resp.status_code != 200:
raise Exception(f'Failed to get response from server: status {resp.status_code}')
raise EnvironmentError(f'Failed to get response from server: status {resp.status_code}')
return resp.json()


Expand All @@ -47,7 +51,7 @@ def set_smpt_params():
try:
SMTP_PORT = int(os.environ['SMTP_PORT'])
except ValueError:
raise Exception(f"Incorrect value for SMTP_PORT number: {os.environ['SMTP_PORT']}")
raise ValueError(f"Incorrect value for SMTP_PORT number: {os.environ['SMTP_PORT']}")
SMTP_SSL = os.environ['SMTP_SSL'].lower() in ['true', 'True']
else:
nuvla_config = get_nuvla_config()
Expand All @@ -59,7 +63,7 @@ def set_smpt_params():
except Exception as ex:
msg = f'Provide full SMTP config either via env vars or in configuration/nuvla: {ex}'
log_local.error(msg)
raise Exception(msg)
raise ValueError(msg)


KAFKA_TOPIC = os.environ.get('KAFKA_TOPIC') or 'NOTIFICATIONS_EMAIL_S'
Expand All @@ -81,7 +85,6 @@ def get_smtp_server(debug_level=0) -> smtplib.SMTP:


def html_content(values: dict):
# subs_config_id = values.get('SUBS_ID')
subs_config_link = f'<a href="{NUVLA_ENDPOINT}/ui/notifications">Notification configuration</a>'

r_uri = values.get('RESOURCE_URI')
Expand Down Expand Up @@ -135,12 +138,19 @@ def send(server: smtplib.SMTP, recipients, subject, html, attempts=SEND_EMAIL_AT
raise SendFailedMaxAttempts(f'Failed sending email after {attempts} attempts.')


def get_recipients(v: dict):
return list(filter(lambda x: x != '', v.get('DESTINATION', '').split(' ')))


def worker(workq: multiprocessing.Queue):
smtp_server = get_smtp_server()
while True:
msg = workq.get()
if msg:
recipients = msg.value['DESTINATION'].split(',')
recipients = get_recipients(msg.value)
if len(recipients) == 0:
log_local.warning(f'No recipients provided in: {msg.value}')
continue
r_id = msg.value.get('RESOURCE_ID')
r_name = msg.value.get('NAME')
subject = msg.value.get('SUBS_NAME') or f'{r_name or r_id} alert'
Expand Down
8 changes: 6 additions & 2 deletions src/notify-slack.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
#!/usr/bin/env python3

import json
import datetime
import multiprocessing
import requests
import os
import re

from notify_deps import *
from notify_deps import get_logger, timestamp_convert, main
from notify_deps import NUVLA_ENDPOINT

KAFKA_TOPIC = os.environ.get('KAFKA_TOPIC') or 'NOTIFICATIONS_SLACK_S'
KAFKA_GROUP_ID = 'nuvla-notification-slack'
Expand All @@ -18,7 +23,6 @@


def message_content(values: dict):
# subs_config_id = values.get('SUBS_ID')
subs_name = lt.sub('&lt;', gt.sub('&gt;', values.get('SUBS_NAME', '')))
subs_config_txt = f'<{NUVLA_ENDPOINT}/ui/notifications|{subs_name}>'

Expand Down
1 change: 1 addition & 0 deletions tests/notify_deps.py
14 changes: 14 additions & 0 deletions tests/test_notify_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import unittest

from notify_email import get_recipients


class NotifyEmail(unittest.TestCase):

def test_get_recipients(self):
assert 0 == len(get_recipients({}))
e1 = '[email protected]'
e2 = '[email protected]'
assert [e1] == get_recipients({'DESTINATION': e1})
assert [e1, e2] == get_recipients({'DESTINATION': f'{e1} {e2}'})
assert [e1, e2] == get_recipients({'DESTINATION': f' {e1} {e2} '})