Skip to content

Commit

Permalink
Add Azure voting app
Browse files Browse the repository at this point in the history
  • Loading branch information
Hans Kristian Flaatten committed Apr 30, 2020
1 parent 05af6c8 commit 08b0983
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 0 deletions.
82 changes: 82 additions & 0 deletions .github/workflows/deploy.yaml
@@ -0,0 +1,82 @@
# This workflow will build a docker container, publish it to Azure Container Registry, and deploy it to Azure Kubernetes Service using a helm chart.
#
# To configure this workflow:
#
# 1. Set up the following secrets in your workspace:
# a. REGISTRY_USERNAME with ACR username
# b. REGISTRY_PASSWORD with ACR Password
# c. AZURE_CREDENTIALS with the output of `az ad sp create-for-rbac --sdk-auth`
#
# 2. Change the values for the REGISTRY_NAME, CLUSTER_NAME, CLUSTER_RESOURCE_GROUP and NAMESPACE environment variables (below).

on: [push]

# Environment variables available to all jobs and steps in this workflow
env:
REGISTRY_NAME: evryflaatten
CLUSTER_NAME: aks-demo
CLUSTER_RESOURCE_GROUP: aks-demo
NAMESPACE: default
IMAGE_NAME: myimage

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master

# Connect to Azure Container registry (ACR)
- uses: azure/docker-login@v1
with:
login-server: ${{ env.REGISTRY_NAME }}.azurecr.io
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}

# Container build and push to a Azure Container registry (ACR)
- run: |
docker build . -t ${{ env.REGISTRY_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }}
docker push ${{ env.REGISTRY_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }}
# Set the target Azure Kubernetes Service (AKS) cluster.
- uses: azure/aks-set-context@v1
with:
creds: '${{ secrets.AZURE_CREDENTIALS }}'
cluster-name: ${{ env.CLUSTER_NAME }}
resource-group: ${{ env.CLUSTER_RESOURCE_GROUP }}

# Create namespace if doesn't exist
- run: |
kubectl create namespace ${{ env.NAMESPACE }} --dry-run -o json | kubectl apply -f -
# Create imagepullsecret for Azure Container registry (ACR)
- uses: azure/k8s-create-secret@v1
with:
container-registry-url: ${{ env.REGISTRY_NAME }}.azurecr.io
container-registry-username: ${{ secrets.REGISTRY_USERNAME }}
container-registry-password: ${{ secrets.REGISTRY_PASSWORD }}
secret-name: ${{ env.REGISTRY_NAME }}-registry-connection
namespace: ${{ env.NAMESPACE }}

# Baking the helm chart to generate the manifests to deploy
- uses: azure/k8s-bake@v1
with:
renderEngine: 'helm'
helmChart: './mychart/'
helm-version: 'latest'
releaseName: 'myapp'
overrideFiles: 'values.yaml'
overrides: |
image.repository:${{ env.REGISTRY_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}
image.tag:${{ github.sha }}
imagePullSecrets[0].name:${{ env.REGISTRY_NAME }}-registry-connection
id: bake

# Deploy app to AKS
- uses: azure/k8s-deploy@v1
with:
manifests: ${{ steps.bake.outputs.manifestsBundle }}
#images: |
# ${{ env.REGISTRY_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }}
#imagepullsecrets: |
# ${{ env.REGISTRY_NAME }}-registry-connection
namespace: ${{ env.NAMESPACE }}
3 changes: 3 additions & 0 deletions Dockerfile
@@ -0,0 +1,3 @@
FROM tiangolo/uwsgi-nginx-flask:python3.6
RUN pip install redis
ADD /azure-vote /app
5 changes: 5 additions & 0 deletions azure-vote/config_file.cfg
@@ -0,0 +1,5 @@
# UI Configurations
TITLE = 'Azure Voting App'
VOTE1VALUE = 'Cats'
VOTE2VALUE = 'Dogs'
SHOWHOST = 'false'
88 changes: 88 additions & 0 deletions azure-vote/main.py
@@ -0,0 +1,88 @@
from flask import Flask, request, render_template
import os
import random
import redis
import socket
import sys

app = Flask(__name__)

# Load configurations from environment or config file
app.config.from_pyfile('config_file.cfg')

if ("VOTE1VALUE" in os.environ and os.environ['VOTE1VALUE']):
button1 = os.environ['VOTE1VALUE']
else:
button1 = app.config['VOTE1VALUE']

if ("VOTE2VALUE" in os.environ and os.environ['VOTE2VALUE']):
button2 = os.environ['VOTE2VALUE']
else:
button2 = app.config['VOTE2VALUE']

if ("TITLE" in os.environ and os.environ['TITLE']):
title = os.environ['TITLE']
else:
title = app.config['TITLE']

# Redis configurations
redis_server = os.environ['REDIS']

# Redis Connection
try:
if "REDIS_PWD" in os.environ:
r = redis.StrictRedis(host=redis_server,
port=6379,
password=os.environ['REDIS_PWD'])
else:
r = redis.Redis(redis_server)
r.ping()
except redis.ConnectionError:
exit('Failed to connect to Redis, terminating.')

# Change title to host name to demo NLB
if app.config['SHOWHOST'] == "true":
title = socket.gethostname()

# Init Redis
if not r.get(button1): r.set(button1,0)
if not r.get(button2): r.set(button2,0)

@app.route('/', methods=['GET', 'POST'])
def index():

if request.method == 'GET':

# Get current values
vote1 = r.get(button1).decode('utf-8')
vote2 = r.get(button2).decode('utf-8')

# Return index with values
return render_template("index.html", value1=int(vote1), value2=int(vote2), button1=button1, button2=button2, title=title)

elif request.method == 'POST':

if request.form['vote'] == 'reset':

# Empty table and return results
r.set(button1,0)
r.set(button2,0)
vote1 = r.get(button1).decode('utf-8')
vote2 = r.get(button2).decode('utf-8')
return render_template("index.html", value1=int(vote1), value2=int(vote2), button1=button1, button2=button2, title=title)

else:

# Insert vote result into DB
vote = request.form['vote']
r.incr(vote,1)

# Get current values
vote1 = r.get(button1).decode('utf-8')
vote2 = r.get(button2).decode('utf-8')

# Return results
return render_template("index.html", value1=int(vote1), value2=int(vote2), button1=button1, button2=button2, title=title)

if __name__ == "__main__":
app.run()
96 changes: 96 additions & 0 deletions azure-vote/static/default.css
@@ -0,0 +1,96 @@
body {
background-color:#F8F8F8;
}

div#container {
margin-top:5%;
}

div#space {
display:block;
margin: 0 auto;
width: 500px;
height: 10px;

}

div#logo {
display:block;
margin: 0 auto;
width: 500px;
text-align: center;
font-size:30px;
font-family:Helvetica;
/*border-bottom: 1px solid black;*/
}

div#form {
padding: 20px;
padding-right: 20px;
padding-top: 20px;
display:block;
margin: 0 auto;
width: 500px;
text-align: center;
font-size:30px;
font-family:Helvetica;
border-bottom: 1px solid black;
border-top: 1px solid black;
}

div#results {
display:block;
margin: 0 auto;
width: 500px;
text-align: center;
font-size:30px;
font-family:Helvetica;
}

.button {
background-color: #4CAF50; /* Green */
border: none;
color: white;
padding: 16px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
-webkit-transition-duration: 0.4s; /* Safari */
transition-duration: 0.4s;
cursor: pointer;
width: 250px;
}

.button1 {
background-color: white;
color: black;
border: 2px solid #008CBA;
}

.button1:hover {
background-color: #008CBA;
color: white;
}
.button2 {
background-color: white;
color: black;
border: 2px solid #555555;
}

.button2:hover {
background-color: #555555;
color: white;
}

.button3 {
background-color: white;
color: black;
border: 2px solid #f44336;
}

.button3:hover {
background-color: #f44336;
color: white;
}
29 changes: 29 additions & 0 deletions azure-vote/templates/index.html
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='default.css') }}">
<title>{{title}}</title>

<script language="JavaScript">
function send(form){
}
</script>

</head>
<body>
<div id="container">
<form id="form" name="form" action="/"" method="post"><center>
<div id="logo">{{title}}</div>
<div id="space"></div>
<div id="form">
<button name="vote" value="{{button1}}" onclick="send()" class="button button1">{{button1}}</button>
<button name="vote" value="{{button2}}" onclick="send()" class="button button2">{{button2}}</button>
<button name="vote" value="reset" onclick="send()" class="button button3">Reset</button>
<div id="space"></div>
<div id="space"></div>
<div id="results"> {{button1}} - {{ value1 }} | {{button2}} - {{ value2 }} </div>
</form>
</div>
</div>
</body>
</html>

0 comments on commit 08b0983

Please sign in to comment.